(CVE-2019-5786) 漏洞原理分析及利用

酷酷的曉得哥發表於2020-07-01

作者:Kerne7@知道創宇404實驗室
時間:2020年6月29日

原文連結:

從補丁發現漏洞本質

首先根據谷歌部落格收集相關CVE-2019-5786漏洞的資料: ,得知是FileReader上的UAF漏洞。

然後檢視 上的補丁

對比補丁可以看到 DOMArrayBuffer* result = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer()),操作放到了判斷finished_loading後面,返回值也從result變成了array_buffer_result_(result的複製)。猜測可能是這個返回值導致的問題。

分析程式碼

raw_data_->ToArrayBuffer()可能會返回內部buffer的複製,或者是返回一個指向其偏移buffer的指標。

根據MDN中FileReader.readAsArrayBuffer()的描述:

FileReader 介面提供的 readAsArrayBuffer() 方法用於啟動讀取指定的 Blob 或 File 內容。當讀取操作完成時,readyState 變成 DONE(已完成),並觸發 loadend 事件,同時 result 屬性中將包含一個 ArrayBuffer 物件以表示所讀取檔案的資料。

FileReader.onprogress事件在處理progress時被觸發,當資料過大的時候,onprogress事件會被多次觸發。

所以在呼叫FileReader.result屬性的時候,返回的是WTF::ArrayBufferBuilder建立的WTF::ArrayBuffer物件的指標,Blob未被讀取完時,指向一個WTF::ArrayBuffer副本,在已經讀取完的時候返回WTF::ArrayBufferBuilder建立的WTF::ArrayBuffer自身。

那麼在標誌finished_loading被置為ture的時候可能已經載入完畢,所以onprogress和onloaded事件中返回的result就可能是同一個result。透過分配給一個worker來釋放其中一個result指標就可以使另一個為懸掛指標,從而導致UAF漏洞。

漏洞利用思路

我選擇的32位win7環境的Chrome72.0.3626.81版本,可以透過申請1GB的ArrayBuffer,使Chrome釋放512MB保留記憶體,透過異常處理使OOM不會導致crash,然後在這512MB的記憶體上分配空間。

呼叫FileReader.readAsArrayBuffer,將觸發多個onprogress事件,如果事件的時間安排正確,則最後兩個事件可以返回同一個ArrayBuffer。透過釋放其中一個指標來釋放ArrayBuffer那塊記憶體,後面可以使用另一個懸掛指標來引用這塊記憶體。然後透過將做好標記的JavaScript物件(散佈在TypedArrays中)噴灑到堆中來填充釋放的區域。

透過懸掛的指標查詢做好的標記。透過將任意物件的地址設定為找到的物件的屬性,然後透過懸掛指標讀取屬性值,可以洩漏任意物件的地址。破壞噴塗的TypedArray的後備儲存,並使用它來實現對地址空間的任意讀寫訪問。

之後可以載入WebAssembly模組會將64KiB的可讀寫執行儲存區域對映到地址空間,這樣的好處是可以免去繞過DEP或使用ROP鏈就可以執行shellcode。

使用任意讀取/寫入原語遍歷WebAssembly模組中匯出的函式的JSFunction物件層次結構,以找到可讀寫可執行區域的地址。將WebAssembly函式的程式碼替換為shellcode,然後透過呼叫該函式來執行它。

透過瀏覽器訪問網頁,就會導致執行任意程式碼

幫助

本人在初次除錯瀏覽器的時候遇到了很多問題,在這裡列舉出一些問題來減少大家走的彎路。

因為chrome是多程式模式,所以在除錯的時候會有多個chrome程式,對於剛開始做瀏覽器漏洞那話會很迷茫不知道該除錯那個程式或者怎麼除錯,可以透過chrome自帶的工作管理員來幫我們鎖定要附加除錯的那個程式ID。

這裡新的標籤頁的程式ID就是我們在後面要附加的PID。

Chrome除錯的時候需要符號,這是google提供的 (載入符號的時候需要 Over the wall)。在windbg中,您可以使用以下命令將其新增到符號伺服器搜尋路徑,其中c:\Symbols是本地快取目錄:

.sympath + SRV * c:\ Symbols * https://chromium-browser-symsrv.commondatastorage.googleapis.com

因為Chrome的沙箱機制,在除錯的過程中需要關閉沙箱才可以執行任意程式碼。可以在快捷方式中新增 no-sandbox來關閉沙箱。

由於這個漏洞機制的原因,可能不是每次都能執行成功,但是我們可以透過多次載入指令碼的方式來達到穩定利用的目的。

在github上有chromuim的原始碼,在分析原始碼的時候推薦使用sourcegraph這個外掛,能夠檢視變數的定義和引用等。

在需要特定版本Chrome的時候可以自己去build原始碼或者去網路上尋找chrome歷代發行版收集的網站。

在看exp和自己編寫的時候需要注意v8引擎的指標問題,v8做了指標壓縮,所以在記憶體中存訪的指標可能和實際資料位置地址有出入。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912109/viewspace-2701686/,如需轉載,請註明出處,否則將追究法律責任。

相關文章