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