作者:腾讯科恩实验室
公众号:https://mp.weixin.qq.com/s/SgY1QsPmgU8iI4EUJfhznQ

6月12日,由腾讯安全发起,腾讯安全科恩实验室与腾讯安全平台部联合主办,腾讯安全学院协办的2019腾讯安全国际技术峰会(TenSec 2019)在上海西岸艺术中心召开。

腾讯安全科恩实验室两位安全研究员Marco Grassi和陈星宇透过对VirtualBox的架构设计及攻击面和虚拟机逃逸漏洞利用过程的分析,总结并首度发布了云计算和桌面虚拟化技术的最新漏洞发现,以下是漏洞分析详情。

01 背景介绍

QEMU(Quick Emulator)是一款免费的开源模拟器,可以用来执行硬件虚拟化。

它通过动态二进制转换模拟机器的处理器,并为机器提供一组不同的硬件和设备模型, 使其能够运行于各种客户操作系统。 它还可以与KVM一起使用,以接近本机的速度运行虚拟机(通过利用Intel VT-x 等硬件扩展)。 QEMU还可以对用户级进程进行仿真,允许某个架构编译的应用程序在另一个架构上运行。

SLiRP模块主要模拟了网络应用层协议,其中包括IP协议(v4和v6)、DHCP协议、ARP协议等,在sourceforge上有 一个很古老的版本源码,QEMU源码中的slirp代码和这里的十分相似。引人注意的是,slirp模块很久未做修改,但是他是QEMU中默认的网络模块,所以其安全性很值得研究。

02 漏洞成因与细节

在模拟tcp协议时,slirp中对几个特别的端口进行了特殊处理,其中包括端口113(Identification protocol),21(ftp), 544(kshell),6667 6668(IRC)……在处理这些特殊的端口时,需要对用户数据进行操作,一不小心就会出现问题。 CVE-2019-6778就是slirp处理113端口的tcp请求时,未验证buffer剩余空间是否足够,直接拷贝用户数据导致的堆溢出。

slirp模块中有两个重要的数据结构,一个是mbuf,一个是sbuf,mbuf是存储用户从ip层传入的数据的结构,而sbuf是存储tcp层中数据的结构体。他们的定义分别如下:

可以看到在模拟ident协议时,程序拷贝了mbuf中的用户data至sbuf中,同时将sb_wptr和sb_rptr向后加上拷贝的字节数,但是这里程序并未对sb_cc进行任何的操作,在上一层的函数的验证,

在调用tcp_emu之前,会验证sbuf中的剩余空间是否足够,但是由于在模拟ident协议时拷贝了数据却并未加上相应的长度进sb_cc,这样使得sbspace计算出来的空间并不是sbuf实际的剩余空间。

所以如果用户一直向113端口发送数据的话,那就会造成在sbuf中的溢出。

poc如下:

在host中运行 sudo nc -lvv 113 ,再在guest中运行poc中即可。注意这里不一定要连接host,只要任何guest可以连接的IP都可以。

03 漏洞利用

由于溢出发生处是在一块纯buffer,前后的数据在实际运行中都是不稳定的,所以需要一个适当的手段来控制堆。

Malloc Primitive

IP分片(IP fragmentation)

IP fragmentation is an Internet Protocol (IP) process that breaks packets into smaller pieces (fragments), so that the resulting pieces can pass through a link with a smaller maximum transmission unit(MTU) than the original packet size. The fragments are reassembled by the receiving host.

在IPv4中,IP分片存在于两个mtu不一样的网络之间传输数据,如果一个较大的packet想传输到一个mtu较小的网络中,那么就需要将这个packet分片后再发送,在IP头中就有专门的字段来满足这一需求。

  • Zero (1 bit),为0,不使用。

  • Do not fragment flag (1 bit),表示这个packet是否为分片的。

  • More fragments following flag (1 bit),表示这是后续还有没有包,即此包是否为分片序列中的最后一个。

  • Fragmentation offset (13 bits),表示此包数据在重组时的偏移。

在试图重组ip包时,如果重组函数返回NULL,这表示当前的分片序列并没有结束,这样这个包就不会被接下来的流程处理,而会直接return!

这意味着我们可以在内存中任意分配IP包(也就是mbuf),这将是一个非常好的malloc原语(primitive)。

Infoleak

想要任意地址写的前提是我们需要一个leak。好消息是由于溢出的字节数是我们可以控制,因此我们可以修改地址的低位。leak的计划就将是:

  1. 溢出修改m_data的低位,在堆的前面写入一个伪造的ICMP包头;

  2. 发送一个ICMP请求,将MF bit置位(1);

  3. 第二次溢出修改第二步的m_data的低位至伪造的包头地址;

  4. 发送MF bit为0的包结束ICMP请求;

  5. 接收来自host的ICMP返回包。

这样完成了infoleak,我们可以得到qemu-system的基址以及slirp所使用的堆基址。

Control PC

现在的问题转化为,在已知基址的情况下,如何利用任意地址写对程序执行流的控制?

最终,在全局段上找到了我们的目标对象:QEMUTime。

在QEMUTimer中,expire_time时间到了以后,将会执行cb(opaque)。

04 漏洞危害

该模块是QEMU中的默认网络后端(Backend),攻击者利用该漏洞可以导致虚拟机拒绝服务,宿主机crash,严重者可造成在宿主机上的任意命令执行。

普通用户可能会受此漏洞影响,而云服务商大多使用Virt I/O,故不受此漏洞影响。

05 漏洞修复

漏洞详情可见Redhat安全社区:

https://bugzilla.redhat.com/show_bug.cgi?id=1664205

漏洞修复如图所示,在拷贝数据前验证sbuf中剩余空间是否足够,目前QEMU最新版已修复该漏洞。


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/955/