利用硬件级MDS侧信道漏洞实现对Chrome Sandbox的逃逸
2021-06-14
来源:嘶吼专业版
可以利用跨进程内存泄漏的漏洞逃逸Chrome沙箱,在发起此攻击之前,仍然需要攻击者破坏渲染器,为了防止对受影响的CPU的攻击,请确保microcode是最新的,并禁用超线程(HT)。
在我的上一个文章“破坏数据流”中,我描述了如何利用Chrome的JavaScript引擎V8中的漏洞来在渲染器中执行代码。为了使这种利用有用,你通常需要将其与第二个漏洞相关联,因为Chrome的沙箱会限制你对操作系统的访问,并且将跨站点渲染器的站点隔离移动到单独的进程中,以防止你绕过Web平台的限制。
在本文中,我们将研究沙盒,尤其是当从受感染的渲染器使用RIDL和类似的硬件漏洞时所产生的影响。Chrome的IPC机制Mojo基于消息路由的机密,泄漏这些机密使我们可以将消息发送到特权接口,并执行不应允许渲染器执行的操作。我们将使用它来读取任意本地文件,以及在Windows上的沙箱外部执行。bat文件。在撰写本文时,Apple和Microsoft都在与Chrome安全团队合作积极致力于修复此漏洞,以防止这种攻击。
0x01 背景知识
以下是Chrome流程模型的简要概述:
渲染器进程位于单独的沙箱中,并且对内核的访问受到限制,例如,通过Linux上的seccomp过滤器或Windows 上的 win32k锁定。但是,为了使渲染器执行任何有用的操作,它需要与其他进程进行对话以执行各种操作。例如,要加载图像,将需要要求网络服务代表其获取图像。
Chrome中用于进程间通信的默认机制称为Mojo。它在后台支持消息/数据管道和共享内存,但是你通常会使用C ++,Java或JavaScript中的高级语言之一绑定。也就是说,你使用自定义接口定义语言(IDL)的方法创建一个接口,Mojo用你选择的语言为你生成存根,而你只是实现了该功能。这可以检查出URLLoaderFactory .mojom IDL,C ++实现,并在渲染使用。
Mojo的一项显着功能是允许你通过现有通道转发IPC端点。该代码在Chrome代码库中得到了广泛使用,即,每当你在。mojom文件中看到接收器或远程参数时。
Mojo在进程之间或更具体地在Mojo的节点之间使用特定于平台的消息管道。两个节点可以直接彼此连接,但是由于Mojo支持消息路由,因此不必连接。网络中的一个节点称为代理节点,它具有一些其他责任来设置节点通道并执行沙箱限制的某些操作。
IPC端点本身称为端口。在上面的URLLoaderFactory示例中,客户端和实现方都由端口标识。在代码中,端口如下所示:
class Port : public base::RefCountedThreadSafe {
public:
// […]
// The current State of the Port.
State state;
// The Node and Port address to which events should be routed FROM this Port.
// Note that this is NOT necessarily the address of the Port currently sending
// events TO this Port.
NodeName peer_node_name;
PortName peer_port_name;
// The next available sequence number to use for outgoing user message events
// originating from this port.
uint64_t next_sequence_num_to_send;
// […]
}
上面的peer_node_name 和peer_port_name 都是用于寻址的128位随机整数。如果将消息发送到端口,它将首先将其转发到正确的节点,接收节点将在本地端口映射中查找端口名称,并将消息放入正确的消息队列。
这意味着如果浏览器进程中存在信息泄漏漏洞,则可以泄漏端口名称,并使用它们将消息注入特权IPC通道。实际上,在Mojo核心文档的安全性部分中对此进行了声明:
“ […]任何节点只要知道端口和节点名称,就可以将任何消息发送到任何其他节点的任何端口。[…]因此,重要的是不要将端口名称泄漏到不应被授予相应功能的节点中。”
可以很容易地利用泄漏的端口号的一个漏洞的一个很好的例子是crbug.com/779314通过@NedWilliamson。这是blob实现中的整数溢出,它使你可以在浏览器进程中读取blob前面的任意数量的堆内存。
该漏洞利用过程将大致如下所示:
1. 破坏渲染器。
2. 使用Blob漏洞泄漏堆内存。
3. 在存储器中搜索端口(有效状态+ 16个高熵字节)。
4. 使用泄漏的端口将消息注入特权IPC连接。
接下来,我们需要考虑两件事。如何用CPU漏洞替换上面的第2步和第3步,以及如何通过特权IPC连接获得什么样的原语。
0x02 RIDL
为了利用此硬件漏洞,我需要寻找另一个漏洞,该漏洞使你可以跨进程边界泄漏内存。来自MDS攻击的 RIDL 似乎是最理想的选择,因为它完全可以保证:它允许你从受影响的CPU上的各种内部缓冲区泄漏数据。有关其工作原理的详细信息,请查看论文或PPT,因为它们比我能解释的要好得多。
已经发布了 microcode和操作系统更新来解决MDS攻击。但是,如果你阅读了英特尔对该问题的深入](https://software.intel.com/security-software-guidance/insights/deep-dive-intel-analysis-microarchitectural-data-sampling)研究,你会注意到,缓解措施在切换到特权较低的执行上下文时清除了受影响的缓冲区。如果你的CPU支持超线程,你仍然可以从物理内核上运行的第二个线程中泄漏数据。解决此问题的建议是禁用超线程或实现组调度程序。
你可以在网上找到多个验证了该MDS 漏洞的PoC,他们中的一些具有不同的属性:
· 它们以加载或存储目标。
· 有些要求从L1缓存中清除key。
· 你可以控制64字节高速缓存行中的索引从先前的访问中泄漏或泄漏64位的值。
· 速度变化很大,取决于变体和漏洞利用。我看到的最高是针对Brandon Falk的228kB / s 的MLPDS攻击。为了进行比较,我的机器上的漏洞利用仅达到25kB / s。
https://gamozolabs.github.io/metrology/2019/12/30/load-port-monitor.html#an-mlpds-exploit
所有利用变体有一个共同属性是,它们在泄漏的内容上具有概率。尽管RIDL论文描述了一些针对某些值的同步原语,但通常需要触发对key的重复访问才能将其完全泄漏。
我最终使用不同的MDS变体为Chrome编写了两个漏洞利用,一个针对Xeon Gold 6154上的Linux构建,另一个针对Core i7-7600U上的Windows。我将描述这两种方法,因为它们在实践中最终面临不同的挑战。
0x03 MFBDS
微体系结构填充缓冲区数据采样(MFBDS)
我的第一个漏洞是使用针对CPU的行填充缓冲区的MFBDS。PoC非常简单:
xbegin out ; start TSX to catch segfault
mov rax, [0] ; read from page 0 => leaks a value from line fill buffer
; the rest will only execute speculatively
and rax, 0xff ; mask out one byte
shl rax, 0xc ; use as page index
add rax, 0x13370000 ; add address of probe array
prefetchnta [rax] ; access into probe array
xend
out: nop
此后,你将定时访问探针阵列以查看已缓存了哪个索引。
你可以在开头更改0 ,以控制泄漏的高速缓存行中的偏移量。另外,你还希望按照本文所述在泄漏值上实现前缀或后缀过滤器。请注意,这只会泄漏不在L1高速缓存中的值,因此你希望有一种方法可以在两次访问之间从高速缓存中移出key值。
对于我的第一个泄漏目标,我选择了一个特权URLLoaderFactory。如上所述,渲染器使用URLLoaderFactory来获取网络资源。它将为渲染器强制执行同源策略(实际上是相同站点),以确保不会破坏Web平台的限制。但是,浏览器进程还将URLLoaderFactories用于不同的目的,并且它们具有其他特权。除了忽略同源策略外,还允许它们上传本地文件。因此,如果我们可以泄漏其端口名之一,则可以使用它将/ etc / passwd 上传到https://evil.website。
下一步将触发对特权加载程序的端口名的重复访问。使浏览器进程发出网络请求可能是一种选择,但似乎开销太大,我决定针对节点中的端口查找。
class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
// […]
std::unordered_map ports_;
// […]
}
每个节点都有一个存储所有本地端口的哈希映射。如果我们将消息发送到不存在的端口,目标节点将在映射中查找它,发现它不存在并删除消息。如果我们的端口名与另一个端口名位于同一哈希库中,它将读取未知端口的完整哈希值以与之进行比较。由于端口名通常与散列存储在同一高速缓存行中,因此这还将端口名本身加载到高速缓存中。MFBDS允许我们泄漏整个缓存行,即使未直接访问值也是如此。
该maps在一个新的Chrome实例上以大约700的存储大小,并且主要随着渲染器数量的增加而增长。这使攻击变得不可行,因为我们将不得不强制使用存储区索引和缓存行偏移量。但是,我注意到一个代码路径,该路径使你可以使用服务工作者创建大量特权URLLoaderFactories。如果你创建启用导航预加载的服务工作,则每个导航都将创建这样的loader。通过简单地创建多个iframe并在服务器端停止请求,你可以同时使数千个加载程序保持活动状态,并使暴力破解变得更加容易。
唯一缺少的是从L1缓存中寻找目标值。在实践中,简单地用32KB数据填充我们的消息似乎可以解决问题,因为我认为数据将被加载到受害者的L1缓存中。
总结完整的利用:
1. 破坏渲染器。
2. 在$ NUM_CPU-1进程中以不同的缓存行偏移量运行RIDL漏洞。
3. 安装具有导航预加载的服务。
4. 创建许多iframe并暂停其请求。
5. 使用随机端口名称将消息发送到网络进程。
6. 如果我们在存储索引上发生冲突,则2.中的过程可能会泄漏端口名称。
7. 将消息欺骗到URLLoaderFactory以将本地文件上传到https://evil.website。
0x04 TSX异步中止(TAA)
在2019年11月发布了MDS攻击的新变种,并且由于TAA PoC似乎比我的MFBDS攻击更快,因此我决定将其改编为Chrome攻击。此外,VUSec发布了一项针对存储操作的漏洞利用程序,如果我们可以将key写入到内存中的不同地址,则该漏洞应允许我们逃脱缓存刷新要求。如果我们可以触发浏览器将消息发送到特权端口,则应该发生这种情况。在这种情况下,secret端口名称也将以节点名称作为前缀,并且我们可以使用RIDL文件中的技术轻松对其进行过滤。
我还开始寻找一个更好的原语,发现如果可以与NetworkService进行通信,它将允许我创建一个新的NetworkContext,从而选择存储cookie的sqlite3数据库的文件路径。
为了找出如何触发从浏览器进程到NetworkService的消息,我查看了界面中的IPC方法,以找到一种看起来可以从渲染器影响它的方法。NetworkService.OnPeerToPeerConnectionsCountChange引起了我的注意,实际上,每次更新WebRTC连接时都会调用此方法。你只需要创建一个伪造的WebRTC连接,每次将其标记为已连接/断开连接时,都会触发一条新消息给NetworkService。
一旦从受破坏的渲染器中泄漏了端口名称,我们就获得了编写具有完全受控路径的sqlite3数据库的原语。
虽然起初听起来并不是很有用,但是你实际上可以滥用它来获得代码执行。我注意到Windows批处理文件是一种非常好的文件格式。如果文件的开头有gadget,它将跳过它直到下一个“ \ r \ n”并从那里执行下一个命令。在我的漏洞利用中,我使用它在用户的自动运行目录中创建一个cookies.bat文件,添加带有“ \ r \ n”的cookie和其中的命令,它将在下次登录时执行。
最终,此漏洞利用平均在我的机器上执行了1-2分钟,并且持续不到5分钟。而且我敢肯定,由于某些技术可以大大提高速度,因此可以大大改善这一点。例如,实际上MLPDS似乎比我使用的变体更快。
利用步骤:
1. 破坏渲染器。
2. 在$ NUM_CPU-1进程中以不同的缓存行偏移量运行RIDL漏洞。
3. 创建伪造的WebRTC连接,并在已连接和已断开连接之间切换。
4. 泄漏NetworkService端口名称。
5. 使用c:\ path \ to \ user \ autorun \ cookies.bat中的cookie文件创建一个新的NetworkContext
6. 插入cookie“ \ r \ ncalc.exe \ r \ n”。
7. 等待下一次登录。
0x05 分析总结
当我开始研究此问题时,我感到惊讶的是,即使漏洞已经公开了一段时间,它仍然可以被利用。如果你阅读有关该主题的指南,则他们通常会在你的操作系统为最新的情况下谈论如何缓解这些漏洞,并应注意你应禁用超线程以完全保护自己。专注于缓解措施无疑给我一种感觉,那就是漏洞已得到解决,我认为这些文章对于启用超线程的影响可能会更加清楚。
话虽如此,我希望你从这篇文章中思考两个问题。首先,信息泄漏漏洞不仅仅可以绕过ASLR。即使不是依靠key端口名,也可能会泄漏其他有趣的数据,例如Chrome的UnguessableTokens,Gmail cookie或计算机其他进程中的敏感数据。如果你对如何大规模查找信息泄漏有所了解,Chrome可能是一个不错的选择。
其次,由于硬件漏洞超出了我的研究范围,因此我长时间忽略了它们。但是,我希望我可以通过此文章为你提供有关其影响的另一个数据点,以帮助你做出是否应该禁用超线程的决定。对于可以用类似的方式破坏其他软件的方式,还有很多探索的余地,我很乐意看到更多应用硬件漏洞突破软件安全性边界的示例。