网站架设软件,网站建设哪家好首推万维科技,老河口网页定制,建设网站用户名走进虚拟机逃逸技术之VMware Escape漏洞CVE-2023-20872复现 技术分享 技术分享
起初#xff0c;为了学习虚拟机逃逸相关技术#xff0c;也为了搞懂硬件虚拟化。于是请教了某巨佬后告诉我一本书#xff0c;看完之后为了验证我理解到的硬件虚拟化及虚拟化逃逸原理是否正确为了学习虚拟机逃逸相关技术也为了搞懂硬件虚拟化。于是请教了某巨佬后告诉我一本书看完之后为了验证我理解到的硬件虚拟化及虚拟化逃逸原理是否正确于是便有了此次实验继而有了本文。 在看完书后网上看到了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设置为 35 0x60即可。接下来代码进行了一个判断判断传递进来的_MSG_SCSI_IO_REQUEST结构中的CDBlength是否和通过
数组中下标元素得到的长度相等。首先CDB数据整个
有16个byte根据相关CDB文档只要是16个字节以内
则不会产生越界溢出故我们需要将CDBlength设置为0x40 or 0x41如何做到这一点此为问题1且先按下不表。
回头看视频中我们看到调用溢出函数的上层返
回地址为14072CC67对应调用 其中第21行的间接调用导致进入了目标函数而在call前的第16行
中判断了a1 8的指针偏移0x18的地方是否为空不为空后续
则调用这个地方的函数地址。而实际调试时可看到偏移0x18的地方根本就是0根本就不可能进入目标函数。根据上图第16行的间接可知必然有一条路径是把目标函数放到
偏移0x18的地方的并且a18的地方很可能是个函数表之类的结
构于是查看目标函数的交叉引用其中0x140BC4D38处的引用有一次对该结构的引用继续引用之来到sub_14080DDD0函数看来是在这里会根据前面的各种情况对a18赋予各种不同的函数
表指针所以我们的工作就是让流程走到这个函数于是交叉引
用之来到函数sub_14072D170:在这里就很明白了sub_14072D170会根据第二个参数来决定
a1使用哪张函数表。调用sub_14072D170的有两处不废话只
说有用的一处另一处一看就没用来到上层这就很有意思了这第二个参数取决于v16结构
而v16的唯一赋值/使用是在26行看来应该是16行的
sub_1400F07C0根据a1a8的数据对v16进行了设置我无心去看
这个sub_1400F07C0内部到底怎么设置v16的因为看到了第32行
的那串英文很明显那是个输出调试信息的其中就有第二个参数
对应的输出是“typex”意味着v12是类型所以这里是
根据CDROM的类型来选择不同的处理方式于是虽然我有十足信心这里是CD的类型但总要实践来证明。可大事
不妙我没有物理光驱随后测试在这里下断后手工更改sub_14072D170函数调用时第二
个参数的值:失败看来此type值还会影响其他后续操作。但是这个失败至少
证明了一点我们更改这第二个参数type,真的应更改了CDROM的类
型即CDROM的类型就可以决定这第二个参数type。于是金钱的力量就是好使虽然才48块接下来就是等待到货了在
这期间我也没闲着一直在测试问题1怎么解决。
很显然问题1其实就等同于如何在LINUX操作系统中给光驱发
送控制命令CDB具体是发送自己任意构造的控制信息
_MSG_SCSI_IO_REQUEST。此乃代码之事自然是要交给AI:在跟chatGPT一顿聊天后写出了第一版的发送自定义CDB信息给光
驱控制器。但随后只要将CDB长度改为大于16字节就发现调试
vmware的windbg中不会打印信息而长度6、10、12、16则可正常
显示。这有两种可能1 是Guest中的Linux内核根本就没有把IO请
求发送给控制器--vmware即LINUX内核中有检查 2 是vmware对
_MSG_SCSI_IO_REQUEST结构有检查。由于视频中并未提及情况2
故本人倾向于情况1导致。于是继续翻了一两天Linux内核代码首
先发现的是chatGPT给我的方法是比较上层的内核函数这个方法
只是把CDB请求加入到了底层驱动请求队列中并非直接与IO驱动
打交道大致来说就是文件驱动发送一个请求插入到队列里而这个队列
中的各种块设备操作可能涉及到各种设备磁头位置的读写于是
采用统一的块设备驱动层来管理这些队列中的请求一般情况下写
操作因为比较慢都是直接写的内存缓存在一定条件下才会真正落
实写文件操作。而块设备会真正落实写文件时才会真的跟块设备
控制器交互。于是我们的ko真正应该调用的是落实块设备交互的那
些函数--mptspi这里虽然视频中也提到了。于是看Linux SCSI驱
动相关模块找到mptspi相关代码部分调用其中函数直接去控制
块设备--CDROM。终于实现了可以发送任意篡改的
_MSG_SCSI_IO_REQUEST结构给“块设备控制器”--vmware上图中红框的40就是该改掉的CDBlength之后60开头的那一串
22就是CDB。至此问题1完美解决。同时其实是稍早一点USB光
驱也到货了插上光驱调整为使用物理光驱再次调试可以看到直接传进来的参数二就是0直接就是另一个类型于是
后续自然调用vmware_vmx80ddd0处的函数设置a1结构之后a18
处的函数表的第4个元素即0x18处已经有了具体的某函数。之后便
是一路畅通的走到判断18处函数并调用最后成功触发漏洞越界写造成crash vmware:实验结束成功获得虚拟机逃逸技术技能树点亮1。POC代码在这里https://github.com/ze0r/vmware-escape-CVE-2023-20872-poc