Obviously, fmt2 can still contain a format string, yet it is printed anyway with vfprintf. I'm really surprised this type of bug still exists. Doesn't every decent compiler warn the developer about this?
It just goes to show that all project owners should be responsible for turning on maximum compiler warnings which make sense for their project. There are lots of great gcc warnings/errors which are not enabled by default. In particular, this one is reported by -Wformat-nonliteral or -Wformat-security. From the gcc docs:
-Wformat is included in -Wall. For more control over some
aspects of format checking, the options -Wformat-y2k,
-Wno-format-extra-args, -Wno-format-zero-length,
-Wformat-nonliteral, -Wformat-security, and -Wformat=2
are available, but are not included in -Wall.
The real crime is creating a library function like printf without also creating a library function to escape format strings. Leaving safe escaping as an exercise for the application programmer clearly doesn't work.
This is like asking for SQL databases to have a SQL-Injection escaping function. You 'escape' format string attacks by using the C language in a correct fashion.
I'm sure what you meant was a server-side escaping function which is obviously pointless, but I did want to point out that MySQL's client driver does ship with one that you can use so you don't have to write your own.
Actually, isn't the escaping done serversiden when using placeholders?
At least in Perl, there's no need to escape placeholder values explicitly. I believe the prepared statement is stored on the server, and then the values sent later. Of course the escaping could be the work of the driver.. anyone know?
Prepared statements are disabled by default and require MySQL >= 4.1.3. Instead, the driver does the placeholder replacement on the client, and prepare() does nothing clever at all.
Building dynamic SQL strings for comparison can sometimes be handy (e.g. with LIKE), so it's really too bad there's no server-side SQL escape function, at least in the sql dialects I'm familiar with.
Yes, client libraries for SQL databases should absolutely have an escaping function. The fact that some don't is responsible for a significant fraction of all security failures.
If you don't want to use a format string, use a function that takes a regular string, like puts, instead of a vprintf variant. Why would anyone go to the trouble of escaping a format string so they can use it with a function whose sole purpose is to parse format strings? (Which you can already do, by the way, by using vprintf correctly.)
This vulnerability is reassuringly difficult to exploit under normal conditions. On this dreary morning in San Francisco, against my better judgement I've taken a crack at it (On most systems, due to a combination of old compiler AST-optimizing hacks and security methods, using techniques like information leaks through %X%X stack printing and Null pointer dereference bugs through the infamous %n specifier are challenging and virtually unexploitable on modern systems). Luckily (for blackhats and the curious), due to the way memcpy() works, I think, like the famously exploitable 'unexploitable buffer overflow' that existed solely in 32-bit Opera, this vulnerability is easier to exploit than it would be in real-world environments where system administrators don't even know what Data Execution Prevention and write protected memory pages are, much less turn them on.
Here's how it breaks down
For reference, here's the basic idea of Memcpy on x86
So you the general premise of exploiting format string bugs if you've never seen them before (and if you're a young person like myself, It's entirely possible this is the first C format specifier bug you've ever seen in a major piece of software, yet again, Finite Field analysis scores another victory for the Static Analysis Team. Take that fuzzers!) is to either use clever format specifiers (%X, and %N as mentioned above are some old school faves) or to take advantage of lower system calls like brk() that can be indirectly abused through calls that accept format specifiers as an argument, but I digress.
So, the user arguments are stored in the above registers. To exploit this vulnerability, you must have control of the length argument which is stored in ECX general purpose register as you can see from this code snippet.
So, the user arguments are stored in the above registers. Before things like ROP, to exploit these vulnerabilities the attacker must have control of other, more directly meaningful arguments such as EIP (Which if you control EIP, why bother setting up some complex staged format string exploit?) and hoped that an external task would reboot this binary if it crashed, and keep trying until you beat address space layout randomization at the entropy game, again, I digress. Regardless, The format specifier returned from getprogname() allows us to do some funky stuff like use "safe" format string specifiers like %c (Don't you just love that classic Infosec industry model where %x is 'dangerous' but %c is 'safe' and where breaking MD5 is a big deal but nobody checks the integrity of their login scrips?) to pop bytes off the stack, write an address either to a stored instruction pointer that will be invoked later in the runtime of the program (and presumably will repair the stack before anything gets noticed by the OS) or to just get trashy and munge your local stack with a new EIP pointing to your shellcode (You can even have Null bytes in it, We're moving on up!). Of course, you're also going to have to be attacking a system running a filesystem with very, very, very long filenames, but I most modern ones support around 255 byte filenames, which is definitely not enough if you're using %c, but you could definitely exploit this bug with %o with a limit of 255 bytes.
The remaining, perhaps more difficult question still has to be asked -- Why is nobody taking compiler warnings seriously? Do you think compilers are just kidding when they say "Someone will use this to take control of any system that has this software"?
Affected versions are 1.8.0 through 1.8.3p1 inclusive. Ubuntu 11.10 is not affected (it's running 1.7.4). Ubuntu 12.04 (alpha) might be, which appears to be running 1.8.3p1, for a short while anyway.
Debian _un_stable, on the other hand may be (depending on when you last updated). There is a new package available and so an `apt-get install sudo' or `apt-get upgrade' will sort it.
RHEL compiled out the debugging support and is NOT vulnerable.
Fedora compiles everything with -DFORTIFY_SOURCE which means this still crashes, but is not (thought to be) vulnerable. In any case there is an update available for Fedora right now. https://admin.fedoraproject.org/updates/sudo-1.8.3p1-2.fc16