PicoCTF 2022

Category: Binary Exploitation

Stack Cache (400 points)

Undefined behaviours are fun.

This was…a very interesting challenge. But once you understood (vaguely) what was going on, it was actually rather simple.

The code we are given shows us that this program is vulnerable to a buffer overflow (obviously), but the only functions we can jump to are win() and UnderConstruction(). The win() function loads the flag and dumps it on the stack, but does not print it out or notify it to us. The UnderConstruction() function essentially creates uninitialized pointers and prints them out using the %p printf modifier (which means to print out the memory address that a pointer is pointing to).

Digging around the interwebz with questions like “What is so bad about an uninitialized pointer?”, “Why are uninitialized pointers bad?” and “How do I stop my cat from meowing at 5 o’clock in the f%#%ing morning”, I eventually discovered some key information via StackOverflow (a.k.a the monopoly single-handedly carrying the entire IT industry).

Basically, when you create an uninitialized pointer, it’s values will be undefined. What does that mean? Well, it means exactly what it says. We don’t actually know what the values will be. It’s undefined. More than likely, the pointers will just point to random values that just so happen to get loaded into them.

However, given that knowledge, an idea came into my head.

What if I, using the buffer overflow vulnerability, loaded the flag into memory first, then called the UnderConstruction function? Will the flag be present in the printf statement called by UnderConstruction?

So, I tried it and…it…worked?? I managed to successfully read the flag off the stack like some standard printf vulnerability. I remember spending hours in GDB (or, pwndbg, as I am very quirky and not-like-the-other-kids), messing with the binary, maybe performing a bit of ROP, but that was honestly all I really needed to do.

So, I copied my same code and executed it on the server binary, and..yep. Same thing. That’s how I got the flag.

It’s worth mentioning that the %p modifier wasn’t actually much of a concern, since really all it does is just print the value the pointers were pointing to. Since the flag values got loaded into the pointers (not their memory addresses), the flag itself got printed out (albeit, in hexadecimal form).

For instance, if part of the flag was “AAAA”, then the pointer that had that value loaded into it would point to 0x41414141.


from pwn import *

#first, define the memory addresses
address = lambda addr: pack(addr, endianness="little")
win_addr = address(0x8049da0)
under_construction = address(0x08049e20)
printf_mem_location = 0x80b40a0

#generate the filler (10 junk bytes+temporary value for EBP)
#then, get the flag and read it to memory
payload = b"a"*10+b"garb"
payload += win_addr + under_construction

import sys

Leave a Reply