所谓虚拟机逃逸(Escape Exploit),指的是突破虚拟机的限制,实现与宿主机操作系统交互的一个过程,攻击者可以通过虚拟机逃逸感染宿主机或者在宿主机上运行恶意软件。
针对 VMware 的虚拟机逃逸 exploit 源码实现了从虚拟机到宿主机器的代码执行,弹出了熟悉的计算器。该开源代码,只需要将执行计算器部分的 shellcode 替换成其他具有恶意攻击的代码,就可以造成很大的危害。
影响范围
- VMware Workstation Pro / Player(12.5.5 之前版本)
- VMware Fusion Pro / Fusion
漏洞分析
- 首先分析漏洞存在于 DnD 和 CnP 机制的 Version3 中,故设置 DnD 与 CnP 均为 version3 的版本。使用的命令分别为「tool.capability.dnd_version 3」和「tools.capability.copypaste_version 3」。
- 为了达到代码执行,需要溢出堆中对象函数指针或者虚表指针。
- 需要通过查询DnD和CnP的版本才能使设置生效,需要发送的命令分别为:「vmx.capability.dnd_version」和「vmx.capability.copypaste_version」,这两个命令均会检查 DnD/CnP 机制的版本,同时根据版本会创建两个对象,DnD 和 CnP,其中 version3 对应的 C++ 对象大小为 0xA8。
- 根据 C++ 对象的大小进行多次越界写内存。
- 通过命令 info-set guestinfo.KEY VALUE 和 info-get guestinfo.KEY 来设置和获取数据绕过 ASLR,通过这两个命令后面的值来泄露堆上的对象,从而获取对象的虚表地址,从而得到 vmware-vmx 的地址。
- 我们根据信息泄露判断溢出的是哪一种 C++ 对象,是 DnD 还是 CnP。根据判断类型,分别利用 ROP 绕过 DEP,拼接 shellcode 后完成 exploit 的构造。CnP 类型对象溢出利用构造:覆盖对象虚表地址,指向伪造的虚表,然后发送 CP 命令,触发虚函数调用,实现命令执行。
SetGlobalPointer 函数发送 「unity.window.contents.start」 命令,通过在命令中指定参数的宽度和高度,写入一个 64 位的堆栈迁移 gadget 地址。然后 DnD 类型对象溢出利用构造,最终发送 payload 完成构造!
逃逸演示
稳定性讨论
因为 Windows LFH 堆的随机化,当前的 exploit 无法做到 100% 成功率。不过可以尝试下列方法来提高成功率:
- 观察 0xA8 大小的内存分配,考虑是否可以通过一些 malloc 和 free 的调用来实现确定性的 LFH 分配,参考这里和这里。
- 寻找堆上的其他 C++ 对象,尤其是那些可以在堆上喷射的
- 寻找堆上其他带有函数指针的对象,尤其是那些可以在堆上喷射的
- 找到一个独立的信息泄漏漏洞