5. Cve-2016-0088的分析,触发,调试
本节介绍的是由Google project zero发现的Hyper-V漏洞,这枚漏洞于2016年被发现,是vmswitch.sys组件产生的问题,可以导致宿主机内核崩溃,造成宿主机DOS。这个漏洞是在Windows Server2012 R2版本的操作系统版本上触发的,所以下面的介绍使用的Windows版本为:Microsoft Windows Server 2012 R2 Standard x64且未安装任何补丁。
5.1. 漏洞分析
这个漏洞发生在vmswitch.sys,用于Hyper-V的虚拟网络设备服务。在vmswitch! VmsMpCommonPvtHandleMulticastOids函数中,有一处越界写内存的问题,可以造成相邻堆块的5字节数据的写入,破坏了下个堆块的POOL_HEADER,在free下个堆块时内核便会抛出异常,导致宿主机蓝屏。
下面我们通过IDA逆向分析vmswitch! VmsMpCommonPvtHandleMulticastOids函数,代码如下。
该漏洞需要连续运行两次vmswitch! VmsMpCommonPvtHandleMulticastOids函数才能触发。
第一次执行vmswitch! VmsMpCommonPvtHandleMulticastOids函数时,会先分配一个大小为set->info_buflen的内存,然后在offset+0x143,offset+0x14A处分别保存分配的内存的地址以及set->info_buflen/6的值。
第二次执行vmswitch! VmsMpCommonPvtHandleMulticastOids函数时, 会先检查set->info_buflen/6的值是否和第一次执行时在offset+0x14A的值相等。简单来说,就是检查第二次调用vmswitch! VmsMpCommonPvtHandleMulticastOid函数时set->info_buflen整除6的值必须要相等,比如第一次调用时set->info_buflen = 60,第二次调用时候set->info_buflen可以为65,他们整除结果是一样的,所以第二次调用函数时相对于上次set->info_buflen最大偏移为5字节。随后代码运行到offset+144EB,由于第一次调用时分配的buffer大小只有set->info_buflen = extlen,但是现在需要向这个内存中拷贝extlen+5字节的数据,直接导致覆盖了下个堆块的前5字节,破坏了POOL_HEADER,在系统free后面这块内存时抛出异常,导致蓝屏。
5.2. PoC编写与漏洞触发
这里,我们使用Linux作为虚拟机系统,由于Linux内核可以随意修改,所以减少了编写PoC的难度,笔者的Linux内核版本为4.7.2。
这里我们的PoC可以直接通过修改Hyper-V在Linux内核驱动代码实现,故我们在./linux-4.7.2/drivers/net/hyperv/rndis_filter.c文件中添加如下代码。
从PoC中的代码可以看出,新增的函数rndis_pool_overflow连续发送了两次数据,上面代码中设置set->oid = 0x01010209; // OID_802_3_MULTICAST_LIST是为了保证虚拟机传来的数据能走到vmswitch! VmsMpCommonPvtHandleMulticastOids函数。两次发送的数据中,set->info_buflen字段的值分别为extlen,和extlen+5,印证了上面分析过程中的5字节溢出。
保存文件,并且重新编译内核。重启Linux宿主机后,Linux系统正常启动,并没有什么异常,但是此时已经发生了溢出,现在只需要关掉虚拟机,让Windows内核回收被溢出的那块内存,便会发生蓝屏,如图1-35。
图1-35
5.3. 调试
在WinDbg中设置VmsMpCommonPvtHandleMulticastOids+144f8处断点,分别观察两次调用VmsMpCommonPvtHandleMulticastOids函数后调用memmove前后的内存对比。
通过上面,可以发现下一个堆块的POOL_HEADER已经被垃圾数据破坏了5字节,如果内核释放这部分内存,则会触发BugCheck。
POOL_HEADER的结构如下。
可以看到,这个漏洞将POOL_HEADER结构的前五个字节,即PreviousSize, PoolIndex, BlockSize, PoolType和部分PoolTag覆盖掉,导致宿主机系统崩溃。
5.4. 总结
可以看到,因为Hyper-V的特殊的宿主机和虚拟机之间的关系,一旦Hyper-V宿主机中的驱动出现问题,那么对整个云系统的打击可以说是非常大的,哪怕不能造成代码执行,也可以造成大面积云上业务的下线。这个漏洞较为简单,可以作为Hyper-V安全研究的范例。
6. Cve-2016-0089的分析,触发,调试
本节漏洞同样是由Google project zero团队发现的,问题出在vmswitch.sys组件上,会导致Windows宿主机的崩溃,造成DOS。这个漏洞是在Microsoft Windows Server 2012 R2 Standard x64且未安装任何补丁的操作系统版本上触发。
6.1. 漏洞分析
该漏洞问题处在vmswitch! VmsVmNicHandleRssParametersChange函数中,是越界读到非法的内存区域导致宿主机内核崩溃。下面我们通过部分IDA中代码来探究问题所在。
通过上面的代码可知,两处代码在调用memmove函数时,没有检查Src参数指向的内存是否越界。参数Src的值是由一个地址加上偏移而得来的,但是这个偏移我们是能通过虚拟机发送的数据控制的,所以造成了宿主机驱动中的越界读。一旦偏移足够大,读到非法的内存位置便可以造成BugCheck,导致宿主机蓝屏。
在上面的汇编代码中,VmsVmNicHandleRssParametersChange+0x11C语句是将虚拟机传来的数据rssp->indirect_taboffset加上一个地址便是memmove函数的Src参数,由于rssp->indirect_taboffset可以控制,所以Src参数便可以从虚拟机中控制。上文中另外一处代码VmsVmNicHandleRssParametersChange+0x215也是如此。
6.2. PoC编写与漏洞触发
和上面一样,这里我们的PoC可以直接通过修改Hyper-V在Linux内核驱动代码实现,故我们在./linux-4.7.2/drivers/net/hyperv/rndis_filter.c文件中添加如下代码。
PoC代码非常简单,只需修改rssp->indirect_taboffset或者rssp->kashkey_offset的值即可,然后重新编译内核,重启虚拟机,便可复现漏洞。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: