Protostar Format 4 Walkthrough

Let’s tackle the Protostar Format 4 challenge from Exploit Exercises ( This is a detailed step-by-step walkthrough explaining all the tools and techniques needed — we’ll be writing a format string exploit.

Format 4 Challenge

Here’s the source code for the challenge, :

The program reads a string from the standard input and passes it to printf. We need to craft a string that will cause a call to .

Exploring the Stack

First thing we’ll do is try to explore the stack of the program when is called. Let’s open in GDB:

To start with, I configure some creature comforts so that GDB displays registers, current CPU instruction, and contents of the stack each time a breakpoint is reached (as I finished writing I realized these are not really needed, but I left them here anyways). I explain these in a bit more detail in the Stack 7 walkthrough: Now let’s run it and play with the input:

Interesting. If we pass a plain string, we get the same string as output. If we use one of the format specifiers, such as , will interpret it and expect additional parameters. There’s no additional parameters provided, but it will still pick values from the stack and use them. tells to interpret the next parameter as 4 byte (on 32 bit systems) pointer (i.e. memory address) and print it in hex. We add as a divider, and also place a pattern at the beginning of the string that we can easily recognize. It looks like the string we pass to stdin is located on the stack, and so instructing to inspect the stack we found it (highlighted). This makes sense, is a local variable in and so it is located on the stack during execution. See my Stack 7 walkthrough (link above) for more info on stack workings and layout.

Reading Arbitrary Program Memory

OK, let’s start crafting our exploit, and we’ll start with exploring the program memory:

Our starting point is the same string we used before. Run the exploit:

Back in GDB:

We see that the beginning of the string can be found on the stack in the fourth “parameter” to . Let’s find a string in memory we’d like to display:

We see that memory at address contains string “code execution redirected! you win”. Let’s trick the program into displaying it! All we need to do is change to the address of the string and change fourth to — the address we provide will be interpreted as the location of the NULL terminated string, which will be printed. Here’s the modified exploit:

And now run it (run the exploit first and redirect output to ):

It works!

Modifying Memory With

So far so good, but we only learned how to explore the contents of the memory. How is it even possible to hijack execution flow of the program with , doesn’t it just print stuff to the standard output? If we check man page for (the C function, not a command, i.e. ), we find this gem in the BUGS section:

“Write to memory” sounds promising, let’s check what does:

So, will print to the standard output and then will store 4 in variable. We can pass any memory address instead of as we control stack through the standard input. Excellent!

Let’s try to write to the variable. Find its memory address first:

We see that the value of target is 0 and that it’s located at . Let’s use it:

Run it in GDB (remember to run the script first and save it’s output to ):

We set a second breakpoint in after and start the program. At the beginning on main the value of target is 0. After the it is 0x54. The good news is we’ve managed to change it. The bad news is, it’s not the expected 0x41. What happened here is that we used the length of the buffer in our calculations, but the printf would output a hex value (like ) instead of the characters in the string.

This brings us to the first trick we’ll use, which is the parameter field modifier. It allows us to reference subsequent arguments, without using the prior arguments: will print 4. This is just the thing we need to reference the memory address we plant in the stack, without using any of the to iterate through the stack values we don’t need. Here’s our modified exploit to overwrite :

And run it in GDB:

It works perfectly now.

The second trick we’ll need for this exploit is the “length modifier” for the parameters. If we wanted to write, say, to some memory address using , we would need to print 134,523,853 characters (converted form hex). That’s a lot! But if we use use instead, it tells printf to treat the parameter as short int, i.e. 2 bytes. So instead of doing one write of , we can two separate writes of and , for which we would need to output 43,981 characters ( in decimal). Also, we can see that the length of the buffer is 512 bytes, so we cannot just pass a long string to output all of those characters, so we’ll also use field width format string modifier (a number we can put right after ). As an example, will print 499 spaces followed by the number 5 — 500 characters in all.

We also notice that is called right after in , which would make is useless if we overwrite the return address for . So our third trick would be to overwrite the address for in the Global Offset Table (GOT). This will also make the exploit more reliable as we don’t need to guess the correct location of the return address on the stack. See my Heap 3 walkthrough for more info on GOT:

The Exploit

Our plan is clear now, we’ll use the input string to plant the addresses of the higher and lower halfs of the exit pointer in GOT, we’ll print the required number of characters and will use twice to overwrite the address of exit in GOT with the address of .

Let’s find all the needed addresses:

So we need to overwrite the memory at with . Let’s put it all together:

And it works when we run it as:

Where’s My Shellz?

Without much explanation, here’s a modified exploit that executes a shell. is approximately the address of all the NOPs () we add to the buffer and we’re trying to jump to about the middle of the nopsled to get to the shellcode I’ve also added:

This should be executed as:

For more info on nopsled and the trick, see my Stack 7 walkthrough.


LiveOverflow Binary Hacking course —

My Protostar Stack 7 walkthrough:

Random rumblings about #InfoSec. The opinions expressed here are my own and not necessarily those of my employer.