最新消息:图 床

Edge Inline Segment Use After Free

COOL IAM 171浏览 0评论

作者:Qixun Zhao(aka @S0rryMybad && 大寶) of Qihoo 360 Vulcan Team
作者博客:https://blogs.projectmoon.pw/2018/09/15/Edge-Inline-Segment-Use-After-Free/

在今個月的微軟補丁里,修復了我報告的4個漏洞,我將會一一講解這些漏洞.因為我寫的這些文章都是用我的空餘時間寫的,因為每天還有大量的工作和需要休息,而且這個博客也是一個非公的私人博客,所以我不能保證更新的時間.

這篇文章講的是CVE-2018-8367,大家可以從這裡看到這個bug的patch. 這是一個品相非常好的UaF,所以利用起來比較簡單.同時這也是JIT中一個比較特別的漏洞,因為它需要其他模塊的配合,希望能為大家以後尋找JIT漏洞的時候帶來一些新思考

測試版本:chakraCore-master-2018-8-5 release build(大概是這個日期下載的就可以了)

關於Chakra的垃圾回收(GC)

要找到chakra中的UaF漏洞,首先需要了解chakra引擎的gc是怎麼執行的.簡單來說,chakra用到的gc算法是標記-清除(mark-sweep)算法,更詳細的細節我推薦大家可以看看<<垃圾回收的算法與實現>>.

這個算法的核心在於有一堆需要維護的根對象(root),在chakra中根對象主要包括顯式定義的腳本變量(var/let/const)還有棧上和寄存器的變量.算法從根對象開始掃描,並且遞歸掃描他們中的子對象(例如array對象中的segment就是array的子對象),直到遍歷完所有的根對象和子對象.標記階段完成後,如果沒有標記的對象就是代表可以釋放的,這時候內存管理器就會負責回收這些對象以用來以後的分配.

Chakra的gc算法主要有兩個缺陷,第一是沒有區分數字和對象,所以利用這個特性通過在棧上分配大量數字,然後通過側信道攻擊可以獲得某個對象的地址.(這是我之前聽過的一種攻擊方法,不知道現在修補沒有)

第二個缺陷在於,gc算法遍歷子對象的時候,是需要知道父對象的大小的,不能越界遍歷標記(例如父對象是array的時候,需要知道array的大小去遞歸標記).所以如果一個對象A中假如有一個指針指向另一個對象B的內部(非對象開始位置),A中的指針是不會執行標記操作的.假如除了對象A中的指針沒有其他任何指針指向對象B,B對象是會被回收的.這樣在A對象中就有一個B對象的懸挂指針(Dangling Pointers).

尋找UaF漏洞的關鍵就在於是否能創造一個對象中存在一個指針,指向另一個對象內部,而一般能出現這種情況的對象是String和Array.以前出現的類似漏洞有:CVE-2017-11843

Array Inline Segment 與Array.prototype.splice

在創建數組的時候,如果數組的size小於一定的值,數組的segment是會連着數組的meta data,也就是保存數組數據的segment緊跟數組後面.內存布局如圖所示:

let arr = [1.1,2.2,3.3,4.4,5.5,6.6];
Array.isArray(arr);

這裡chakra在處理splice這個runtime接口的時候,裡面存在一個優化的模式,假如要刪除的element的start和end剛好等於一個segment的start和end(如上圖就是index[0]到[5]),就會把這個segment的地址直接賦值到新創建的數組中(function|ArraySpliceHelper|):

由於JIT的開發人員不熟悉runtime的邏輯,不清楚在創建數組的時候headsegment的length不能大於64,導致打破了chakra中的一些慣例.我們可以看到|BoxStackInstance|中創建數組的時候,根本沒有判斷需要創建的head大小就直接創建了一個inline segment array.(這裡我們需要deepcopy為true才可以)

所以到底什麼是BoxStackInstance,在什麼情況下才能調用這個創建數組?

在JIT中,有一個優化機制叫做escape analysis,用於分析一個變量是否逃出了指定的範圍,假如一個變量的訪問用於只在一個function裡面,我們完全可以把這個變量當成局部變量,分配在棧上,在函數返回的時候自動釋放.這樣的優化可以減少內存的分配和gc需要管理的對象,因為這裡對象的生命周期是和函數同步的,並不是由gc管理.

但是這裡有一個問題,但是某些特殊情況下,我們需要把這個棧上的變量重新分配到堆上,這時候就需要調用BoxStackInstance重新創建對象.

情況一就是bailout發生的時候,因為需要OSR回到解釋器層面執行,這時候就沒有所謂的native函數棧概念,只剩下虛擬機的虛擬棧,否則對象會引用已釋放的棧空間.這種情況deepcopy為false,並不滿足我們的需要.

情況二就是通過arguments訪問一個棧變量,因為arguments可能是一個堆對象,它是由gc管理的,它裡面必定不能包含棧分配的對象.這時候deepcopy為true.

至此,漏洞的大概原理已經分析清楚.

I WANT TYPE CONFUSION

通過上面的分析,我相信大家結合GPZ的case差不多已經知道如何構造poc了:

转载请注明:IAMCOOL » Edge Inline Segment Use After Free

0 0 vote
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x