标题 | 简介 | 类型 | 公开时间 | ||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
详情 | |||||||||||||||||||
[SAFE-ID: JIWO-2024-2222] 作者: 凉笙 发表于: [2018-12-16]
本文共 [449] 位读者顶过
0x00 漏洞编号
[出自:jiwo.org]
在VMware Workstation和Fusion中的拖放(Dnd)和复制粘贴(CP)功能存在堆溢出漏洞,这会让虚拟机客户端在宿主机上执行任意代码。
0x03 漏洞原理
1. RPCI通信机制
在介绍漏洞原理之前,先来了解一下VMWare中宿主机(host)与虚拟机(guest)之间的通信机制,其中的一种方式叫做Backdoor,利用windows的特权指令in,该指令在正常的host环境用户态中执行会报异常,而在guest中正是利用该异常被host的hypervisor捕获,来实现通信。
guest中利用frida框架注入到vmtools.exe中使用RpcChannel_SendOneRaw发送消息。
RpcChannel_SendOneRaw调用路径: RpcChannel_SendOneRaw -> RpcChannel_Send -> BkdoorChannelSend -> RpcOut_send -> Message_Send -> Backdoor -> in特权指令
RpcChannel_SendOneRaw的参数 const char *data就是给Host发送的指令, 在第3小节会讲host是怎么接收guest 的命令。
2. 漏洞
Dnd/CP的Version 4的dnd/cp分片数据包校验函数。
代码如下:
static Bool
open-vm-tools中的代码在此:dndCPMsgV4.c
对于Dnd/CP version 4的功能中,当guest发送分片Dnd/CP命令数据包时,会调用DnDCPMsgV4_UnserializeMultiple函数进行分片重组,重组的时候DnDCPMsgV4IsPacketValid函数中的[1]处代码校验不严格,会导致[2]处堆溢出,可以构造如下的数据包来触发漏洞。
Dnd/CP的Version 3的dnd分片数据包校验函数。
Bool
open-vm-tools中的代码在此:dndCommon.c
对于老版本Version 3的Dnd/CP的功能中,在[3]处同样对分片重组的包有着校验失效的问题,可以发送如下的数据包来触发溢出。
3. 漏洞原理
第2节看完open-vm-tools中漏洞溢出的地方,现在来看vmware-vmx.exe中怎么利用漏洞实现逃逸。
bind_function会把RPCI通信的命令和函数绑定到一个函数指针数组里面。
bind_function第3个参数是命令的名字,第4个参数是对应处理的回调函数。
回调函数的定义如下:
char fastcall handler(int64 a1, __int64 a2, const char request, int requestlen, const char **result, _DWORD resultlen);
handler第三个参数是接收的命令, 第5个参数是回复给guest的数据。
发送如下命令可以设置和查询dnd/cp的版本。
讲完host如何接收guest的命令后,来看看guest的堆溢出怎么触发host的逃逸。
在处理guest的“tools.capability.dnd_version 3"命令时,设置当前的dnd_version。
在处理guest的"vmx.capability.dnd_version"命令时,会获取当前的dnd_version,并且更新dnd/cp全局对象。
在Update_DndCP_Object函数中delete掉前一个版本的obj_CP和obj_Dnd, 析构对象的时候都会调用到他们各自的虚函数,只需要溢出到虚表上就能执行漏洞代码。
能够执行代码的路径很多,可以溢出Dnd,也可以溢出CP, 只需要选择溢出其中一个虚函数。
0x04 绕过ASLR
要想在guest中获取host的对象,就需要有个能够泄漏信息的地方,例如guest中发送info-set和info-get命令。
利用info-set覆盖字符串的结尾NULL字符,让value字符串与后面的内存块连接起来,然后在info-get中读取Key,就能获取到value字符串后面的内存,达到信息泄漏。
0x05 Exploit分析
此次分析的exp是由unamer发布在github上的vmware_escape项目。
1. 设置DnD/CP版本
2. 绕过ASLR
多次发送info-set, info-get,进行堆溢出。
获取泄漏的信息,绕过ASLR。
3. 实现代码执行
通过泄漏的信息,判断是指针是Dnd对象还是CP对象,然后设置不同的rop。
、 |