OpenBSD: Local DoS and root exploit
Posted by Team   
OpenBSD On current OpenBSD systems, any local user (being or not in the wheelgroup) can fill the kernel file descriptors table, leading to a denial ofservice.

Date: Thu, 09 May 2002 13:11:31 GMT
Subject: OpenBSD local DoS and root exploit

The following is research material from FozZy from Hackademy and Hackerz
Voice newspaper  (, and can be distributed
modified or not if proper credits are given to them. For educational
purposes only, no warranty of any kind, I may be wrong, this post could
kill you mail reader, etc. 


On current OpenBSD systems, any local user (being or not in the wheel
group) can fill the kernel file descriptors table, leading to a denial of
service. Because of a flaw in the way the kernel checks closed file
descriptors 0-2 when running a setuid program, it is possible to combine
these bugs and earn root access by winning a race condition.


The "root exploit" problem was fixed on the CVS a week ago, a few hours
after I reported this security bug. Patches for OpenBSD 3.1, 3.0 and 2.9
should be available on the OpenBSD website today. Removing the setuid bit
from /usr/bin/skey* is not a good workaround, you must patch your kernel.
Increasing kern.maxfiles and lowering the local users hard limits (both
number of processes and opened files per process) could be a workaround to
the DoS problem.


-=- Local Denial of Service -=-

A local user can exhaust all the file descriptor entries in the kernel
table, since there is nothing like a "per user limit" (unlike what is done
for processes). It is only a "per process limit" which can be reached
easily by a process creating pipes in a loop. One pipe means two unique
file descriptors. Such a process can fork when its limit is reached, and
then go on creating pipes, fork again... and finally reach the system
Then only the cracker can execute commands, by freeing some file
descriptors when he wants to. Even root cannot run commands: typing "ls" in
the console answers "Two many opened files in system" or "No".
Operations of crontabs, logging facilities, daemons and servers, are at
risk too.
Other systems may be vulnerable to this attack. Linux tries to prevent this
with some file descriptors available only to root.
NB: Someone might find a way to exploit this remotly.

-=- Local Root Exploit -=-

Three weeks ago, XXXXXXXX from Pine released an advisory about the
following bug on FreeBSD: closing file descriptors 0, 1 and/or 2 before
exec'ing a setuid program can make this program open files under these fds,
which have special meanings for libc (stdin/out/err). Reading or writing to
root-owned files can be made possible, since stdXX==opened_file. 

Since 1998, there is a check in the OpenBSD kernel, intended to prevent
this: in the execve function, if fd 0, 1 or 2 is closed, then it is opened
as a new file descriptor assigned to /dev/null. Then, the setuid program
can be safely executed.
But, unlike the FreeBSD and NetBSD patch (and unlike what does linux in
glibc), if there is a failure here, we break out of the current loop and
the execve goes on (it should fail: this was pointed out by art in the
comments of the code, but not fixed).

In sys/kern/kern_exec.c, in the loop where the kernel tries to open
/dev/null on closed fd 0->2: 
 if ((error = falloc(p, &fp, &indx)) != 0)

This can be exploited by a local user to gain root ! An attacker can win a
race condition with respect to the system file descriptors table:

1) Fill the kernel file descriptors table (see the "local DoS"

2) Execute a setuid prog with (for instance) fd number 2 closed. In the
execve kernel function, fd number 2 will not be opened to /dev/null because
the falloc will fail. So, the setuid program will be run with fd 2 closed.

3) Quickly close some fd in order to allow the program to run correctly
( needs free file descriptors, and so does the setuid program). 
Step 3 timing is crucial: if too early, /dev/null will be assigned to fd 2.
If too late, the suid prog execution will fail. But I found that, by tuning
a simple "for" loop, the good timing is quite easy to meet...

-=- Exploit -=-

I exploited successfully this vulnerability on OpenBSD 3.0, and became root
from luser using the setuid-root program "/usr/bin/skeyaudit" (keyinit was
the FreeBSD exploit by phased, but the OpenBSD skeyinit is not exploitable
the same way).
The trick is to put the line we want to insert in /etc/skeyskey into
argv[0], with new line tags, when running skeyaudit. Any entry for the
local user must be removed first, so skeyaudit will complain on stderr,
printing its "filename" (argv[0]) and some error text. If /etc/skeyskey is
opened on fd number 2, we won.

Exploit code here:

-= GREETS =-

Uzy,, and Gobbles :)


Hackademy, Paris.
Hackerz Voice Newspaper International Edition :