• QEMU漏洞挖掘


    转载:https://www.tuicool.com/articles/MzqYbia

    qemu是一个开源的模拟处理器硬件设备的全虚拟化仿真器和虚拟器.

    KVM(kernel virtual machine)是一个Linux内核模块,为用户层提供硬件虚拟化的特性,QEMU通过kvm模拟一个目标架构的时候,可以实现与主机相同的架构,从而极大提高模拟效率.

    安装配置qemu参见 官方文档

    漏洞挖掘

    要想实现从虚拟机里(以后统称guest主机)影响qemu,继而影响用户的主机(以后统称Host主机),就需要找到Guest主机与qemu通信的方法,再通过分析qemu对虚拟机传递数据的处理流程来发掘可利用点,比如虚拟机内传递一个异常值,导致qemu堆溢出,然后利用虚拟机传递布置的内容构造exploit,就可以实现控制qemu完成任意代码执行了.

    这里,我介绍的是IO通信的挖掘与利用.

    IO通信

    硬件接入系统的时候,系统会为硬件的寄存器分配连续的IO端口或者IO内存.通过写入IO端口或内存,就能将数据传递给硬件.而qemu虚拟了很多硬件设备,当我们操作这些IO端口的时候,就相当于传递了数据进入qemu进程内.

    对于 IO端口 ,我们可以通过下列方式传递数据:

    #include <sys/io.h>
    iopl(3)//赋予当前程序读写IO端口的权限,也可以使用IOperm()来临时启用
    //读取
    inb(port);//byte
    inw(port);//word=2 bytes
    inl(port);//dwords=4 bytes
    //写入
    outb(val,port);
    outw(val,port);
    outl(val,port);

    对于 IO内存 ,可以使用下列方式传递数据:

    #include <asm/io.h>
    #include <linux/ioport.h>

    long addr=ioremap(ioaddr,iomemsize);
    readb(addr);
    readw(addr);
    readl(addr);
    readq(addr);//qwords=8 btyes

    writeb(val,addr);
    writew(val,addr);
    writel(val,addr);
    writeq(val,addr);
    iounmap(addr);

    需要注意的是,IO端口操作可以直接使用gcc编译,再通过root权限执行就可以,而IO内存操作需要编写内核驱动.

    挖掘第一步:确定目标设备

    开始挖掘前,我们需要先定一个目标设备,而设备列表我们可以通过下列命令获得:

    $ qemu-system-x86_64 -device ?

    若想了解设备的使用信息可以这样:

    $ qemu-system-x86_64 -device mptsas1068,help

    例如:如果我们想加载mptsas设备,可以使用如下命令:

    $ qemu-system-x86_64 -m 2048 --enable-kvm -device mptsas1068 -hda /folder/with/img/centos.img

    当然可能还需要其它参数设置,这个就看你个人需求了.

    另外,每个设备其实对应的都是一个或多个c文件,我们也可以在qemu源码的 hw 目录里找,然后根据文件里的关键词,对比前面获取的设备列表,判断是属于哪个设备.

    同时,很多默认设备我们不需要主动加载.对于默认设备,我们只需要找到对应的c文件就可以开始测试了.

    挖掘第二步:确定设备对应的IO端口IO内存

    在guest主机里,我们执行如下命令获取设备信息:

    $ lspci

    如果认不出来,我们可以这样:

    $ lsmod |grep mptsas(假设驱动就叫mptsas) 
    有可能驱动并不是叫mptsas,这个时候你就例举所有的驱动,然后对比不加载设备时结果的区别来判断.

    $ modinfo mptsas

    如果还认不出来,我们就这样:

    $ lspci -nnv

    这下你总知道了吧.而且我们还知道了这个设备对应的IO端口是 0xc000 ,大小为256(意味着最大可以inl(0xc000+255)).IO内存是 0xfebc0000-febc3fff,febb0000-febbffff ,可以看到它有两块IO内存

    针对mptsas设备,从 lspci 命令,我们知道其对应的bus信息是 00:04.0 ,我们也可以通过下列方式获取对应的IO内存和端口的信息.

    $ cat /proc/iomem| grep 00:04.0
    $ cat /proc/ioports|grep 00:04.0

    除此以外,还有一种方法可以快速获取所有信息:

    $ lshw

    有的设备是特殊设备(比如usb设备,virtio设备),你不一定找得到对应名字,就需要你结合对应c文件的各种关键词以及加载时列表的关键词来找.

    如果加载了一个设备,找不到io信息,你谷歌一下.比如之前测试vmware-vga的时候,我是这样搜索的”How can I find what video driver is in use on my system”

    挖掘第三步:找到对应源文件

    如果你是直接通过文件确定的设备可以跳过这一步.

    如果你是通过设备列表选定目标,就需要找寻该设备的c源文件了.不然你都不知道谁在处理你传的数据,不是很尴尬.

    找文件的技巧也就是先去hw目录,然后找到对应设备的子目录,比如我举例的mptsas,我们通过lspci命令知道,其属于scsi设备,因此就在scsi目录查找,轻松找到两个相关文件 mptconfig.c 和 mptsas.c ,至于mptendian.c,看一眼就知道不重要啦.当然了,有时候我们不一定能找到关键词怎么办?? 通过source Insight 的关键词搜索,搜索所有文件来匹配关键词.

    挖掘第四步: 编写交互代码

    终于要开始为所欲为了,先来看看怎么写测试代码:

    #include <sys/io.h>
    void main(){
    iopl(3);
    inb(0xc050);
    }

    //针对IO内存
    #include <asm/io.h>
    #include <linux/module.h>
    #include <linux/ioport.h>
    #include <linux/random.h>

    long pmem;//注意这里不要使用指针类型,不然后面地址加偏移的时候很容易出错
    void m_init(){
    printk("m_init ");
    int i,cmd,cmd_size;
    int va,offset;
    pmem=ioremap(0xfebf0000,0x8000);//映射io内存
    offset=0x10;//根据设备情况而定
    if (pmem){
    writel(value,pmem+offset);//通常情况下都是写4字节,你也可以根据源码的处理方式选择
    }else printk("ioremap fail ");
    iounmap(pmem);
    return;
    }
    void m_exit(){
    printk("m_exit ");
    return;
    }
    module_init(m_init);
    module_exit(m_exit);

    [更多IO操作详细信息] http://www.oschina.net/question/565065_67988 )

    挖掘第五步: 审计源码

    我们已经找到处理输入的文件了,怎么找到哪一个函数是第一个处理我们输入的函数呢??

    通用的方法:找包含 read,write 关键字的函数名.

    针对mptsas,找的结果如下:

    通过不断找函数的caller,我们最终会找到第一个处理的函数,而有的设备有多个映射IO内存和端口,就意味着有多个处理函数分别对应不同的内存和端口.

    自此能说的也不多了,你都已经知道怎么控制数据了,剩下就是去查看qemu怎么处理数据了.

    qemu在获取数据的时候也会通过调用Guest系统的内存来读取数据,处理guest地址转换的函数叫 dma_memory_read,dma_memory_write ,所以记得注意地址不要出错.

    有的模块有一个内存是拿来放数据的,比如之前测试vmware-vga的时候,一段IO内存就是从结构s-fifo[0x1000] 来读取的.而不是使用函数来处理.

    改天再附上测试mptsas的fuzz代码.

  • 相关阅读:
    MapReduce WordCount Combiner程序
    Spring Boot 单元测试
    Spring Boot @SpringApplicationConfiguration 不能导入的问题
    西西弗斯 滚石上山
    《Effective Modern C++》翻译--简单介绍
    算法排序问题
    MySQL Study之--MySQL schema_information数据库
    HDOJ 4251 The Famous ICPC Team Again
    一、OpenStack入门 之 初步认识
    python模块
  • 原文地址:https://www.cnblogs.com/scu-cjx/p/9149291.html
Copyright © 2020-2023  润新知