前言:
这个项目是我在2017年和黎镓辉同学申请的南京邮电大学STITP(大学生创新训练计划)项目,指导老师是沙乐天老师。
在将近一年的紧凑时间内,我和黎镓辉同学在老师以及学长的帮助下,从立项开始一点点地开始学习如何复现这个当时还十分火热的CVE。
由于当时还没有系统学习网安专业知识,研究时间也是在课余时间里挤出来的,因此会有一些仓促,但好在有了老师的指导,我们最终成功进行了复现并提出了一些改进方法。
由于大多数资料以及报告都保存在另一位同学那边,由于特殊原因已经难以找到当时的报告以及部分研究调试数据,为此我根据最终答辩时的PPT制作了这个核心思路总结概述。
总结的过程有一些简陋,如果有所缺漏请指出,谢谢。
正文:
1、 后门(BACKDOOR)接口
使得在用户态就可以通过这个接口发送命令和host通信
函数中含有一个”inl”指令会导致用户态程序产生权限错误
该错误会被host的hypervisor捕捉从而实现通信,类似于一个错误中断
2、 RPCI(Remote Procedure Call Interface)
基于Backdoor机制实现,通过这个机制,guest可以向host发送请求完成某些操作
例如拖放(Drag n Drop)和复制黏贴(Copy Paste)
RPCI依据info-get guestinfo.ip获取guest的ip地址,这是通过套接字实现的
3、 漏洞
类似于过去在Version4中所出现的漏洞,在Version3中也同样存在
当guest发送DnD/CP数据包时,host会重组guest发送的DnD/CP消息
关键问题在于,函数只检查了包头的buffer长度,对后续的数据包检查无效,
因此可以在后续的包中指定更大的binarySize来满足检查,触发溢出
4、 漏洞利用执行方法
我们需要在堆上覆盖一个函数指针,或者破坏C++的虚表指针
(1)首先将DnD/CP协议设置为version 3,RPCI在检查到DnD/CP协议版本修改时会创建一个对应版本的C++对象,对于version3,两个C++对象会被创建,一个用于DnD,一个用于CP
(2)分配一个内存块,让它分配在C++对象前,利用堆溢出改写C++对象的vtable指针(虚表),让其指向可控内存,执行SHELL
5、 绕过ASLR
在实现上述过程首先要绕过保护机制ASLR(地址空间布局随机化)
关键在于找到能够破坏的,带有长度或数据指针的对象,并且可以被guest读取。
于是找到了“info-set”和”info-get”
我们可以通过溢出来覆盖结尾的null字节,让字符串连接上相邻的内存块。如果我们能够在发生溢出的内存块和DnD或CP对象之间分配一个字符串,那么我们就能泄露对象的vtable地址,从而我们就可以知道vmware-vmx的地址。
问题在于,这种覆盖可能导致关键函数被覆盖从而崩溃
具体实现策略:
1.首先分配一些填满“A”的字符串,
2.然后通过溢出写入一些“B”,
3.接下来读取所有分配的字符串,其中含有“B”的就是被溢出的字符串。
4.这样我们就找到了一个字符串可以被用来读取泄露的数据,然后以bucket的内存块大小0xA8的粒度继续溢出,每次溢出后都检查泄露的数据。
5.由于DnD和CP对象的vtable距离vmware-vmx基地址的偏移是固定的,每次溢出后只需要检查最低一些数据位,就能够判断溢出是否到达了目标对象。
执行流程图
6、 两种情形,两种方法
(1)DND
不能只覆盖vtable指针,需要伪造一个vtable来躲避访问
(2)CP
覆盖虚指针,让它指向我们可控的其他数据,这些数据可以用作对象虚表,只要我们找到一个指向可控数据的指针就可以解决
7、 如何解决LFH堆问题
LFH堆一旦开启便无法关闭,但是使用一些全局标志可以导致无法启用LFH(gflag调试)
8、 例图
由于我们之前执行获得的结果截图没有保存,因此这里使用的是原作者的例图。
我们使用的是WINXP虚拟系统实现的逃逸。