OpenBSD local DoS and root exploit

From: fozzyat_private
Date: Thu May 09 2002 - 06:11:31 PDT

  • Next message: Dave Ahmad: "Re: OpenBSD local DoS and root exploit"

    The following is research material from FozZy from Hackademy and Hackerz
    Voice newspaper (http://www.hackerzvoice.org), 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. 
    
    
    -= OVERVIEW =-
    
    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.
    
    
    -= SOLUTIONS =-
    
    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.
    
    
    -= TECHNICAL DESCRIPTION =-
    
    -=- 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
    limit.
    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 ld.so".
    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)
         break;
    (...)
    -------------
    
    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"
    explanation).
    
    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
    (ld.so 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:
    http://www.dmpfrance.com/fd_openbsd.c
    
    
    -= GREETS =-
    
    Uzy, millertat_private, and Gobbles :)
    
    
    FozZy
    <<fozzyat_private>>
    
    Hackademy, Paris.
    Hackerz Voice Newspaper International Edition :
    http://www.dmpfrance.com/inted.html
    



    This archive was generated by hypermail 2b30 : Thu May 09 2002 - 10:16:30 PDT