Intro

Challenges were categorized into common CTF domains—Reverse Engineering, Web Exploitation, Binary Exploits, Cryptography, Digital Forensics, and Networking. One of the hard challenges was,

Binary Challenge

  • We began by loading the binary into Binary Ninja to understand what it did and where it might be vulnerable.
  • We found that the binary was protected with common security measures: non-executable stacks, stack canaries, and Address Space Layout Randomization (ASLR). These would make a simple buffer overflow attack much harder.
  • Then, we noticed a function that handled user input in a suspicious way. It read more data than expected and wrote it into a fixed-size buffer. This hinted that we might be able to overwrite important data next to that buffer, maybe something like a function pointer stored in the Global Offset Table (GOT).
  • We needed a memory address leak to get past ASLR. The binary did print out some debugging info, which included a memory address. With that address, we could figure out where libc was loaded in memory.
  • With NX enabled, we couldn’t just put our shellcode on the stack. Instead, we used a ROP chain to call system("/bin/sh") from libc.
  • Hence using a python script using pwntools,
    • First we leak the memory address of puts and using this we get libc’s base address.
    • Using this, we get system and bin sh address using:
libc_base = leak - libc.symbols['puts'] 
system_addr = libc_base + libc.symbols['system'] 
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00')))
  • Then to craft the ROP payload,
    • First we find a gadget like pop rdi; ret using ROPgadget
    • Then, push the address of /bin/sh onto the stack so that pop rdi; ret sets rdi to /bin/sh
    • Finally, call system() to run the shell.
payload = b'A' * offset
payload += p64(rop.chain())