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

movl LEN(%esp), %ecx
movl SRC(%esp), %eax
movl DEST(%esp), %edx

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.

cmp %eax, %edx
jx link(copy_forward)
je L(fwd_write)
cmp $32, %ecx
jge L(fmt)
jmp L(get_prog_name_offset)

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"?