首页
社区
课程
招聘
走进虚拟机逃逸技术之VMware Escape漏洞CVE-2023-20872复现
发表于: 2024-7-18 19:04 7698

走进虚拟机逃逸技术之VMware Escape漏洞CVE-2023-20872复现

2024-7-18 19:04
7698

POC代码在这里:https://github.com/ze0r/vmware-escape-CVE-2023-20872-poc

    起初,为了学习虚拟机逃逸相关技术,也为了搞懂硬件虚拟化。于是请教了某巨佬后告诉我一本书,看完之后为了验证我理解到的硬件虚拟化及虚拟化逃逸原理是否正确,于是便有了此次实验,继而有了本文。
 
    在看完书后,网上看到了HITB 2023大会上的一个虚拟机逃逸的议题,名字是:“Escaping From VMware Workstation Through The Disk Controller - Wenxu Yin”,有兴趣的可以自行搜索。看完视频后就觉得这个漏洞值得一试,理由是:
1 从视频内容上看,这个漏洞相当得简单直接,用来学习虚拟机逃逸是个绝佳得案例
2 视频内容可以看出,这个漏洞相当稳定好用,毕竟现场演示用的是真机实际环境直接演示,连个视频都不录,所以肯定是个稳定好用的漏洞。
 
    基于这两条信息,就想要复现一下这个漏洞,于是有了下面的事情。
 
    我看书学到的就是,虚拟机逃逸的本质其实就是,虚拟机软件(vmware)对non-root模式下CPU发出的IO指令的接管和处理,也就是none-root模式下发出的IO中断请求,通过VMCB结构中的信息退出到root模式来管理,而接管了guest发出的IO请求后,hypervisor(虚拟机软件)通过VMCB拿到并处理这个请求,而虚拟机软件逃逸漏洞,其实就是发生在这个处理请求时,虚拟机软件中的BUG导致。此为漏洞原理本质。
 
    按照视频中的配置安装vmware和guest操作系统,宿主机就直接用我日常用的电脑,卸载了最新版的vmware,然后搜索到17.0.0-20800274版的vmware安装,guest操作系统使用ubuntu 22.04
 
首先,我们来到视频中所说的检查函数:
    起初,为了学习虚拟机逃逸相关技术,也为了搞懂硬件虚拟化。于是请教了某巨佬后告诉我一本书,看完之后为了验证我理解到的硬件虚拟化及虚拟化逃逸原理是否正确,于是便有了此次实验,继而有了本文。
 
    在看完书后,网上看到了HITB 2023大会上的一个虚拟机逃逸的议题,名字是:“Escaping From VMware Workstation Through The Disk Controller - Wenxu Yin”,有兴趣的可以自行搜索。看完视频后就觉得这个漏洞值得一试,理由是:
1 从视频内容上看,这个漏洞相当得简单直接,用来学习虚拟机逃逸是个绝佳得案例
2 视频内容可以看出,这个漏洞相当稳定好用,毕竟现场演示用的是真机实际环境直接演示,连个视频都不录,所以肯定是个稳定好用的漏洞。
 
    基于这两条信息,就想要复现一下这个漏洞,于是有了下面的事情。
 
    我看书学到的就是,虚拟机逃逸的本质其实就是,虚拟机软件(vmware)对non-root模式下CPU发出的IO指令的接管和处理,也就是none-root模式下发出的IO中断请求,通过VMCB结构中的信息退出到root模式来管理,而接管了guest发出的IO请求后,hypervisor(虚拟机软件)通过VMCB拿到并处理这个请求,而虚拟机软件逃逸漏洞,其实就是发生在这个处理请求时,虚拟机软件中的BUG导致。此为漏洞原理本质。
 
    按照视频中的配置安装vmware和guest操作系统,宿主机就直接用我日常用的电脑,卸载了最新版的vmware,然后搜索到17.0.0-20800274版的vmware安装,guest操作系统使用ubuntu 22.04
 
首先,我们来到视频中所说的检查函数:
代码一目了然,CDB_Info就是第三个参数a3,这个结构偏移0x30的地方就是传进来的_MSG_SCSI_IO_REQUEST的CDB数据,只有0x10大小,偏移0x28处就是CDBlength,是一个byte,而在随后的33行,根据CDB数据的第一个字节右移5位作为下标,数组就是1409D9238处,数组各元素为可用的CDB长度,这个就不截图了,视频中有。其中第4个元素(下标3)为0x40,我们只要将CDB数据第一个字节(OPcode)设置为 3<<5 = 0x60即可。
 
接下来代码进行了一个判断,判断传递进来的_MSG_SCSI_IO_REQUEST结构中的CDBlength是否和通过数组中下标元素得到的长度相等。首先CDB数据整个有16个byte,根据相关CDB文档,只要是16个字节以内,则不会产生越界溢出,故我们需要将CDBlength设置为0x40 or 0x41,如何做到这一点?此为问题1,且先按下不表。
 
回头看视频中,我们看到调用溢出函数的上层返回地址为14072CC67,对应调用:
代码一目了然,CDB_Info就是第三个参数a3,这个结构偏移0x30的地方就是传进来的_MSG_SCSI_IO_REQUEST的CDB数据,只有0x10大小,偏移0x28处就是CDBlength,是一个byte,而在随后的33行,根据CDB数据的第一个字节右移5位作为下标,数组就是1409D9238处,数组各元素为可用的CDB长度,这个就不截图了,视频中有。其中第4个元素(下标3)为0x40,我们只要将CDB数据第一个字节(OPcode)设置为 3<<5 = 0x60即可。
 
接下来代码进行了一个判断,判断传递进来的_MSG_SCSI_IO_REQUEST结构中的CDBlength是否和通过数组中下标元素得到的长度相等。首先CDB数据整个有16个byte,根据相关CDB文档,只要是16个字节以内,则不会产生越界溢出,故我们需要将CDBlength设置为0x40 or 0x41,如何做到这一点?此为问题1,且先按下不表。
 
回头看视频中,我们看到调用溢出函数的上层返回地址为14072CC67,对应调用:
其中第21行的间接调用导致进入了目标函数,而在call前的第16行中,判断了a1 + 8的指针偏移0x18的地方是否为空,不为空后续则调用这个地方的函数地址。而实际调试时:
其中第21行的间接调用导致进入了目标函数,而在call前的第16行中,判断了a1 + 8的指针偏移0x18的地方是否为空,不为空后续则调用这个地方的函数地址。而实际调试时:
可看到偏移0x18的地方根本就是0,根本就不可能进入目标函数。根据上图第16行的间接可知,必然有一条路径是把目标函数放到偏移0x18的地方的,并且a1+8的地方很可能是个函数表之类的结构,于是查看目标函数的交叉引用:
可看到偏移0x18的地方根本就是0,根本就不可能进入目标函数。根据上图第16行的间接可知,必然有一条路径是把目标函数放到偏移0x18的地方的,并且a1+8的地方很可能是个函数表之类的结构,于是查看目标函数的交叉引用:
其中0x140BC4D38处的引用有一次对该结构的引用:
其中0x140BC4D38处的引用有一次对该结构的引用:
继续引用之,来到sub_14080DDD0函数:
继续引用之,来到sub_14080DDD0函数:
看来是在这里会根据前面的各种情况对a1+8赋予各种不同的函数表指针,所以我们的工作就是让流程走到这个函数,于是交叉引用之,来到函数sub_14072D170:

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-7-18 19:51 被bksaro编辑 ,原因: 添加代码地址
收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 459
活跃值: (1652)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我想知道是那本书
2024-7-18 20:17
0
雪    币: 1243
活跃值: (347)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
Panel_demo 我想知道是那本书[em_1]
哈哈,书名是《newBluePill深入理解硬件虚拟机》
2024-7-18 22:18
0
雪    币: 459
活跃值: (1652)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
bksaro 哈哈,书名是《newBluePill深入理解硬件虚拟机》
好的,感谢分享
2024-7-28 16:31
0
游客
登录 | 注册 方可回帖
返回
//