綁定帳號登入

Android 台灣中文網

打印 上一主題 下一主題

[轉載] 對最新Chrome沙箱逃逸漏洞利用的分析

[複製連結] 查看: 33825|回覆: 3|好評: 0
跳轉到指定樓層
樓主
wesley23 | 收聽TA | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
發表於 2020-5-7 17:02

馬上加入Android 台灣中文網,立即免費下載應用遊戲。

您需要 登錄 才可以下載或查看,沒有帳號?註冊

x
CVE-2020-0981:对最新Chrome沙箱逃逸漏洞利用的分析

导语:Windows上的Chromium沙箱经受了时间的考验。它被认为是大规模部署的最好的沙箱机制之一,不需要提升特权即可运行。


Windows上的Chromium沙箱经受了时间的考验。它被认为是大规模部署的最好的沙箱机制之一,不需要提升特权即可运行。尽管优点明显,但确实也存在一些缺点。沙箱的实现主要取决于Windows操作系统的安全性,更改Windows的行为不受Chromium开发团队的控制,如果在Windows的安全实施机制中发现漏洞,则沙箱就可能会被破坏。

这篇文章介绍了Windows 10 1903中引入的一个漏洞,此漏洞打破了Chromium可以使沙盒非常安全的假设。我将介绍如何使用该漏洞来开发执行链,以逃逸用于Chrome / Edge上的GPU进程或Firefox中默认内容的沙箱。利用进程也是对Windows中一些小缺陷的挖掘,这些小缺陷本身并没有越过安全边界,但却导致成功的沙箱逃逸。此漏洞于2020年4月修复为CVE-2020-0981

https://bugs.chromium.org/p/project-zero/issues/detail?id=2006 https://portal.msrc.microsoft.co ... isory/CVE-2020-0981

0x01 漏洞背景

在描述漏洞本身之前,快速看一下Chromium沙箱在Windows上是如何工作的,沙箱是指通过使用受限令牌来处理最小特权。

https://chromium.googlesource.co ... s/design/sandbox.md

受限令牌是Windows 2000中添加的一项功能,可通过以下操作来修改进程的访问令牌,从而减少授予进程的访问权限:

· 永久禁用群组。

· 删除特权。

· 添加受限制的SID。

禁用组将删除访问令牌的成员身份,从而导致无法访问由这些组保护的资源。删除特权可防止进程执行任何不必要的特权操作。最后,添加受限制的SID会更改安全访问检查进程,要被授予对资源的访问权限,我们需要匹配主列表以及“受限SID”列表中的组的安全描述符条目。如果SID列表之一未授予对资源的访问权限,则访问将被拒绝。

Chromium还使用Vista中添加的完整性级别(IL)功能来进一步限制资源访问。通过设置较低的IL,无论访问检查的结果如何,我们都可以阻止对更高完整性资源的写访问。

通过这种方式将受限令牌与IL结合使用,沙箱可以限制受威胁进程可以访问哪些资源,从而限制RCE可以产生的影响。阻止写访问尤为重要,因为通常这将使攻击者可以通过写文件或注册表项来破坏系统的其他部分。

Windows上的任何进程都可以使用其他令牌创建新进程,例如,通过调用CreateProcessAsUser。是什么阻止了沙盒流程使用不受限制的令牌创建新流程?Windows和Chromium实施了一些安全缓解措施,以使在沙箱外部创建新进程变得困难:

1. 内核限制了非特权用户可以向新进程分配的令牌。

2. 沙箱限制了用于新进程的合适访问令牌的可用性。

3. Chromium在Job对象内运行一个沙盒流程,该流程可被任何硬进程配额限制为1的子进程继承。

4. 在Windows 10中,Chromium使用子进程缓解策略来阻止子进程创建,除了来自3的Job对象之外,还应用了该对象。

所有这些缓解措施最终都依赖Windows来确保安全。但是,到目前为止,最关键的是1,即使2到4都失效了,从理论上讲,我们也不能为新进程分配更多特权的访问令牌。分配新令牌时内核要检查什么?

假设调用进程没有SeAssignPrimaryTokenPrivilege ,则新令牌必须满足两个标准之一,该条件已在内核函数SeIsTokenAssignableToProcess 中进行了检查,条件基于内核的TOKEN对象结构中的指定值,如下图所示:


                               
登錄/註冊後可看大圖

总之,令牌必须是:

1. 当前流程令牌的子级。基于新令牌的父令牌ID等于进程令牌的ID。

2. 当前进程令牌的同级。基于父令牌ID和身份验证ID字段相等。

还进行了其他检查,以确保新令牌不是标识级别的模拟令牌,并且新令牌的IL必须小于或等于当前进程令牌,这些同样重要,但正如我们看到的那样,在实践中用处不大。

令牌分配显然不会检查父令牌或子令牌是否受到限制。如果你位于受限令牌沙箱中,能否获得通过所有检查并将其分配给有效逃离沙箱的不受限制的子令牌?答案是不能的,系统会在分配受限令牌时确保同级令牌检查失败,而是确保将执行父/子检查。如果检查内核函数SepFilterToken ,将了解如何实现此函数。将现有属性从父令牌复制到新的受限令牌时,将执行以下代码。

NewToken- > ParentTokenId = OldToken- > TokenId;

通过设置新的受限令牌的父令牌ID,它可以确保只有创建受限令牌的进程才能将其用作子对象,因为令牌ID对于TOKEN对象的每个实例都是唯一的。同时,通过更改父代令牌ID,同级检查将被破坏。

但是,当我做一些测试以验证Windows 10 1909上的令牌分配行为时,我发现有些奇怪。无论我创建了什么受限令牌,我都无法使分配失败,再次查看SepFilterToken ,我发现代码已更改。

NewToken- > ParentTokenId = OldToken- > ParentTokenId;

现在,内核代码只是直接从旧令牌中复制父令牌ID。这完全打破了检查,因为新的沙盒进程具有一个令牌,该令牌被视为桌面上任何其他令牌的同级。

假设我可以绕过已有的其他三个子进程缓解措施,那么这一行更改可能足以突破“受限令牌”沙箱。

0x02 沙箱逃逸

我想出的最后一个沙箱逃逸程序非常复杂,也不一定是最佳方法。但是,Windows的复杂性意味着很难在我们的链中找到可供利用的替代原语。

首先尝试获取合适的访问令牌以分配给新进程。令牌需要满足一些条件:

1. 令牌是主令牌或可转换为主令牌。

2. 令牌的IL等于沙箱IL,或者可以写,因此可以降低IL级别。

3. 令牌符合兄弟令牌标准,因此可以进行分配。

4. 令牌用于当前的控制台会话。

5. 令牌未沙盒化或沙盒化程度小于当前令牌。

访问令牌是可保护的对象,因此,如果你具有足够的访问权限,则可以打开令牌的句柄。但是,访问令牌不是用名称来引用的,而是要打开令牌,你需要有权访问进程或模拟线程。可以使用Get-AccessibleToken 命令使用NtObjectManager PowerShell模块查找可访问令牌。

PS> $ps = Get-NtProcess -Name "chrome.exe" `                   -FilterScript { $_.IsSandboxToken } `                   -IgnoreDeadProcess PS> $ts = Get-AccessibleToken -Processes $ps -CurrentSession `                               -AccessRights Duplicate PS> $ts.Count 101

该脚本获取了我计算机上运行的每个沙盒Chrome进程的句柄(显然首先启动了Chrome),然后使用每个进程中的访问令牌来确定可以为TOKEN_DUPLICATE 访问打开哪些其他令牌。检查TOKEN_DUPLICATE 在新进程中用作令牌的原因是,由于两个进程不能使用同一访问令牌对象,因此需要复制令牌。访问检查考虑了调用进程是否对目标进程具有PROCESS_QUERY_LIMITED_INFORMATION 访问权限,这是打开令牌的先决条件。

一开始,我们可以访问的某些令牌在沙盒中的数量要比当前令牌在沙盒中的数量更多,我们只需要未沙盒化的可访问令牌。其次,尽管有许多可访问的令牌,但这很可能是少数进程能够访问大量令牌的产物。我们将其过滤为仅可以访问非沙盒标记的Chrome进程的命令行。

PS> $ts | ? Sandbox -ne $true | `     Sort {$_.TokenInfo.ProcessCommandLine} -Unique | `     Select {$_.TokenInfo.ProcessId},{$_.TokenInfo.ProcessCommandLine}  ProcessId ProcessCommandLine --------- ----------------------------------      6840 chrome.exe --type=gpu-process ...     13920 chrome.exe --type=utility --service-sandbox-type=audio ...

在所有可能的Chrome进程中,只有GPU进程和Audio Utility进程有权访问非沙盒令牌,这不应该让人感到意外,渲染器进程比GPU或“音频”沙箱具有更多的锁定功能,这是由于调用系统服务以使这些进程正常运行的限制。由于大多数RCE发生在HTML / JS内容中,因此大大降低了RCE发生沙箱逃逸的可能性。也就是说确实存在GPU漏洞,例如Lokihardt在Pwn2Own 2016上使用的一个漏洞

https://bugs.chromium.org/p/chromium/issues/detail?id=595834

让我们集中讨论逃逸GPU进程沙箱。因为我没有GPU RCE,所以我将DLL注入到进程中以运行逃逸代码。这并不像听起来那么简单,一旦GPU进程启动,该进程就被锁定为仅加载Microsoft签名的DLL。我使用KnownDlls 的技巧将DLL加载到内存中。

https://www.tiraniddo.dev/2019/0 ... -bypassing-cig.html

为了逃逸沙箱,我们需要执行以下操作:

1. 打开一个不受限制的令牌。

2. 复制令牌以创建新的主令牌并使令牌可写。

3. 删除令牌的IL以匹配当前令牌(对于GPU,这是低IL)

4. 使用新令牌调用CreateProcessAsUser 。

5. 逃逸低IL沙箱。

即使是执行第1步,我们也存在问题。获取无限制令牌的最简单方法是为父进程(即主要的Chrome浏览器进程)打开令牌。但是,如果你查看令牌列表,则GPU进程可以访问,你会发现不包括Chrome主浏览器进程。这是为什么?这是故意的,因为我在报告了内核中的此漏洞后才意识到,GPU进程沙箱可以打开浏览器进程的令牌。使用此令牌,可以创建一个新的受限令牌,该令牌将通过同级检查以创建具有更多访问权限并逃逸沙箱的新进程。为了减轻这种情况,我修改了对进程令牌的访问权限,以阻止较低IL的进程为TOKEN_DUPLICATE 访问打开令牌。看到HardenTokenIntegerityLevelPolicy。在此修复程序之前,你不需要内核中的任何漏洞即可逃逸Chrome GPU沙箱,至少不需要普通的Low IL令牌即可。

因此,我们无法使用简单的方法,但是我们应该能够简单地枚举进程并找到符合我们标准的进程。我们可以通过使用NtGetNextProcess 系统调用来做到这一点,正如我在上一篇博客文章中所描述的。我们打开所有进程以进行PROCESS_QUERY_LIMITED_INFORMATION 访问,然后打开令牌以进行TOKEN_DUPLICATE 和TOKEN_QUERY 访问。然后,我们可以在继续执行步骤2之前检查令牌以确保其不受限制。

https://googleprojectzero.blogsp ... n-console-able.html

要复制令牌,我们调用DuplicateTokenEx并请求传递TOKEN_ALL_ACCESS 作为所需访问的主令牌。但是有一个新问题,当我们尝试降低IL时,会从SetTokenInformation获得ERROR_ACCESS_DENIED 。这是由于Microsoft添加到Windows 10并向后移植到所有支持的操作系统(包括Windows 7)的沙箱缓解措施。以下代码是NtDuplicateToken的摘要,其中已引入缓解措施。

ObReferenceObjectByHandle(TokenHandle, TOKEN_DUPLICATE,      SeTokenObjectType, &Token, &Info); DWORD RealDesiredAccess = 0; if (DesiredAccess) {     SeCaptureSubjectContext(&Subject);     if (RtlIsSandboxedToken(Subject.PrimaryToken)       && RtlIsSandboxedToken(Subject.ClientToken)) {         BOOLEAN IsRestricted;         SepNewTokenAsRestrictedAsProcessToken(Token,             Subject.PrimaryToken, &IsRestricted);         if (Token == Subject.PrimaryToken || IsRestricted)             RealDesiredAccess = DesiredAccess;         else             RealDesiredAccess = DesiredAccess                  & (Info.GrantedAccess | TOKEN_READ | TOKEN_EXECUTE);     } } else {     RealDesiredAccess = Info.GrantedAccess; }  SepDuplicateToken(Token, &DuplicatedToken, ...) ObInsertObject(DuplicatedToken, RealDesiredAccess, &Handle);

当复制令牌时,内核会检查调用方是否沙箱保护。如果将其沙箱保护,则内核将检查要复制的令牌的限制是否小于调用者。如果限制较少,则代码会将所需的访问限制为TOKEN_READ 和TOKEN_EXECUTE 。这意味着,如果我们请求诸如TOKEN_ADJUST_DEFAULT 之类的写访问权限,它将被从复制调用返回给我们的句柄上删除。反过来,这将阻止我们减少IL,以便可以将其分配给新流程。

这似乎使我们的漏洞利用链无法继续写下去了。如果我们无法写入令牌,则无法降低令牌的IL,这会阻止我们对其进行分配。但是该实现有一个小缺陷,重复操作将继续完成,并仅返回具有有限访问权限的句柄。当你创建新的令牌对象时,默认安全性将授予调用者对令牌对象的完全访问权限。这意味着一旦你获得了新令牌的句柄,就可以调用普通的DuplicateHandle API将其转换为完全可写的句柄。尚不清楚这是否是有意的,尽管应注意,CreateRestrictedToken 中的类似检查如果新令牌不受限制,则返回错误。无论如何,我们都可以滥用此功能来获得可写的不受限制的令牌,以将其分配给具有正确IL的新进程。

现在我们可以获得一个不受限制的令牌,可以调用CreateProcessAsUser 来创建我们的新进程。但是速度并不快,因为GPU进程仍在限制性Job对象中运行,这阻止了创建新进程。我将近5年前的“ In-Console-Able ”文章中详细介绍了Job对象如何阻止新流程的创建。

https://googleprojectzero.blogsp ... n-console-able.html

我们不能在控制台驱动程序中使用相同的漏洞来逃逸Job对象吗?在Windows 8.1上,你可能可以,但是在Windows 10上,有两点使我们无法使用它:

1. Microsoft更改了Job对象以支持辅助进程计数器。如果你拥有SeTcbPrivilege ,则可以将flag传递给NtCreateUserProcess 来创建仍在Job内的新进程,该进程不计入进程数。控制台驱动程序使用它来删除逃逸作业的要求。由于我们在沙箱中没有SeTcbPrivilege ,因此无法使用此功能。

2. Microsoft向令牌添加了一个新flag,以防止将其用于新进程。Chrome会在所有沙盒进程中设置此flag,以限制新的子进程。即使没有“ 1”,该flag也会阻止滥用控制台驱动程序以生成新进程。

这两个功能块的组合通过滥用控制台驱动程序在当前作业之外产生了一个新进程。我们需要想出一种既可以避免Job对象限制,又可以绕过子进程限制flag的方法。

Job对象是从父对象继承到子对象的,因此,如果我们可以在Job对象之外找到GPU进程可以控制的进程,则可以将该进程用作新的父对象并逃逸Job。不幸的是,至少在默认情况下,如果你检查GPU进程可以访问哪些进程,则它只能自行打开。

PS> Get-AccessibleProcess -ProcessIds 6804 -AccessRights GenericAll `              | Select-Object ProcessId, Name ProcessId Name --------- ----      6804 chrome.exe

打开本身并不会很有用,而且我们不能依靠偶发的进程来运行它,而该进程恰好在运行时同时可以访问并且没有运行Job。

我注意到的一件事是,在设置新的Chrome沙箱进程的进程中,竞争很小。首先创建流程,然后应用Job对象。如果可以让Chrome浏览器生成新的GPU进程,则可以在应用Job对象之前将其用作父进程。GPU进程的处理甚至支持崩溃时重新生成该进程。但是,我找不到在不导致当前GPU进程终止的情况下启动新GPU进程的方法,因此不可能使代码运行足够长的时间来利用这种竞争。

相反,我决定专注于寻找一个RPC服务,该服务将在Job之外创建一个新进程。有很多RPC服务将流程创建作为主要目标,而其他服务则将流程创建作为副作用。例如,我已经在以前的博客文章中记录了Secondary Logon服务,其中RPC服务的全部目的是产生新进程。

https://googleprojectzero.blogsp ... -thread-handle.html

但是,此想法有一个小缺陷,特别是令牌中的子进程缓解flag是跨模拟边界继承的。由于通常使用模拟令牌作为新进程的基础,因此任何新进程都会被阻止。但是,我们有一个未设置flag的无限制令牌,可以使用非限制令牌创建一个可以在RPC调用期间模拟的限制令牌,并且可以绕过子进程缓解flag。

我列出可以通过这种方式使用的已知服务,这些服务汇总在下表中:


                               
登錄/註冊後可看大圖

该表并不详尽,可能还会有其他RPC服务允许创建进程。正如我们在表中看到的那样,无法从沙盒级别访问生成了辅助登录,WMI和BITS之类的进程的众所周知的RPC服务。UAC服务是可访问的,存在一种通过滥用调试对象来滥用服务以运行任意特权代码的方法。不幸的是,当创建一个新的UAC进程时,该服务会将父进程设置为调用方进程。继承Job对象后,新进程将被阻止。


本文翻译自:https://googleprojectzero.blogsp ... -this-one-line.html如若转载,请注明原文地址:


「用Android 就來APK.TW」,快來加入粉絲吧!
Android 台灣中文網(APK.TW)
收藏收藏1 分享分享 分享專題
用Android 就來Android 台灣中文網(https://apk.tw)
回覆

使用道具 舉報

沙發
bluekai | 收聽TA | 只看該作者
發表於 2021-1-5 14:18
剛好在找類似的文章,感謝分享
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

板凳
ice963 | 收聽TA | 只看該作者
發表於 2021-6-22 22:34
慢慢再來研究,謝謝版主的分享
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

地板
qa180 | 收聽TA | 只看該作者
發表於 2021-8-15 14:55
這個有教學
可以看一下
多冊
這個 東西??????
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則