一行代碼能產生多大影響:Chrome沙箱逃逸漏洞分析


一行代碼能產生多大影響:Chrome沙箱逃逸漏洞分析

概述

Windows環境上的Chromium沙箱已經經受了時間的考驗,目前,人們普遍認為這是在大規模部署的沙箱機制中最好的一個,不需要特權提升即可運行。然而,優點和缺點往往都是相對的。沙箱的實現主要取決於Windows操作系統的安全性,而對Windows的更改行為不會受到Chromium開發團隊的控制。如果我們在Windows的安全實施機制中發現錯誤,那麼就有可能攻破沙箱。

本文主要分析了Windows 10 1903版本中引入的一個漏洞,該漏洞打破了CHromium用來保證沙箱安全的某些安全假設。我們將詳細分析如何利用該漏洞來開發利用鏈,以在Chrome/Edge的GPU進程或Firefox的默認內容沙箱中實現沙箱逃逸。我們的漏洞利用過程,實際上是對Windows上一些小缺陷的仔細觀察,這些小缺陷本身並沒有越過安全邊界,但卻導致成功的沙箱逃逸。該漏洞在2020年4月修復,編號為CVE-2020-0981。

漏洞背景

在描述漏洞本身之前,我們首先快速瀏覽一下Chromium沙箱在Windows上的工作方式。藉助受限令牌(Restricted Token),沙箱可以按照最小特權的概念來工作。受限令牌是在Windows 2000中添加的一項功能,可以通過以下操作來修改進程的訪問令牌,從而減少授予該進程的訪問權限:

1、永久禁用組;

2、刪除特權;

3、添加受限制的SID。

禁用組將會刪除訪問令牌的成員,從而導致無法訪問由這些組進行保護的資源。刪除特權可以防止進程執行任何不必要的特權操作。最後,添加受限制的SID會更改安全訪問檢查過程。如果要被授予對資源的訪問權限,我們需要匹配主列表以及“受限SID”列表中的組的安全描述符條目。如果SID列表中的成員沒有被授予對資源的訪問權限,那麼訪問就會被拒絕。

Chromium還使用從Vista開始添加的完整性級別(IL)功能來進一步限制資源訪問。通過設置較低的IL,無論訪問檢查的結果如何,都可以阻止對更高完整性資源的寫入訪問。

通過這種方式,將受限令牌與IL結合使用,沙箱可以限制受威脅進程能夠訪問哪些資源,從而限制遠程代碼執行可能造成的潛在影響。阻止寫訪問尤為重要,因為這通常會使攻擊者可以通過寫文件或註冊表項,來破壞系統的其他部分。

Windows上的任何進程都可以使用其他令牌創建新進程,例如:通過調用CreateProcessAsUser。那麼,是什麼阻止了沙箱進程使用不受限制的令牌創建新進程呢?Windows和Chromium實施了一些安全緩解措施,以使得在沙箱外部創建新進程變得困難:1、內核限制了非特權用戶可以向新進程分配的令牌;

2、沙箱限制限制了用於新進程的適用訪問令牌的可用性;

3、Chromium在Job對象內運行一個沙箱進程,該進程可以被任何硬進程配額限制為1的子進程繼承。

4、在Windows 10中,Chromium使用子進程緩解策略來阻止子進程創建。除了來自3的Job對象之外,還應用了該對象。

所有這些緩解措施最終都依賴於Windows來確保安全。但是,到目前為止,最關鍵的還在於1。即使2、3、4都失敗了,從理論上來看,我們也不能為新的進程分配更多特權的訪問令牌。那麼,在分配新令牌時,內核需要檢查哪些內容呢?

我們假設調用過程中沒有SeAssignPrimaryTokenPrivilege(我們實際的測試中也沒有),那麼新的令牌必須滿足兩個條件之一,這兩個條件已經在內核函數SeIsTokenAssignableToProcess中進行了檢查。檢查的條件基於內核TOKEN對象結構中的指定值,如下所示:

一行代碼能產生多大影響:Chrome沙箱逃逸漏洞分析

總而言之,令牌必須滿足以下條件:

1、當前進程令牌的子級。要求新令牌的父令牌ID等於進程令牌的ID。

2、當前進程令牌的同級。要求父令牌ID和身份驗證ID相同。

此外,還進行了其他檢查,以確保新令牌不是身份驗證級別的模擬令牌,並且新令牌的IL必須小於或等於當前進程令牌。這些同樣重要,但正如我們即將看到的,在實際中用處不大。

令牌分配的過程中,不會檢查父令牌或子令牌是否受到限制。如果位於受限令牌沙箱中,我們能否通過所有檢查,並將其分配給可以逃逸的沙箱的子級不受限制的令牌呢?顯然是不能的,系統會在分配受限令牌時進行“同級令牌”檢查,而這些環節將無法通過,這時父級/子級檢查將強制執行。如果我們查看內核函數SepFilterToken,我們將會了解其具體的實現方式。將現有屬性從父令牌複製到新的受限令牌時,將會執行以下代碼:

<code>NewToken->ParentTokenId = OldToken->TokenId;
/<code>

通過設置新的受限令牌的父令牌ID,可以確保只有創建受限令牌的進程才能將其用於子級,因為令牌ID對於TOKEN對象的每個實例都是唯一的。同時,通過修改父令牌ID,將會破壞同級檢查。

但是,當我在Windows 10 1909環境上進行測試以驗證令牌分配行為時,我發現有些奇怪,因為無論我創建了什麼令牌,都無法導致分配失敗。再次查看SepFilterToken,我發現代碼已經更改。

<code>NewToken->ParentTokenId = OldToken->ParentTokenId;
/<code>

現在,內核代碼只會從舊令牌中複製父令牌ID。這完全打破了原有的檢查,因為新的沙箱進程具有一個令牌,而這個令牌被視為桌面上任何其他令牌的同級。

假設我可以繞過其他三個已有的子進程緩解措施,那麼這一行更改就足以讓我們突破“受限令牌”沙箱。為此,我們還要進行一系列的嘗試。

沙箱逃逸

最終,我想到的沙箱逃逸方式非常複雜,不一定是最佳方案。但是,由於Windows的複雜性,我們很難在漏洞利用鏈中找到可以利用的替代原語。

首先,我們嘗試獲取合適的訪問令牌,並將其分配給新的進程。令牌需要滿足以下條件:

1、令牌是主令牌,或者可以轉換為主令牌;

2、令牌的IL等於沙箱的IL,或者允許寫入,從而可以降低IL級別;

3、令牌符合同級令牌的標準,可以進行分配;

4、令牌用於當前的控制檯會話;

5、令牌未沙箱化,或者比當前令牌沙箱化的程序要小。

訪問令牌是可保護的對象,因此,如果我們具有足夠的訪問權限,就可以打開令牌的句柄。但是,訪問令牌不是用名稱來引用的,而是需要打開令牌,這就意味著需要我們有權訪問進程或模擬線程。我們可以使用Get-AccessibleToken命令使用PowerShell的NtObjectManager模塊查找可訪問的令牌。

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

這個腳本獲取了計算機上運行的每個沙箱Chrome進程的句柄,然後使用每個進程中的訪問令牌來確定我們可以為TOKEN_DUPLICATE訪問打開哪些其他的令牌。之所以要檢查TOKEN_DUPLICATE在新進程中使用的令牌的原因是,由於兩個進程不能使用同一訪問令牌對象,因此我們需要對令牌進行復制。訪問檢查需要判斷調用進程是否對目標進程具有PROCESS_QUERY_LIMITED_INFORMATION訪問權限,這是打開令牌的先決條件。我們得到了很多結果,大概超過100個條目。

但是,這個數字是有迷惑性的。一開始,幾乎可以確定,我們可以訪問的某些令牌在沙箱中的數量要比當前令牌在沙箱中的數量更多。確實,我們只需要未沙箱化的可訪問令牌。其次,儘管有許多可訪問的令牌,但這很可能是代表著只有少數進程能夠訪問大量的令牌。為此,我們需要將其過濾為僅可以訪問非沙箱標記的Chrome進程的命令行。

<code>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 ...
/<code>

在所有可能的Chrome進程中,只有GPU進程和Audio utility進程有權訪問非沙箱令牌。這並不意外。渲染器進程比GPU或Audio沙箱具有更多的鎖定功能,這是由於調用系統服務以使這些進程正常運行的限制。這確實意味著,由於大多數遠程代碼執行發生在呈現的HTML或JS內容中,因此大大降低了遠程代碼執行出現沙箱逃逸的可能性。也就是說,確實存在GPU漏洞,例如Lokihardt曾在Pwn2Own 2016上使用過的一個漏洞。

接下來,讓我們集中討論逃逸GPU進程沙箱。由於我現在沒有GPU遠程代碼執行,因此我將DLL注入到進程中以實現逃逸。這並不像聽起來那麼簡單,一旦GPU進程啟動,該進程就被鎖定為僅加載Microsoft簽名的DLL。我使用了KnownDlls的技巧將DLL加載到內存中。

為了實現沙箱逃逸,我們需要執行以下操作:

1、打開一個不受限制的令牌;

2、複製令牌,以創建新的主令牌,並使令牌可寫;

3、刪除令牌的IL,以匹配當前令牌(對於GPU來說,這是低IL);

4、使用新令牌調用CreateProcessAsUser;

5、逃逸低IL沙箱。

即使是第一步,我們也存在問題。獲取不受限制令牌的最簡單方法是為父進程(即主要的Chrome瀏覽器進程)打開令牌。但是,如果查看令牌列表,我們發現GPU進程可以訪問,但其中不包括Chrome主瀏覽器進程。原因在於,GPU進程沙箱可以打開瀏覽器進程的令牌。使用這個令牌,可以創建一個新的受限令牌,該令牌將通過同級檢查,以創建具有更多訪問權限的新進程,並逃逸沙箱。為了緩解這種情況,我修改了對進程令牌的訪問權限,以阻止較低IL的進程為TOKEN_DUPLICATE訪問打開令牌。大家可以關注HardenTokenIntegerityLevelPolicy。在進行這一修復之前,我們不需要內核中的漏洞,即可逃逸Chrome GPU沙箱,至少不需要正常的低級別IL令牌。

因此,我們無法使用簡單的方法,但我們應該可以簡單地枚舉進程,並找到符合標準的一個進程。我們可以通過使用NtGetNextProcess系統調用來實現這一點,正如我在上一篇文章中所描述的一樣。我們打開所有進程,以進行PROCESS_QUERY_LIMITED_INFORMATION訪問,然後打開令牌,進行TOKEN_DUPLICATE和TOKEN_QUERY訪問。然後,我們可以檢查令牌,以確保其不受限制,然後再繼續執行第二步。

要複製令牌,我們可以調用DuplicateTokenEx並請求傳遞TOKEN_ALL_ACCESS作為所需訪問的主令牌。但是,有一個新問題,當我們嘗試降低IL時,會從SetTokenInformation中得到ERROR_ACCESS_DENIED。這是由於Microsoft在WIndows 10中添加了沙箱緩解措施,並向後移植到了所有受支持的操作系統,包括Windows 7。下面的代碼是NtDuplicateToken的摘要,其中已經引入了緩解措施:

<code>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);
/<code>

當我們複製令牌時,內核會檢查調用方是否已經沙箱化。如果將其沙箱化,則內核將檢查要複製的令牌的限制是否小於調用方。如果限制較少,則代碼會將所需的訪問權限限制為TOKEN_READ和TOKEN_EXECUTE。這意味著,如果我們請求類似於TOKEN_ADJUST_DEFAULT這樣的寫訪問權限,它將被從賦值調用返回給我們的句柄刪除。反過來,這會阻止我們減少IL,以便可以將其分配給新進程。

這似乎導致我們的漏洞利用鏈徹底終結。如果我們無法寫入令牌,就無法降低令牌的IL,從而無法對其進行分配。但是,這個實現有一個小缺陷,重複操作將會繼續完成,並僅返回具有受限訪問權限的句柄。當我們創建新的令牌對象時,默認安全性將授予調用方對令牌對象的完全訪問權限。這意味著,一旦我們獲得了新令牌的句柄,就可以調用普通的DuplicateHandleAPI將其轉換為完全可寫的句柄。目前我們還不清楚這是不是有意的,但應該注意的是,如果新令牌的限制沒那麼嚴格,那麼CreateRestrictedToken中的類似檢查會返回錯誤。無論如何,我們都可以濫用這個功能,以獲得可寫的、不受限制的令牌,以將其分配給具有正確IL的新進程。

現在,我們可以獲得一個不受限制的令牌,可以調用CreateProcessAsUser來創建我們的新進程。但它的速度並不快,因為GPU進程仍然在受限Job對象中運行,這會阻止創建新進程。在將近5年前的一篇名為“In-Console-Able”的文章中,我詳細介紹了Job對象如何阻止新進程的創建。我們不能在控制檯驅動程序中使用相同的漏洞來逃逸Job對象嗎?在Windows 8.1上,我們似乎可以,但是在Windows 10上,有兩件事阻止我們對其的利用:

1、Microsoft更改了Job對象以支持輔助進程計數器。如果我們擁有SeTcbPrivilege,我們可以將一個標誌傳遞給NtCreateUserProcess,以在Job內部創建一個新進程,該進程不計入進程總數。控制檯驅動程序使用它來清除了逃逸Job的前置條件。由於我們在沙箱中沒有SeTcbPrivilege,因此無法使用這個功能。

2、Microsoft為令牌添加了一個新的標誌,以防止將其用於新的進程。Chrome會在所有沙箱進程中設置這個標誌,以限制新的子進程。即使沒有1,該標誌也將阻止濫用控制檯驅動程序以產生新的進程。

通過將這兩個功能塊進行組合,我們藉助濫用控制檯驅動程序的方式,在當前Job之外產生了一個新的進程。我們需要想出一種方式,既可以避免Job對象限制,也可以繞過子進程限制的標誌。

Job對象是從父對象繼承到子對象的,因此,如果我們可以在Job對象之外找到GPU進程可以控制的基礎訥航,則可以將該進程用作新的父對象並逃逸Job。遺憾的是,在默認情況下,如果我們檢查GPU進程可以訪問哪些進程,會發現它只能自行打開。

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

打開其自身可能不會很有幫助,但我們不能依靠運氣來實現漏洞利用,我們需要嘗試別的方式。

我注意到一件事,在一個很小的競爭條件下,設置一個新的Chrome沙箱程序。首先創建進程,然後應用Job對象。如果我們可以讓Chrome瀏覽器生成新的GPU進程,就可以在應用Job對象之前將其用作父進程。GPU進程的處理甚至支持崩潰時重新生成該進程。但是,我們找不到在不導致當前GPU進程終止的情況下,啟動新GPU進程的方法,因此無法運行足夠長的代碼來利用競爭條件。

相反,我決定專注於尋找一個RPC服務,該服務將在Job之外創建一個新進程。有很多RPC服務將進程創建作為主要目標,而其他服務則將進程創建作為一個附加功能。例如,我們以前說過Secondary Logon服務,其中RPC服務的全部目的是產生新進程。但是,這個想法有一個小缺陷,令牌中的子進程緩解標誌是跨模擬邊界繼承的。由於通常使用模擬令牌作為新進程的基礎,因此任何新的進程都將被阻止。但是,我們有一個未設置標誌的非受限令牌,可以使用非受限令牌創建一個可以在RPC調用期間模擬的受限令牌,並且可以繞過子進程緩解標誌。

我嘗試列出可以通過這種方式利用的已知服務,如下所示:

Secondary Logon Service 不可訪問 不可逃逸Job

WMI Win32_Process 不可訪問 可以逃逸Job

用戶帳戶控制(UAC) 可訪問 不可逃逸Job

後臺智能傳輸服務(BITS) 不可訪問 可以逃逸Job

DCOM Activator 可訪問 可以逃逸Job

上表並不全面,可能還會有其他RPC服務允許創建進程。但是,正如我們在上面所看到的那樣,我們無法從沙箱級別訪問這些派生出Secondary Logon、WMI、BITS的已知RPC服務。UAC服務是可以訪問的,存在一種通過濫用調試對象來濫用服務,以運行任意特權代碼的方法。但遺憾的是,當創建一個新的UAC進程時,該服務會將父進程設置為調用方進程。繼承Job對象後,新進程將會被阻止。

列表中的最後一個服務是DCOM Activator,該系統服務負責啟動進程外COM服務器,可以從我們的沙箱級別訪問該服務。它還將所有COM服務器作為服務進程的子級啟動,這意味著Job對象不會被繼承。看起來很理想,但還存在一個小問題,為了使DCOM Activator有效,我們需要沙箱可以創建的進程外COM服務器。該對象必須滿足以下條件:

1、服務器的Launch Security授予沙箱本地激活權限;

2、服務器不能以交互用戶身份運行(該用戶會從沙箱中派生),也不能在服務進程中運行;

3、服務器可執行文件必須可以訪問受限令牌。

在這裡,我們不需要擔心第3條,GPU進程可以訪問系統可執行文件,因此我們使用預先安裝的COM服務器。創建後,是否無法訪問COM服務器也並不重要,我們所需要的只是在Job外部啟動COM服務器進程的權限,然後就可以實現劫持。我們可以使用OleViewDotNet和Select-ComAccess命令,找到可訪問的COM服務器。

<code> PS> Get-ComDatabase -SetCurrent
PS> Get-ComClass -ServerType LocalServer32 | `
      Where-Object RunAs -eq "" | `
      Where-Object {$_.AppIdEntry.ServiceName -eq ""} | `
      Select-ComAccess -ProcessId 6804 `
           -LaunchAccess ActivateLocal -Access 0 | `
      Select-Object Clsid, DefaultServerName

Clsid                                DefaultServerName
-----                                -----------------
3d5fea35-6973-4d5b-9937-dd8e53482a56 coredpussvr.exe
417976b7-917d-4f1e-8f14-c18fccb0b3a8 coredpussvr.exe
46cb32fa-b5ca-8a3a-62ca-a7023c0496c5 ieframe.dll
4b360c3c-d284-4384-abcc-ef133e1445da ieframe.dll
5bbd58bb-993e-4c17-8af6-3af8e908fca8 ieproxy.dll
d63c23c5-53e6-48d5-adda-a385b6bb9c7b ieframe.dll
/<code>

在Windows 10的默認安裝中,我們有6個備選的軟件。請注意,其中4個都在DLL中,但是這些類已經註冊為在DLL Surrogate中運行,因此仍然可以在進程外使用。我們決定選擇COREDPUSSVR中的服務器,因為它是唯一的可執行文件,而不是通用的DLLHOST,因此更易於查找。這個COM服務器的啟動安全性授予每個人和所有AppContainer程序包本地激活權限,如下所示:

一行代碼能產生多大影響:Chrome沙箱逃逸漏洞分析

順便提一句,即使為COREDPUSSVR註冊了兩個類,這個可執行文件實際上也只註冊了一個以417976b7開頭的類。創建另一個類,將啟動服務器可執行文件,但是類的創建將會掛起,以等待一個永遠不會出現的類。

要啟動服務器,我們需要在模擬子進程無標誌受限令牌的同時調用CoCreateInstance。我們還需要傳遞CLSCTX_ENABLE_CLOAKING,以模擬令牌激活服務器,默認值將使用已設置子進程緩解標誌的進程令牌,因此將會阻止進程的創建。這樣一來,我們就可以發現一個COREDPUSSVR實例在相同的沙箱級別運行,但是在Job對象之外,並且也沒有子進程的緩解。我們似乎接近成功了。

但是,還沒有那麼快。通常,新進程的默認安全性基於用於創建新進程的訪問令牌中的默認DACL。但遺憾的是,由於某些未知原因,DCOM Activator在進程上設置了一個明確的DACL,它僅授予對用戶、SYSTEM和當前登錄SID的訪問權限。即使GPU進程實際上以相同的安全級別運行,也不允許GPU進程打開新的COM服務器進程。我們如此接近成功,但又離成功如此遙遠。我嘗試了幾種方法在COM服務器內部執行代碼,例如Windows Hooks,但沒有效果。

幸運的是,進程啟動後創建的所有線程仍然將使用默認的DACL。我們可以打開其中一個線程,進行完全訪問,並使用SetThreadContext更改線程上下文以重定向執行。我們需要對這些新線程的線程ID進行暴力破解,因為進一步的沙箱緩解措施將阻止我們使用CreateToolhelp32Snapshot來枚舉無法直接打開的進程,而NtGetNextThread需要我們現在還沒有的父進程句柄。

濫用線程會非常痛苦,特別是在我們沒有辦法直接將任何內容寫入進程的時候,但這至少可以有效。為了簡便起見,我決定調用WinExec,它將生成一個新進程,並且只需要執行命令行即可。新進程將具有基於默認DACL的安全性,因此我們可以將其打開。

我可以選擇其他類似LoadLibrary的方式來加載DLL。但是,在比較混亂的線程上下文中,這可能會導致進程崩潰。我認為,最好的方法是儘快逃逸這個進程,以避免這種情況。

那麼,用什麼作為WinExec的命令行呢?我們無法在COM服務器進程中直接寫入或分配內存,但是我們可以輕鬆地重新利用二進制文件中現有的字符串來執行。為了避免尋找字符串地址或處理ASLR,我們選擇在DLL的開頭使用PE簽名,該簽名為我們提供了字符串“PE”。當傳遞給WinExec時,當前的PATH環境變量將會用於查找要啟動的可執行文件。我們可以將PATH設置為COM服務器中所需的任何內容,因為當以相同的安全級別啟動進程時,DCOM Activator將使用調用方的環境。我們唯一要做的就是找到一個可以寫入的目錄,這次我們可以使用Get-AccessibleFile找到一個候選對象,如下所示。

<code>PS> Get-AccessibleFile -Win32Path "C:" -Recurse -ProcessIds 6804 `
     -DirectoryAccessRights AddFile -CheckMode DirectoriesOnly `
     -FormatWin32Path | Select-Object Name
Name
----
C:ProgramDataMicrosoftDeviceSync
/<code>

通過設置PATH環境變量,在其中包含DeviceSync路徑,並將名為PE.exe的可執行文件複製到該目錄,我們可以設置線程上下文,並生成一個新的進程,該進程不在Job對象中,並且可以由GPU進程打開。

現在,我們可以利用內核漏洞,以低IL運行不受限制的令牌,從新的進程中調用CreateProcessAsUser。這樣一來,將會刪除所有除低級別IL以外的沙箱。最後一步,就是突破低IL。也有很多方法可以做到這一點,但我選擇了濫用UAC服務。通過濫用相同的令牌訪問權限,我們得以在利用鏈中濫用權限,打開不受限制的令牌,從而獲得UI訪問權限。這樣一來,我們可以自動化特權用戶界面,以在低級別沙箱外部執行任意代碼。這不一定有效,但可以嘗試。

最終,我們總結的利用鏈如下:

1、打開一個不受限制的令牌。

a、暴力破解進程,直到找到合適的進程令牌。

2、複製令牌,以創建新的主令牌,並使令牌可寫。

a、重複令牌為只讀;b、複製句柄,以獲得寫訪問權限。

3、投放令牌的IL,以匹配當前令牌。

4、使用新令牌調用CreateProcessAsUser。

a、創建一個新的受限令牌,以刪除子進程緩解標誌。b、將環境塊的PATH設置為包含DeviceSync的文件夾,然後投放PE.exe文件。c、模擬受限令牌,並創建OOP COM服務器。d、暴力破解COM服務器進程中的線程ID。e、修改線程上下文,以調用WinExec,在內存中傳遞已知PE簽名的地址。f、等待創建PE進程。

5、逃逸低IL沙箱。

a、生成屏幕鍵盤的副本,並打開其令牌。b、根據打開的令牌,創建具有UI訪問權限的新進程。c、自動運行對話框,以退出低IL沙箱。

或者,以圖表形式表示如下:

一行代碼能產生多大影響:Chrome沙箱逃逸漏洞分析

總結

我希望通過這篇文章,能讓大家熟悉Windows內核中的一個微小更改是如何嚴重影響沙箱環境安全性的。此外,還演示了緩解沙箱行為的漏洞利用的價值。因為緩解措施的存在,很多時候都讓漏洞利用過程不再那麼便捷。研究引入漏洞的場景和過程會非常有趣。我們推斷,也許是有人在更新代碼的過程中,認為這是一個Bug,並且對其進行了“修復”。或者,是隨著時間的推移才失去了單線的安全性。無論如何,這並不是有意的調整,而且也在現在提供了修復的方案。由於操作系統中的一些“特性”,即使漏洞利用方法需要花費很多精力才能發現,但通常也可以通過一些緩解措施來達成目標。這些功能本身並非安全問題,但對於構建漏洞利用鏈來說非常有幫助。


原文鏈接:https://www.anquanke.com/post/id/203790


分享到:


相關文章: