Yes, quite a few similar questions exist already (5037601, 19166698, 4855162, 14505995, 5052648, 13409508, 7745146, 7459630; sorry, not enough rep for more than 2 links), and yes, there are some nice articles explaining this kind of thing (click, click, http ://codearcana.com/posts/2013/05/02/introduction-to-format-string-exploits.html). I've read them and I think I get the general idea, but I still fail at succesfully exploiting the easiest training toy example that I could think of.
#include <stdio.h>
void f(char* a)
{
printf("a: %p\n", &a);
printf(a);
return;
}
void main(int argc, char** argv)
{
f(argv[1]); //please ignore the lack of any check
return;
}
Yes, the stack is executable and yes, memory layout randomisation is disabled. Each execution gives me the same address of a
. I can feed it for instance $ ruby -e 'print "AAAA"+("%08x."*16)'
, and that results in:
a: 0xbfffece0
AAAAbfffece0.bfffecf0.b7fd7ff4.00000000.00000000.bffffcf8.080484b0.bfffecf0.00000fff.b7fd8420.00000000.41414141.78383025.3830252e.30252e78.252e7838.
So now I can see where my input ends up in memory. I can write a value to the stack with $ ruby -e 'print "12345%n"+("%08x."*16)'
, which results in this:
a: 0xbfffece0
12345bfffecf0.b7fd7ff4.00000000.00000000.bffffcf8.080484b0.00000005.00000fff.b7fd8420.00000000.34333231.256e2535.2e783830.78383025.3830252e.30252e78.
Obviously, my ultimate goal would presumably be something like <something><NOPs><shellcode>
, where <something>
overwrites the return address of f
so that the program will jump into the NOP sled and execute the shellcode. But the address of the saved return address seems to depend on my input now, right? Something similar to 0xbfffece0 - len(input) - 12
, assuming a 12-byte prologue? Perhaps this example is not the easiest after all...
I'm getting confused. Any ideas?
Another idea is to use the dollar sign: %<distance>$n
.
Quoting from Linux's printf manpage:
One can also specify explicitly which argument is taken, at each place where an argument is required, by writing "%m$". Where the decimal integer m denotes the position in the argument list of the desired argument, indexed starting from 1. Source
Example: %5$n
would write to the 5th address from the top of the stack.