Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Hacking TMNF: Part 2 - Exploiting a blind format string bug- 967

bricked.techPosted 3 Years Ago
  • In the previous post, a format string vulnerability was found that led to a crash. This post is all about exploiting the vulnerability to get code execution. The vulnerability occurs in the stdout logging because of a call to fprintf taking in a user controlled string with no other parameters.
  • Simply sending a %99999s will crash the program. What else can we do besides crash? With format string bugs, the identifier %n can be used to perform writes. However, the format string is stored on the heap. This means that the simple <target addr>%x$n doesn't work. This is because the format string parser will attempt to find data on the stack for pointers and it will not be our controlled data.
  • Although we cannot control the location being written to via %n, we can still write to ANY pointer on the stack with a user controlled value. What if there are user controlled pointers on the stack though? By design, the Base Pointer (BP) is exactly this.
  • So, here's the trick. Since we can perform this format string vulnerability multiple times, we can abuse that. On the first write, we'll use a pointer on the stack to write a user controlled value on the stack. This will be the address we want to write in the future. On the second write, we will use the <target addr>%x$n trick with this address and other user controlled value by incrementing the amount of spaces in use. With this technique, we have an arbitrary write primitive!
  • Let's make this primitive better! Currently, it is writing 134.5 MB of padding to stdout because of the amount of filler bytes required for %n to write the address. To get around this, the %hhn specifier can be used to write a single byte at a time. This led to a 1/16 chance that the attack would work because of base pointer alignment.
  • The author decided that the speed gain was worth it but wanted to figure out the 1/16 problem beforehand. They noticed that the RPC GetVersion returned a global variable. By performing a write to corrupt the string in the version with the format string bug, we can leak a stack address. In particular, using a relative write on the global address to the name to point to the .bss section argv pointer, we can leak a stack address. This requires a slow 2 byte write but makes this much faster later on.
  • Once we have the arbitrary write primitive, we need something to write! The binary is compiled without PIE, meaning that we can corrupt the global variables for the binary without needing a memory leak. From the arbitrary write and the stack leak, we can trivially ROP the binary. The chain, which is made easier by the binary being statically compiled, calls mprotect to make the stack executable then jumping to shellcode written beforehand. They created a reverse shell with this.
  • The code for the ROP is interesting since it makes heavy use of the pwntools functionality instead of hardcoding addresses and sycalls. Pretty neat to see and something I'd use in the future. Overall, great post on format string exploitation.