Firefox 沙盒逃逸 (CVE-2020-12388)

  • A+
所属分类:安全文章
Firefox 沙盒逃逸 (CVE-2020-12388)
 
Firefox 沙盒逃逸 (CVE-2020-12388)

前言

在这篇博客文章中,讨论了Windows内核对受限令牌的处理问题,该问题使我能够逃逸Chrome GPU沙箱。最初,我计划使用Firefox来演示POC,因为Firefox的内容渲染器使用与Chrome GPU进程相同的沙箱级别。这意味着Firefox内容RCE可以在沙箱中执行代码,在沙箱中您可能会滥用Windows内核限制令牌问题,从而使问题更加严重。
但是,在研究沙盒逃逸时,我意识到Firefox也可能会有逃逸漏洞。即使Windows问题已修复,GPU级别沙箱在多个进程中的使用也引入了沙箱逃逸。这篇博客文章介绍了Chromium沙箱的具体行为以及Firefox为何易受攻击。我还将详细介绍我对Chromium沙箱所做的更改,以介绍一种缓解问题的方法,该方法已被Mozilla用来修复漏洞。
作为参考,P0的问题报告为2016,Firefox的问题报告为1618911。Firefox定义了自己的沙箱配置文件。撰写这篇文章时,content sandbox(内容沙箱)被定义为level 5,因此我将继续介绍L5,而不是GPU沙箱。
 
Firefox 沙盒逃逸 (CVE-2020-12388)

根本原原因
问题的根本原因在于,使用L5,一个内容进程可以打开另一个内容进程进行完全访问。在Chromium的浏览器中,这通常不是问题,一次只能运行一个GPU进程,尽管可能同时运行着其他非Chromium进程,这些非Chromium进程也访问着GPU。Chromium中的内容渲染进程使用的沙箱受到的限制明显更大,它们不能打开任何其他进程。
L5沙箱使用受限令牌作为主要沙箱防御措施。一个内容进程可以访问另一个内容进程的原因取决于该进程的主令牌的默认DACL。对于内容进程,默认的DACL使用RestrictedToken :: GetRestrictedToken设置,以下用户将被授予完全访问权限:
User Access
Current User
Full Access
NT AUTHORITYSYSTEM
Full Access
NT AUTHORITYRESTRICTED
Full Access
Logon SID
Read and Execute Access
默认DACL用于设置初始进程和线程安全描述符。L5使用的令牌级别为USER_LIMITED,所有的组几乎都被禁用,但以下情况除外:
Current UserBUILTINUsersEveryoneNT AUTHORITYINTERACTIVELogon SID
并添加以下受限制的SID:
BUILTINUsersEveryoneNT AUTHORITYRESTRICTEDLogon SID
将当前用户组和RESTRICTED受限SID结合在一起,就可以授予对沙箱进程或线程的完全访问权限。
要了解为什么能够打开另一个内容进程是一个问题,我们必须了解Chromium沙箱如何启动一个新进程。由于将主令牌分配给新进程的方式,一旦进程启动,就无法再更改为其他令牌。在这里可以做一些事情,例如删除特权和降低完整性级别,但是无法删除组或添加新的受限SID。
一个新的沙盒进程需要进行一些初始化,这需要比受限沙盒需要更多的访问权限,因此Chromium使用了一个技巧。它为初始线程分配了一个更高特权的模拟令牌,以便初始化以更高的特权运行。对于L5,初始令牌的级别为USER_RESTRICTED_SAME_ACCESS,它仅创建不是禁用组且所有普通组都添加了受限的SIDs。这使得令牌几乎等同于普通令牌,但是被认为是受限的。如果“主令牌”受到限制,但“模拟令牌”没有受到限制,则Windows将阻止设置令牌。
一旦完成所有初始化,就可以通过调用沙箱目标服务中的LowerToken函数来删除模拟令牌。这意味着有一个时间窗口,从新的沙盒进程开始到调用LowerToken时,该进程实际上在没有沙盒的情况下运行,除了具有低IL之外。如果您可以在删除模拟令牌之前劫持执行程序,则可以获得足够的特权,进行沙箱逃逸。
Firefox 沙盒逃逸 (CVE-2020-12388)
与Chrome GPU处理不同,Firefox在正常使用期间会创建新的内容进程。仅仅创建一个新的标签就可以产生一个新的进程。因此,当在创建新进程的时候进行劫持,即可成功控制进程。另外,受到控制的渲染进程会通过IPC调用创建新进程。
有了这些知识,我使用了许多与以前的博客文章相同的技术来开发了完整的POC。USER_RESTRICTED_SAME_ACCESS令牌的更高特权简化了漏洞利用。例如,我们不再需要劫持COM Server的线程,因为特权更高的令牌使我们可以直接打开进程。另外,至关重要的是,我们永远不需要离开“受限沙箱”,因此该漏洞利用程序不必依赖于先前MS所修复的内核错误版本。您可以找到问题附带的完整POC,并且我在下图中总结了步骤。
Firefox 沙盒逃逸 (CVE-2020-12388)
 
Firefox 沙盒逃逸 (CVE-2020-12388)

开发补丁程序

在我的报告中,我建议了针对此问题的补丁程序,请在沙箱策略中启用SetLockdownDefaultDacl选项。SetLockdownDefaultDacl从默认DACL中同时删除了RESTRICTED和登录SID,这将阻止一个L5进程打开另一个进程。我已经添加了此沙箱策略功能,以响应我在上一个博客中提到的GPU沙箱逃逸,这是Pwn2Own的lokihardt使用的。但是,其目的是阻止GPU进程打开渲染器进程,而不是阻止一个GPU进程打开另一个GPU进程。因此,该策略未在GPU沙箱上设置,而仅在渲染器上设置。
事实证明,我不是第一个报告一个Firefox内容处理程序打开另一个进程的人。 Niklas Baumstark在我报告前一年就已经报告过。我建议的修复SetLockdownDefaultDacl的功能已在修复Niklas的问题报告中进行了尝试,它破坏了包括DirectWrite缓存和音频播放在内的各种功能,会导致显著的性能下降,这会导致使用SetLockdownDefaultDacl成为不可取的事情。上述提到的,诸如DirectWrite高速缓存中断的原因是由于Windows RPC服务中的编码模式导致的,如下所示:
int RpcCall(handle_t handle, LPCWSTR some_value) {  DWORD pid;  I_RpcBindingInqLocalClientPID(handle, &pid);
RpcImpersonateClient(handle); HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, nullptr, pid); if (!process) return ERROR_ACCESS_DENIED;
...}
此示例代码在特权服务中运行,并且由沙盒应用程序通过RPC调用。它首先调用RPC运行时以查询调用者的进程ID。然后,它模拟了调用者并尝试打开调用过程的句柄。如果打开过程失败,则RPC调用将返回拒绝访问错误。
对于正常的应用程序,一个完全合理的假设是调用者可以访问自己的进程。但是,一旦锁定了进程安全级别,情况就不再如此。如果我们要禁止访问同一级别的其他进程,那么结果就是我们也禁止打开自己的进程。通常,这不会导致什么问题,因为流程中的大多数代码都使用“当前进程的”伪句柄,该句柄从未进行访问检查。
Niklas的报告并未包含完整的沙箱逃逸功能。缺少完整的POC加上修复它的困难导致修复停滞。但是,如果使用完整的沙箱逃逸来演示问题的影响,则Mozilla必须在性能或安全性之间进行选择,除非可以采用其他补丁程序。
该补丁程序必须做两件事:
授予进程对其自己的进程和线程的访问权限。拒绝同一级别的任何其他进程。
没有任何管理员权限,我们无法使用许多东西,例如内核进程回调。该补丁程序必须在普通用户权限的用户模式下运行。
修复漏洞的关键,在于受限制的SIDs列表要包括的SIDs是不在令牌中。我们可以为每个沙盒生成一个随机的SID进程,将其作为受限SID并添加到默认DACL中。然后,我们可以使用SetLockdownDefaultDacl锁定默认DACL。
当打开进程时,访问检查将与当前用户的SID相匹配,以进行常规检查,而随机SID与受限SID检查相匹配。但是,每个内容进程将具有不同的随机SID,因此尽管正常检查仍将通过,但访问检查无法成功通过受限SID的检查。这达成了我们的目标。您可以在PolicyBase :: MakeTokens中查看实现方式。
我将补丁添加到Chromium代码仓库中,Firefox能够对其进行合并和测试。它起到了阻止攻击的作用,并且似乎没有引入以前的性能问题。
该修补程序的另一个问题是确保系统上所有其他进程的安全,这些进程必须采用缓解措施来进行防御,包括所有Chromium浏览器以及Chromium的用户(例如Electron)。例如,如果未更新Chrome,则Firefox内容进程可能会关闭Chrome的GPU进程,这将导致Chrome重新启动它,而firefox进程可能会通过劫持新的GPU进程而通过Chrome逃逸。这就是为什么即使不是直接受到攻击,我还是启用了Chromium GPU进程的缓解措施,该进程已在2020年4月底发布的M83(和Microsoft Edge 83)中提供。
最后,此博客文章演示了Firefox中的沙箱逃逸,同时也需要向Chromium沙箱添加新的防护功能。与以前的博客文章相比,无需更改Windows代码。

Firefox 沙盒逃逸 (CVE-2020-12388)


戳“阅读原文”查看更多内容

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: