Protostar Format 4 Walkthrough

Let’s tackle the Protostar Format 4 challenge from Exploit Exercises (https://exploit-exercises.com/protostar/format4/). 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, format4.c:

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 hello().

Exploring the Stack

First thing we’ll do is try to explore the stack of the program when printf is called. Let’s open format4 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: https://medium.com/@airman604/protostar-stack7-walkthrough-2aa2428be3e0. 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 printf format specifiers, such as %p, printf 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. %p tells printf 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 AAAA 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 printf to inspect the stack we found it (highlighted). This makes sense, buffer is a local variable in vuln() 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 printf. Let’s find a string in memory we’d like to display:

We see that memory at address 0x80485f0 contains string “code execution redirected! you win”. Let’s trick the program into displaying it! All we need to do is change AAAA to the address of the string and change fourth %p to %s — 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 /tmp/f4):

It works!

Modifying Memory With printf

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 printf, doesn’t it just print stuff to the standard output? If we check man page for printf (the C function, not a command, i.e. man 3 printf), we find this gem in the BUGS section:

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

So, printf(“AAAA%n”, &n_char) will print AAAA to the standard output and then will store 4 in n_char variable. We can pass any memory address instead of &n_char as we control stack through the standard input. Excellent!

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

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

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

We set a second breakpoint in vuln after printf and start the program. At the beginning on main the value of target is 0. After the printf 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 0xb7fd8420) instead of the %p 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 printf arguments, without using the prior arguments: printf(“%4$d”, 1, 2, 3, 4, 5) 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 %p to iterate through the stack values we don’t need. Here’s our modified exploit to overwrite target:

And run it in GDB:

It works perfectly now.

The second trick we’ll need for this exploit is the “length modifier” for the printf parameters. If we wanted to write, say, 0x0804abcd to some memory address using %n, we would need to print 134,523,853 characters (converted form hex). That’s a lot! But if we use %hn use instead, it tells printf to treat the parameter as short int, i.e. 2 bytes. So instead of doing one write of 0x0804abcd, we can two separate writes of 0x0804 and 0xabcd, for which we would need printf to output 43,981 characters (0xabcd 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, printf(“%500d”, 5) will print 499 spaces followed by the number 5 — 500 characters in all.

We also notice that exit() is called right after printf() in vuln(), which would make is useless if we overwrite the return address for vuln. So our third trick would be to overwrite the address for exit() 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: https://medium.com/@airman604/protostar-heap-3-walkthrough-56d9334bcd13

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 %hn twice to overwrite the address of exit in GOT with the address of hello().

Let’s find all the needed addresses:

So we need to overwrite the memory at 0x08049724 with 0x080484b4. 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. 0xbffff5d0 is approximately the address of all the NOPs (\x90) 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 (…; cat) | … trick, see my Stack 7 walkthrough.

References

LiveOverflow Binary Hacking course — https://www.youtube.com/watch?v=iyAyN3GFM7A&list=PLhixgUqwRTjxglIswKp9mpkfPNfHkzyeN

My Protostar Stack 7 walkthrough: https://medium.com/@airman604/protostar-stack7-walkthrough-2aa2428be3e0

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