可以利用跨進程內存泄漏的漏洞逃逸Chrome沙箱,在發(fā)起此攻擊之前,仍然需要攻擊者破壞渲染器,為了防止對受影響的CPU的攻擊,請確保microcode是最新的,并禁用超線程(HT)。
在我的上一個文章“破壞數(shù)據(jù)流”中,我描述了如何利用Chrome的JavaScript引擎V8中的漏洞來在渲染器中執(zhí)行代碼。為了使這種利用有用,你通常需要將其與第二個漏洞相關聯(lián),因為Chrome的沙箱會限制你對操作系統(tǒng)的訪問,并且將跨站點渲染器的站點隔離移動到單獨的進程中,以防止你繞過Web平臺的限制。
在本文中,我們將研究沙盒,尤其是當從受感染的渲染器使用RIDL和類似的硬件漏洞時所產(chǎn)生的影響。Chrome的IPC機制Mojo基于消息路由的機密,泄漏這些機密使我們可以將消息發(fā)送到特權接口,并執(zhí)行不應允許渲染器執(zhí)行的操作。我們將使用它來讀取任意本地文件,以及在Windows上的沙箱外部執(zhí)行。bat文件。在撰寫本文時,Apple和Microsoft都在與Chrome安全團隊合作積極致力于修復此漏洞,以防止這種攻擊。
0x01 背景知識
以下是Chrome流程模型的簡要概述:
渲染器進程位于單獨的沙箱中,并且對內核的訪問受到限制,例如,通過Linux上的seccomp過濾器或Windows 上的 win32k鎖定。但是,為了使渲染器執(zhí)行任何有用的操作,它需要與其他進程進行對話以執(zhí)行各種操作。例如,要加載圖像,將需要要求網(wǎng)絡服務代表其獲取圖像。
Chrome中用于進程間通信的默認機制稱為Mojo。它在后臺支持消息/數(shù)據(jù)管道和共享內存,但是你通常會使用C ++,Java或JavaScript中的高級語言之一綁定。也就是說,你使用自定義接口定義語言(IDL)的方法創(chuàng)建一個接口,Mojo用你選擇的語言為你生成存根,而你只是實現(xiàn)了該功能。這可以檢查出URLLoaderFactory .mojom IDL,C ++實現(xiàn),并在渲染使用。
Mojo的一項顯著功能是允許你通過現(xiàn)有通道轉發(fā)IPC端點。該代碼在Chrome代碼庫中得到了廣泛使用,即,每當你在。mojom文件中看到接收器或遠程參數(shù)時。
Mojo在進程之間或更具體地在Mojo的節(jié)點之間使用特定于平臺的消息管道。兩個節(jié)點可以直接彼此連接,但是由于Mojo支持消息路由,因此不必連接。網(wǎng)絡中的一個節(jié)點稱為代理節(jié)點,它具有一些其他責任來設置節(jié)點通道并執(zhí)行沙箱限制的某些操作。
IPC端點本身稱為端口。在上面的URLLoaderFactory示例中,客戶端和實現(xiàn)方都由端口標識。在代碼中,端口如下所示:
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位隨機整數(shù)。如果將消息發(fā)送到端口,它將首先將其轉發(fā)到正確的節(jié)點,接收節(jié)點將在本地端口映射中查找端口名稱,并將消息放入正確的消息隊列。
這意味著如果瀏覽器進程中存在信息泄漏漏洞,則可以泄漏端口名稱,并使用它們將消息注入特權IPC通道。實際上,在Mojo核心文檔的安全性部分中對此進行了聲明:
“ […]任何節(jié)點只要知道端口和節(jié)點名稱,就可以將任何消息發(fā)送到任何其他節(jié)點的任何端口。[…]因此,重要的是不要將端口名稱泄漏到不應被授予相應功能的節(jié)點中?!?/p>
可以很容易地利用泄漏的端口號的一個漏洞的一個很好的例子是crbug.com/779314通過@NedWilliamson。這是blob實現(xiàn)中的整數(shù)溢出,它使你可以在瀏覽器進程中讀取blob前面的任意數(shù)量的堆內存。
該漏洞利用過程將大致如下所示:
1. 破壞渲染器。
2. 使用Blob漏洞泄漏堆內存。
3. 在存儲器中搜索端口(有效狀態(tài)+ 16個高熵字節(jié))。
4. 使用泄漏的端口將消息注入特權IPC連接。
接下來,我們需要考慮兩件事。如何用CPU漏洞替換上面的第2步和第3步,以及如何通過特權IPC連接獲得什么樣的原語。
0x02 RIDL
為了利用此硬件漏洞,我需要尋找另一個漏洞,該漏洞使你可以跨進程邊界泄漏內存。來自MDS攻擊的 RIDL 似乎是最理想的選擇,因為它完全可以保證:它允許你從受影響的CPU上的各種內部緩沖區(qū)泄漏數(shù)據(jù)。有關其工作原理的詳細信息,請查看論文或PPT,因為它們比我能解釋的要好得多。
已經(jīng)發(fā)布了 microcode和操作系統(tǒng)更新來解決MDS攻擊。但是,如果你閱讀了英特爾對該問題的深入](https://software.intel.com/security-software-guidance/insights/deep-dive-intel-analysis-microarchitectural-data-sampling)研究,你會注意到,緩解措施在切換到特權較低的執(zhí)行上下文時清除了受影響的緩沖區(qū)。如果你的CPU支持超線程,你仍然可以從物理內核上運行的第二個線程中泄漏數(shù)據(jù)。解決此問題的建議是禁用超線程或實現(xiàn)組調度程序。
你可以在網(wǎng)上找到多個驗證了該MDS 漏洞的PoC,他們中的一些具有不同的屬性:
· 它們以加載或存儲目標。
· 有些要求從L1緩存中清除key。
· 你可以控制64字節(jié)高速緩存行中的索引從先前的訪問中泄漏或泄漏64位的值。
· 速度變化很大,取決于變體和漏洞利用。我看到的最高是針對Brandon Falk的228kB / s 的MLPDS攻擊。為了進行比較,我的機器上的漏洞利用僅達到25kB / s。
https://gamozolabs.github.io/metrology/2019/12/30/load-port-monitor.html#an-mlpds-exploit
所有利用變體有一個共同屬性是,它們在泄漏的內容上具有概率。盡管RIDL論文描述了一些針對某些值的同步原語,但通常需要觸發(fā)對key的重復訪問才能將其完全泄漏。
我最終使用不同的MDS變體為Chrome編寫了兩個漏洞利用,一個針對Xeon Gold 6154上的Linux構建,另一個針對Core i7-7600U上的Windows。我將描述這兩種方法,因為它們在實踐中最終面臨不同的挑戰(zhàn)。
0x03 MFBDS
微體系結構填充緩沖區(qū)數(shù)據(jù)采樣(MFBDS)
我的第一個漏洞是使用針對CPU的行填充緩沖區(qū)的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 ,以控制泄漏的高速緩存行中的偏移量。另外,你還希望按照本文所述在泄漏值上實現(xiàn)前綴或后綴過濾器。請注意,這只會泄漏不在L1高速緩存中的值,因此你希望有一種方法可以在兩次訪問之間從高速緩存中移出key值。
對于我的第一個泄漏目標,我選擇了一個特權URLLoaderFactory。如上所述,渲染器使用URLLoaderFactory來獲取網(wǎng)絡資源。它將為渲染器強制執(zhí)行同源策略(實際上是相同站點),以確保不會破壞Web平臺的限制。但是,瀏覽器進程還將URLLoaderFactories用于不同的目的,并且它們具有其他特權。除了忽略同源策略外,還允許它們上傳本地文件。因此,如果我們可以泄漏其端口名之一,則可以使用它將/ etc / passwd 上傳到https://evil.website。
下一步將觸發(fā)對特權加載程序的端口名的重復訪問。使瀏覽器進程發(fā)出網(wǎng)絡請求可能是一種選擇,但似乎開銷太大,我決定針對節(jié)點中的端口查找。
class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
// […]
std::unordered_map ports_;
// […]
}
每個節(jié)點都有一個存儲所有本地端口的哈希映射。如果我們將消息發(fā)送到不存在的端口,目標節(jié)點將在映射中查找它,發(fā)現(xiàn)它不存在并刪除消息。如果我們的端口名與另一個端口名位于同一哈希庫中,它將讀取未知端口的完整哈希值以與之進行比較。由于端口名通常與散列存儲在同一高速緩存行中,因此這還將端口名本身加載到高速緩存中。MFBDS允許我們泄漏整個緩存行,即使未直接訪問值也是如此。
該maps在一個新的Chrome實例上以大約700的存儲大小,并且主要隨著渲染器數(shù)量的增加而增長。這使攻擊變得不可行,因為我們將不得不強制使用存儲區(qū)索引和緩存行偏移量。但是,我注意到一個代碼路徑,該路徑使你可以使用服務工作者創(chuàng)建大量特權URLLoaderFactories。如果你創(chuàng)建啟用導航預加載的服務工作,則每個導航都將創(chuàng)建這樣的loader。通過簡單地創(chuàng)建多個iframe并在服務器端停止請求,你可以同時使數(shù)千個加載程序保持活動狀態(tài),并使暴力破解變得更加容易。
唯一缺少的是從L1緩存中尋找目標值。在實踐中,簡單地用32KB數(shù)據(jù)填充我們的消息似乎可以解決問題,因為我認為數(shù)據(jù)將被加載到受害者的L1緩存中。
總結完整的利用:
1. 破壞渲染器。
2. 在$ NUM_CPU-1進程中以不同的緩存行偏移量運行RIDL漏洞。
3. 安裝具有導航預加載的服務。
4. 創(chuàng)建許多iframe并暫停其請求。
5. 使用隨機端口名稱將消息發(fā)送到網(wǎng)絡進程。
6. 如果我們在存儲索引上發(fā)生沖突,則2.中的過程可能會泄漏端口名稱。
7. 將消息欺騙到URLLoaderFactory以將本地文件上傳到https://evil.website。
0x04 TSX異步中止(TAA)
在2019年11月發(fā)布了MDS攻擊的新變種,并且由于TAA PoC似乎比我的MFBDS攻擊更快,因此我決定將其改編為Chrome攻擊。此外,VUSec發(fā)布了一項針對存儲操作的漏洞利用程序,如果我們可以將key寫入到內存中的不同地址,則該漏洞應允許我們逃脫緩存刷新要求。如果我們可以觸發(fā)瀏覽器將消息發(fā)送到特權端口,則應該發(fā)生這種情況。在這種情況下,secret端口名稱也將以節(jié)點名稱作為前綴,并且我們可以使用RIDL文件中的技術輕松對其進行過濾。
我還開始尋找一個更好的原語,發(fā)現(xiàn)如果可以與NetworkService進行通信,它將允許我創(chuàng)建一個新的NetworkContext,從而選擇存儲cookie的sqlite3數(shù)據(jù)庫的文件路徑。
為了找出如何觸發(fā)從瀏覽器進程到NetworkService的消息,我查看了界面中的IPC方法,以找到一種看起來可以從渲染器影響它的方法。NetworkService.OnPeerToPeerConnectionsCountChange引起了我的注意,實際上,每次更新WebRTC連接時都會調用此方法。你只需要創(chuàng)建一個偽造的WebRTC連接,每次將其標記為已連接/斷開連接時,都會觸發(fā)一條新消息給NetworkService。
一旦從受破壞的渲染器中泄漏了端口名稱,我們就獲得了編寫具有完全受控路徑的sqlite3數(shù)據(jù)庫的原語。
雖然起初聽起來并不是很有用,但是你實際上可以濫用它來獲得代碼執(zhí)行。我注意到Windows批處理文件是一種非常好的文件格式。如果文件的開頭有gadget,它將跳過它直到下一個“ \ r \ n”并從那里執(zhí)行下一個命令。在我的漏洞利用中,我使用它在用戶的自動運行目錄中創(chuàng)建一個cookies.bat文件,添加帶有“ \ r \ n”的cookie和其中的命令,它將在下次登錄時執(zhí)行。
最終,此漏洞利用平均在我的機器上執(zhí)行了1-2分鐘,并且持續(xù)不到5分鐘。而且我敢肯定,由于某些技術可以大大提高速度,因此可以大大改善這一點。例如,實際上MLPDS似乎比我使用的變體更快。
利用步驟:
1. 破壞渲染器。
2. 在$ NUM_CPU-1進程中以不同的緩存行偏移量運行RIDL漏洞。
3. 創(chuàng)建偽造的WebRTC連接,并在已連接和已斷開連接之間切換。
4. 泄漏NetworkService端口名稱。
5. 使用c:\ path \ to \ user \ autorun \ cookies.bat中的cookie文件創(chuàng)建一個新的NetworkContext
6. 插入cookie“ \ r \ ncalc.exe \ r \ n”。
7. 等待下一次登錄。
0x05 分析總結
當我開始研究此問題時,我感到驚訝的是,即使漏洞已經(jīng)公開了一段時間,它仍然可以被利用。如果你閱讀有關該主題的指南,則他們通常會在你的操作系統(tǒng)為最新的情況下談論如何緩解這些漏洞,并應注意你應禁用超線程以完全保護自己。專注于緩解措施無疑給我一種感覺,那就是漏洞已得到解決,我認為這些文章對于啟用超線程的影響可能會更加清楚。
話雖如此,我希望你從這篇文章中思考兩個問題。首先,信息泄漏漏洞不僅僅可以繞過ASLR。即使不是依靠key端口名,也可能會泄漏其他有趣的數(shù)據(jù),例如Chrome的UnguessableTokens,Gmail cookie或計算機其他進程中的敏感數(shù)據(jù)。如果你對如何大規(guī)模查找信息泄漏有所了解,Chrome可能是一個不錯的選擇。
其次,由于硬件漏洞超出了我的研究范圍,因此我長時間忽略了它們。但是,我希望我可以通過此文章為你提供有關其影響的另一個數(shù)據(jù)點,以幫助你做出是否應該禁用超線程的決定。對于可以用類似的方式破壞其他軟件的方式,還有很多探索的余地,我很樂意看到更多應用硬件漏洞突破軟件安全性邊界的示例。