
介紹
去年,英國國家網絡安全中心(NCSC)報告了一個V8編譯器中存在的安全漏洞,随後Google便悄悄修複了該漏洞。這個漏洞ID為1003286,漏洞的具體資訊可以點選【】擷取。根據漏洞報告的描述,這是一個空指針解除引用DoS漏洞,這個漏洞是一個不可利用的漏洞,并且隻能通過WASM代碼來觸發。在深入分析之後,我們發現這裡還有另一種觸發該漏洞的方式,并且能夠通過V8 JIT編譯器程序來利用該漏洞實作攻擊。
在這篇文章中,我們将會介紹該漏洞的利用技術細節,并示範如何利用該漏洞實作遠端代碼執行。
漏洞成因
出于代碼優化方面的考慮,V8 JIT編譯器使用了節點圖,并通過優化管道的幾個階段減少節點圖來生成優化的本機代碼。而且這個節點圖也适用于WASM編譯器,可以将WASM代碼編譯為本機代碼。
節點在圖中使用“Use”結構互相連結,如下所示:
通過使用這種結構,節點可以指定自己的輸入節點和使用者節點來減少圖的周遊。Use結構體重包含了用于儲存多種資訊的比特字段,如下所示:
InputIndex字段表示這個Use結構輸入節點的索引,它可以用來定位使用者節點相應的輸入節點。但是,這個字段僅提供了17比特的空間來存儲索引,而且沒有任何代碼來檢測這個限制是否正常執行。是以,我們就可以使用大量輸入節點來建構一個圖,讓這些節點指向一個單一節點,以此來引起整型溢出。比如說,0x20002表示0x2為輸入節點索引。
Use::input_ptr和Use::from函數都使用了這個InputIndex字段來定位使用者節點以及對應的輸入節點。
這将導緻節點、Use結構及其子字段之間出現類型混亂的情況。
NCSC的研究人員使用WebAssembly建構了一個PoC,并通過它來處罰空指針解引問題。WASM代碼優化過程比JIT編譯器的更加簡單,是以控制過程與JIT編譯器相比也更加難,是以它們無法避免空指針解引的情況。
在分析過程中,我們發現JIT代碼可以讓節點擁有大量輸入節點:
這個函數可以幫助我們建構一個跟NCSC代碼不同的PoC,并成功處罰漏洞,最終實作代碼執行流的控制。
漏洞利用
雖然這個漏洞存在于V8 JIT編譯器之中,但它跟其他常見的JIT編譯器漏洞有很大不同。為了成功利用該漏洞,我們需要生成能夠利用初始漏洞的漏洞代碼,然後利用它們來實作遠端代碼執行。
節點、Use和Operator都是我們能夠是以類型混亂的結構體,它們對應的結構如下:
上面的Use::input_ptr和Use::from函數都是通過ReplaceWithValue函數來調用的,而這個函數是用來替換節點值的:
這裡的“old_to”并非節點類型,而是Use字段:
如果use->prev為空,old_to->first_use則會被替換成use->next。由于“old_to”本質為Use,那麼old_to->first_use就相當于CheckMap節點的Operator。如果old_to->first_use被替換成了use->next,那麼CheckMapNode->op->opcode就會變成use->next->bit_field。此時,CheckMap節點的操作碼opcode就會被其他opcode替換,并導緻CheckMap節點失效。這也是漏洞利用第一步的主要攻擊場景:
根據這個模型,我們建立了下列代碼:
在替換JSStrictEqual節點之前的節點圖正好滿足我們的要求:
現在,我們就可以在PACKED_DOUBLE_ELEMENTS和DICTIONARY_ELEMENTS數組之間引起類型混亂問題,并擷取任意讀寫/addrof原語來實作遠端代碼執行了。
廣大研究人員可以在Chrome v77版本上進行完整的漏洞利用測試。
精彩推薦