Protostar 0x10 - Format0

Prev: 0x0F - Heap3 pt 2
Next: 0x11 - Format1

The level introduces format string vulnerabilities and, per the instructions, should be done in fewer than 10 bytes of input.

Let's look at the source code:


Argv[1] is passed from "main" into this "vuln" function, which uses "sprintf" to pass it into "buffer." Conveniently, "buffer" is located right after our target on the stack. We'll need to overflow this buffer and replace "target" with "0xdeadbeef."

Can we achieve this with just a standard buffer overflow?


$ /opt/protostar/bin/format0 `python -c 'print "A" * 64 + "\xef\xbe\xad\xde"'`
you have hit the target correctly :)


Yes, we can. But, if we revisit the level's instructions we can see that we should have fewer than 10 bytes of input.

We know that "0xdeadbeef" is 4 bytes of input on its own, so we don't have much else to work with. However, the use of "sprintf" stands out here. Per the "sprintf" man page, this function operates the same as "printf," except it stores the results in a string buffer as opposed to stdout.

So, we want to look for a conversion character that extends or pads our input somehow. There are several that will work for us. For example:

  • %Nd or %Ni, where "N" is a number we provide, will set the precision of a nonexistent integer represented by "d" or "i"
  • %No, %Nu, or %Nx, where "N" is a number we provide, will set the precision of a nonexistent unsigned integer represented by "x"
  • %Ns, where "N" is a number we provide, will limit the length of a nonexistent string "s" to the number of characters provided by "N," otherwise padding it if the string itself is smaller
The key piece to note here is that we are allowed to pass in these conversion characters without providing arguments. In other words, we typically use "printf" like this:

printf("%d", int_variable)

However, we won't actually be passing in any arguments such as "int_variable" above, nor does the program account for this/handle this in any fashion, so therein lies the vulnerability. When "sprintf" encounters a conversion character, it will expect the variable that needs converting passed to it as an argument on the stack, and thus, it will pop off a random stack value. 

Let's enter %64s to pad our input. "sprintf" will take a value off of the stack that it expects to be the argument, and then pad it so that it is 64 bytes long. Then, we can provide our target:


$ /opt/protostar/bin/format0 `python -c 'print "%64s\xef\xbe\xad\xde"'`
you have hit the target correctly :)


Awesome!