深入探索Hypervisor:Oracle VirtualBox研究
我进入漏洞研究领域已有一段时间,VirtualBox是我的第一个研究目标。在这个过程中我学到了很多,希望这些笔记能为对逃逸hypervisor感兴趣的读者提供有用的信息。
我假设读者对内存破坏、hypervisor架构和设备I/O有一定的基础知识。
本文中的代码片段基于VirtualBox 6.1.4。
在Windows上编译VirtualBox
VirtualBox的用户态进程可能被用来攻击内核,因此它实现了一个内核模块来保护用户态进程和驱动本身。这意味着我们不能简单地附加任何调试器到VM进程进行调试。感谢@_niklasb,我知道有两种解决方法:
- 使用嵌套虚拟机,在VMWare虚拟机中运行VirtualBox,然后使用远程内核调试器
- 构建一个没有进程强化的自定义VirtualBox版本,这样我们还能获得调试符号
按照这个指南的步骤构建VirtualBox可以节省大量时间。
寻找有趣的代码部分
人们最常问我的问题之一是如何在如此庞大的代码库中寻找漏洞。对我来说,答案是查看处理客户机操作系统提供数据的代码部分。简而言之,VirtualBox(或hypervisor)包含许多模拟设备,有些是常见标准设备(Intel 82540EM以太网控制器、Intel HD音频控制器、开放主机控制器接口等),有些是VirtualBox特定设备(VMM/主机通信设备)。这些模拟设备使用设备特定协议与客户机操作系统通信处理数据,我们的目标是操纵这些通信,破坏它们的协议并使设备进入异常状态。
要利用模拟设备,你需要编写一个内核模块与之交互,然后正确设置设备寄存器并触发数据处理。以下是一些设备处理客户机提供数据(通常是表示某些数据结构的二进制blob)的建议位置:
RT_UNTRUSTED_VOLATILE_GUEST关键字
从定义来看:
|
|
任何用RT_UNTRUSTED_VOLATILE_GUEST关键字声明的变量都应包含与客户机操作系统共享的易失性数据,客户机可能随时修改这些数据。在源代码目录中搜索此关键字可以揭示许多使用不可信客户机数据的函数。
I/O端口和映射内存处理程序
I/O端口和映射内存是CPU与其他设备之间执行输入/输出的两种互补方法。要找到这些处理程序的注册位置,可以搜索以下函数调用:
|
|
pfnIn
和pfnOut
是处理客户机CPU IN和OUT指令的回调函数。
|
|
pfnWrite
和pfnRead
是处理客户机映射内存读写操作的回调函数。
搜索这些函数的引用,我们可以找到许多直接处理客户机操作系统数据的地方。
客户机物理内存读写处理程序
如果模拟设备想要从客户机内存读写数据,它们会使用以下函数:
|
|
GCPhys
是要读取的缓冲区的客户机物理地址。
pvBuf
是存储读取缓冲区的主机进程缓冲区。
cbRead
是缓冲区的大小。
|
|
GCPhys
是要写入的缓冲区的客户机物理地址。
pvBuf
是要写入客户机内存的主机进程缓冲区。
cbWrite
是缓冲区的大小。
我们可以将这些函数视为类似memmove()
,但是从客户机操作系统到主机进程,反之亦然。因此,如果这些操作的大小计算错误:
- 对于
PDMDevHlpPhysRead
,它可能覆盖目标主机缓冲区相邻的内存并触发内存越界写入。通过这一点,我们可以控制对象的vtable、属性等。 - 对于
PDMDevHlpPhysWrite
,它可能过度读取源缓冲区相邻的内存并将其移动到客户机物理内存。客户机操作系统可以读取此物理内存并获得信息泄露
寻找漏洞
你可以使用上述说明开始审计VirtualBox源代码,以下关于模糊测试的想法也可以应用于QEMU、VMWare等。
简单模糊测试
我曾经这样在VirtualBox中寻找漏洞:
编写一个持续执行以下操作的内核驱动:
- 生成随机的设备数据结构
- 将生成的数据保存到共享文件夹
- 使用I/O端口或映射内存设置设备状态和寄存器
在主机VM进程上启用页面堆。 启动VM然后运行驱动,等待VM崩溃。 检查VM日志文件和共享文件夹中保存的测试用例。 尝试复现并找到根本原因。
这种方法使用起来相当简单,我会先生成简单的随机数据结构,然后启动模糊器。在等待它发现任何问题的同时,我可以继续阅读源代码来优化生成器,制作更复杂的结构并通过更多约束。
这种方法确实有效,我用它赢得了我的第一次Pwn2Own。研究和编写合适的生成器花了我几天时间,但运行模糊器后5分钟就找到了这个漏洞。漏洞利用细节可以在这里找到。
覆盖率导向的模糊测试
在对这些模拟设备进行简单模糊测试一段时间后,我意识到设备处理的大多数数据都是使用PDMDevHlpPhysRead()
函数从客户机物理内存读取的。由于我们的驱动可以完全控制该内存范围,于是我有了一个想法。
首先,我修改VirtualBox的源代码,检查VM进程是否在模糊测试模式下运行。如果我们在模糊测试模式下,设备将从主机操作系统上的文件读取数据,而不是使用PDMDevHlpPhysRead()
函数从客户机内存读取。
例如,我们选择E1000网络适配器,因为这里有一些已发布的研究。当它想要发送以太网帧时,它会使用e1kTxDLoadMore()
函数从客户机内存读取帧:
|
|
继续修改设备使用PDMDevHlpPhysRead()
读取数据的每个位置,然后我们需要阅读代码来了解设备如何处理一个数据单元,例如:
- E1000网络适配器如何发送以太网帧
- OHCI USB控制器如何发送URB
- HDA如何传输流等
有了这些知识,我们可以编写一个函数来快速调用必要的函数执行数据处理,记得每次重置设备以确保代码覆盖率稳定。我们称这个函数为fuzz_entry()
。
在设备的初始化例程中选择一个合适的位置放置对fuzz_entry()
函数的调用,然后每次VM在模糊测试模式下启动时,fuzz_entry()
将被调用并处理来自测试用例文件的数据。现在,VirtualBox变成了一个可以读取输入文件并处理它的应用程序,因此我们可以使用AFL来模糊测试它。这就是我为HITB Driven2Pwn 2019和Pwn2Own 2020找到漏洞的方法,详细文章即将发布。
漏洞利用原语
堆喷射
当你想要执行堆喷射时,需要在主机VM进程中分配许多具有受控内容的缓冲区,以下是我实现的方法。
分配大小 < 0x3FA0:使用E1000网络适配器发送以太网帧
通过适当的设备配置,E1000网络适配器将使用RTMemAlloc()
(malloc()
的包装器)分配帧缓冲区。以太网帧的最大大小为0x3FA0。
分配大小 > 0x1000:发送VMMDev请求
当我们发送VMMDev请求时,VM将在主机进程中复制命令。利用此功能,我们可以在主机进程中分配缓冲区。
要通过这种方式分配缓冲区,需要在客户机操作系统中安装Guest Additions。
信息泄露
通过观察Windows中主机进程VirtualBoxVM.exe的内存布局,由于随机化较弱,视频RAM缓冲区(VRAM)的范围每次运行都相当相似。
这是共享内存,主机进程和客户机操作系统都可以访问。对于Windows 10 64位客户机,其默认大小为128MB。
我编写了一个脚本来转储VRAM地址及其大小,运行约500次后得到如下结果:
|
|
我们可以看到VRAM地址略有不同,但内存范围0xcb10000 - 0x13220000总是落在此缓冲区内。因此,使用地址0x10000000作为泄露地址是安全的。
通过这种巧妙的信息泄露,我在HITB Driven2Pwn 2019上用一个单一的UAF漏洞逃逸了VirtualBox。
RWX页面
在Windows主机上,这个页面非常接近VRAM缓冲区,并且其大小足够大,我们可以很好地猜测其地址。这样我们就免费获得了一个RWX页面的地址,还有什么比这更好的呢?:D
这个页面过去是由重新编译器模块分配的,但不幸的是,自VirtualBox 6.1.0以来,这个模块已被移除。
即将发布的文章
在接下来的文章中,我们将介绍通过本文描述的方法发现的漏洞利用。
其他VirtualBox研究
- https://github.com/MorteNoir1/virtualbox_e1000_0day
- https://www.voidsecurity.in/
- https://ssd-disclosure.com/ssd-advisory-virtualbox-vrdp-guest-to-host-escape/
- https://ssd-disclosure.com/ssd-advisory-oracle-virtualbox-multiple-guest-to-host-escape-vulnerabilities/
- https://github.com/phoenhex/files/blob/master/slides/unboxing_your_virtualboxes.pdf
- https://github.com/phoenhex/files/blob/master/slides/thinking_outside_the_virtualbox.pdf
- https://labs.f-secure.com/archive/3d-accelerated-exploitation/
- https://www.thezdi.com/blog/2018/8/28/virtualbox-3d-acceleration-an-accelerated-attack-surface
- https://www.coresecurity.com/corelabs-research/publications/breaking-out-virtualbox-through-3d-acceleration
- https://phoenhex.re/2018-07-27/better-slow-than-sorry