There’s really not much to this one. It’s pretty much the same as format2 with the only difference being we’ll need to write multiple bytes.
Finding Our String
I started in the same manner we have been for the last several challenges by printing off values from the stack. After printing those values, I sought to align my string of interest as the last byte printed from the stack. Again, you could calculate this intelligently, but I found guess and check works faster.
python -c ‘print “AAAA” + “%x.”*12 | ./format3
I found that this properly aligned our “byte of interest” as the last byte printed from the stack. In the same manner as before, I used the following to find the address of target: objdump -t format3 | grep target which gives 0x080496f4.
Now for the exploitation. To start things out I tried to use the exact same technique from format2 as I figured it would make for a good starting place.
Not surprisingly, it doesn’t work. It places the value of four into our byte of interest because 4 bytes occurred before our %n formater. Now you may consider just placing padding before the %n formater to have it print the value 0x01025544. As you may have guessed, it isn’t that easy as 0x01025544 is far too long. In fact it comes out to 16,930,116. I went ahead and tried it anyway and got the below:
This ominous black screen eventually unfroze and gave me:
Ya. That totally worked. Would not have expected that nonsense. I really thought it would crash or something. That being said, that really wasn’t the point of the exercise. I’m pretty sure they were trying to get me to do a multibyte write.
So back to the multibyte write. I think it’s easiest to just show you the solution and then explain why it works:
So here’s what’s going on. First we need to write to address 0x080496f4. You can see this address comes first in my format string specifier. It matches up with the first format string specifier of %56x%12$n. The reason we used %56 here is that 0x44=68 decimal. Since there are 12 bytes before my first format specifier, I had to pad it with 56 bytes to come up with a total of 68 bytes. This will write the value of 0x44 to location 0x080496f4.
Next we need to write 0x55 or 85 decimal to the next byte, which is at location 0x080496f5. We’ve already had 68 bytes up to this point so we need another 17 bytes to get 85. This is why for the second set of format string specifiers we have %17x%13n. Now here we’re using %13n because we want to write to the second address in our format string (0x080496f5). We now have the first two bytes written.
Now the last address is a bit misleading. Intuitively, you might think that there should be four sets of addresses and format string specifiers. We can actually shortcut this last write. Recall, the last two bytes we have to write are 0x0102. We can actually do this in one go and that’s what you are seeing here. Remember, up to this point we have printed 85 bytes. If we want to print 0x102 = 258 decimal we need to print 173 more bytes and we need to do it at address 0x080496f6. That’s exactly what is happening with the %173×14$n.