llsoftsecbook
llsoftsecbook copied to clipboard
Add section about printf exploits
printf
can be used for exploits if an attacker controls the format string:
char *input = ; // attacker controlled
print(input);
There are three main format options that can be used for exploitation, the first two are well-known, the third one is rather esoteric, but essential for exploiting:
-
"%p"
leaks argument registers and stack memory. -
"%s"
dereferences a pointer (in argument registers or on the stack) and leaks the memory until the first zero-byte in memory. -
"%n"
writes to a pointer (from argument registers or on the stack).
Different registers or memory can be leaked by repeating format options, e.g. "%p %p %p %p %p %p %s"
.
POSIX (and therefore glibc) supports argument reordering, allowing to replace the repetition by "%5$p"
to print the 5th argument and jumping back and forth between arguments.
Now to the most important format option, "%n"
. When %n
is found in a format string, printf
interprets the argument as a pointer and writes the number of printed characters so far to this pointer.
This makes a nice write gadget, as the written number can be controlled by prepending garbage output of the needed length, e.g. with "%100p%n"
to write a 100
. The size of the written value can be controlled by specifying a precision for "%n"
.
With this much, we still need a pointer on the stack that points to something useful which we want to overwrite. Luckily, one possibility that is always there are frame pointers, which conveniently point directly to another address that is also located on the stack.
A possible pattern is, use a frame pointer to overwrite the few least-significant bytes of the next frame pointer with a controlled value, making this second frame pointer point to a controlled location. A second "%n"
in the string makes use of the second frame pointer to overwrite a more interesting memory location.
If there are two or more attacker controlled printf
s in a row (or a loop of them), the first one can be used to leak information about stack layout, existing pointers and so on (leaking a return address breaks ASLR). The second printf
can then be used to change the memory content based on the leaked information.