

Format string vulnerability found in 'sudo' - sweis
http://www.sudo.ws/sudo/alerts/sudo_debug.html

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

------
kmm
In the source of sudo-1.8.3p1, the error is in src/sudo.c at line 1219.
Relevant code snippet:

    
    
      easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);
      va_start(ap, fmt);
      vfprintf(stderr, fmt2, ap);
      va_end(ap);
      efree(fmt2);
    

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?

~~~
tlb
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.

~~~
ZephyrP
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.

~~~
spullara
This is provided by MySQL, as an example:

[http://dev.mysql.com/doc/refman/5.0/en/mysql-real-escape-
str...](http://dev.mysql.com/doc/refman/5.0/en/mysql-real-escape-string.html)

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.

~~~
gizzlon
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?

~~~
rjh29
See "Prepared Statement Support" from
<http://search.cpan.org/perldoc?DBD::mysql#Class_Methods>

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.

~~~
gizzlon
hm.. could be useful information.. thanks

------
morsch
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.

~~~
mcclung
Super. My gentoo boxes are 1.8.2, and are broken as expected.

    
    
      $ ln -s /usr/bin/sudo ./%s
      $ ./%s -D9
      [some debug output with garbage]
      Segmentation fault
      $
    

Bug is here:

<https://bugs.gentoo.org/show_bug.cgi?id=401533>

Looks like it's patched on x86/amd64 already.

OpenIndiana looks unaffected. It's using 1.7.4p4.

~~~
vangale
Yep patch is in Gentoo, I just did a sync and 1.8.3_p2 will be built.

------
hobin
ArchLinux, in its current state, is vulnerable. I suspect it will be patched
soon enough.

/me sends a note to the package maintainers anyway.

~~~
klodolph
ArchLinux doesn't have package signing, so patching sudo isn't going to get
you much.

~~~
gcr
Sure it does, as of earlier this year.
<http://www.archlinux.org/news/pacman-4-moves-to-core/>

Still in beta though. Not very stable.

------
gte910h
Lion runs 1.7.4p6

------
aninteger
OpenBSD 4.9 and 5.0 are ok (both on 1.7.2p8)

------
dodger
c is terrifying.^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^HComputers are terrifying.

