We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

ChadF • 11 years ago

The moment you used this code:

char buffer[100];
strncpy(buffer, argv[1], 100);

You already made it vulnerable to memory errors/attacks. If the length of argv[1] is 100 or more, then the value in buffer will _not_ be null terminated (see strncpy() manual page).

Anyone else see the irony of an article that is aimed at avoiding a memory/input-validation exploit, just to introduce another one? =)

Easy Cat • 11 years ago

Why is it an exploit?

Normal, sane people do not write "printf(buffer)" !

Normal people write "printf("%s", buffer)" !!!

Robot • 7 years ago

Good question (this question is 3 years old, but it is still relevant for readers today). The reason that this vulnerability is still present in modern code is because there are functions that indirectly use printf, but where a flaw might not be so obvious. For example the syslog() call can also be exploited in some cases: https://capec.mitre.org/dat.... Some issues can be deeply hidden inside the code.

And in some environments a developer may pass data to an already existing function, without completely understanding how it works.

So why it might seem unlikely that someone would write printf(buffer), there are other more subtle issues that could go unnoticed.

Sayeed Mahmud • 11 years ago

Great post !!! Keep it up.. I haven't really tested it... but as soon as I do will be back with some questions :D

dany • 8 years ago

In replacing strdup with system: "Our goal is to find the correct offsets (instead of 17 and 18) so that the we output sh;#AAAABBBB<garbabe>0x41414141<garbage>0x42424242.
This takes some work, but in our case the correct offsets are 99 and 100" How exactly did you get to 99 and 100 offset?

Maor Izenberg • 6 years ago

As seen in the example at the start of the article (using the number 10) this is the offset to get the first variable on the stack (the 99th parameter). This is changed from one machine to another so you need some guess

Pleasehelp • 10 years ago

This is making perfect sense up to the point where you do this:

$ env -i ./a.out "$(python -c 'import sys; sys.stdout.write("sh;#\x04\xa0\x04\x08\x06\xa0\x04\x08%00000x%99$hp%00000x%100$hp")')"
sh;#00x804a00480484490x804a006

I totally get where the address 0x804a004 comes from but where did you get 0x804a006 from???

awreece • 10 years ago

0x804a004 is the of the strdup GOT entry. To understand where the 0x804a006 comes from, remember that our final payload is going to look like: <address><address+2>%<number>x%<offset>$hn%<other number="">x%<offset+1>$hn. The reason we need <address+2> is because we are using $hn to write data, and $hn writes 2 bytes at a time. Since the GOT entry is a 4 byte (pointer) sized value, we have to perform 2 writes - to the lower 2 bytes (located at 0x804a004) and to the upper 2 bytes (located at 0x804a006).

MrObvious • 11 years ago

Simple solutions: 1) {simplest} Don't use printf to format data into a fixed length buffer. 2) {lazy but effective, as long as you don't mind run-time errors} Enable buffer overrun protection code - if supported by the environment. 3) {common sense} Add the lengths of the elements together + 6 per integer + 15 per float or long + however much padding implied by the format string and use that for the buffer length.

Felix Collins • 11 years ago

Please show me how this exploit would work with c#.

Steffen • 4 years ago

Hi, great article! I still have one question. In your example the upper half of your system address is bigger than the lower half thus you can tell python to 0x<upper> - 0x<lower>. What can do if that is not the case, for example: 0x1fe29c00

peterjson • 6 years ago

https://uploads.disquscdn.c...

Great post bro. It's very helpful for my study. I have facing some problem with this one. I want to change printf(buf) to system(buf) like what you are talking. But unfortunately, the printf addr is 0x0804a000 so when i pass it as arg[1], the snprintf() stop reading when ever it face Null byte. So I can't change printf to system sucessfully. Can you figure out the problem and help me. Thanks for your blog. Keep going bro!

awreece • 6 years ago

When you can't write to a specific address because of null bytes, you typically have to get a tad creative (you'll note I carefully crafted the examples above to avoid this issue to simplify the explanation).

Usually I just try to find a different function to overwrite (e.g. printf("string literal") is typically optimized by compilers to be a puts() call). Otherwise, you need to be more clever to avoid needing to modify the last byte. In my example, system was at 0x555c2250 -- if printf was at an address that ended with 0x50, you wouldn't need to modify the last byte.

That said, I don't know what the goal of your problem is -- the second printf call of the string "\n" isn't as straightforward as my example above for getting a shell.

peterjson • 6 years ago

Finally, I think i should change the way to achieve it. I'm learning and preparing knowledge for such as CTF games. My problem can be solved like what you're talking if there not be a snprintf function. Anyway, thank you so much. Your series about binary exploitation is very helpful for me

Joachim Hyrathon • 8 years ago

Hello dear Alex, I am trying to translate this blogpage into Chinese for personal studying purpose. And if I am lucky to get your permission, I'd like to post it on my own blog:http://hyrathon.github.io/. Of course the origin address will be preserved. Looking for your apply! :-)

awreece • 6 years ago

Sure! Just attribute it back here with a link :)

TG • 10 years ago

Thanks for this! Very clear and helpful walk-through :)

someone • 11 years ago

Hi, i think that there some addresses was changed outside the debugger! why??

awreece • 11 years ago

The short answer is that the debugger added environment variables (which are put on the stack when the program is loaded and change all subsequent addresses). To see this, compare the output of printenv and gdb printenv (see the section "Debugging an Exploit" in the article).

The long answer realizes that one of the first things main will do will be to align the stack (you should see something like and $0xfffffff0,%esp right after the function prologue). This is ensure that all stack variables are sufficiently aligned to be used as any type. The addition of one byte on the stack (from changing the length of your payload) could change the alignment sufficiently that when main later aligns the stack, it changes offsets and addresses.

MrObvious • 11 years ago

A better solution, don't use lower level languages to program a website (as in: c, c++, c#, ...). Instead, use higher level languages with variant data types (as in: php, cfml, ...).