Chromium issue 1196683、1195777分析

深信服千里目發表於2021-04-21

2021年4月12日,開源瀏覽器核心Chromium的一處改動提交引起了關注。這是Chromium Javascript引擎v8的一處漏洞bugfix。同時針對該bugfix的迴歸測試樣本regress-1196683.js也被提交。基於該回歸測試,有安全研究員公佈了完整的利用程式碼。由於Chromium開發流程,該漏洞於4月13日Chrome的release版中才被修復。無獨有偶,4月15日Chromium程式碼倉庫另一處改動提交也包含了迴歸測試樣本regress-1195777.js。基於該樣本,完整的利用程式碼再次被公佈。由於最新的Chrome release版沒有引入該bugfix,利用程式碼仍可以在最新的Chrome瀏覽器的渲染程式穩定利用。當受影響版本的Chormium核心瀏覽器在沒有開啟沙箱的情況下(--no-sandbox),訪問攻擊者構造的惡意連結時,將會觸發該漏洞,造成遠端程式碼執行。


 

1. Issue 1196683原理分析


該issue的bugfix程式碼如下:

 Chromium issue 1196683、1195777分析

 

bugfix修復了v8 TurboFan在指令選擇階段針對ChangeInt32ToInt64節點的指令選擇錯誤問題。改動前根據ChangeInt32ToInt64節點的輸入節點型別選擇指令。如果輸入節點型別為有符號整數,則選擇指令X64Movsxlq先做符號擴充套件,否則選擇X64Movl做零擴充套件。Bugfix後則無論輸入型別,一律選擇X64Movsxlq做符號擴充套件。根據修復程式碼可以猜測,這裡應該是ChangeInt32ToInt64節點輸入型別為無符號整數,導致指令選擇階段錯誤選擇X64Movl指令引發的安全問題。

 

首先通過regress-1196683.js分析漏洞根因:

 Chromium issue 1196683、1195777分析

 

觸發JIT的foo函式只有一行程式碼,重點關注 (arr[0] ^ 0) + 1在TurboFan中關鍵階段的優化過程:


1) TyperPhase

Chromium issue 1196683、1195777分析 

異或操作符對應32節點,其兩個輸入分別為常量0(24節點)和arr[0](80節點)。

 

2) SimplifiedLoweringPhase

Chromium issue 1196683、1195777分析 

32節點SpeculativeNumberBitwiseXor被優化成Word32Xor,並加入後繼節點ChangeInt32ToInt64。此時ChangeInt32ToInt64節點的輸入節點Word32Xor型別為Signed32

 

3) EarlyOptimizationPhase

Chromium issue 1196683、1195777分析 

可以看到原32節點被刪除,並用80節點替代作為110節點ChangeInt32ToInt64的輸入。此時ChangeInt32ToInt64節點的輸入節點LoadTypedElement型別為Unsigned32


這段邏輯對應的v8程式碼如下:

 Chromium issue 1196683、1195777分析

如上所示,對於x ^ 0 => x的情況,使用左節點替換當前節點,從而引入了錯誤的資料型別。

 

4) InstructionSelectionPhase


根據前面的分析,指令選擇階段,ChangeInt32ToInt64節點的輸入節點LoadTypedElement型別為Unsigned32,最終選擇X64Movl指令替換ChangeInt32ToInt64節點:

 Chromium issue 1196683、1195777分析

 

因為錯誤選擇了零擴充套件指令X64Movl,導致(arr[0] ^ 0)返回錯誤的值:0x0000000080000000


最終利用該漏洞,通過如下程式碼可以得到一個JIT中非預期值為1的變數x(預期值應為0):

 Chromium issue 1196683、1195777分析

 


2. Issue 1195777原理分析


該issue的bugfix程式碼如下:

 Chromium issue 1196683、1195777分析

 

bugfix修復了v8 TurboFan在SimplifiedLowering階段,對64位整數轉為32位整數的資料型別轉換節點生成錯誤的問題。改動前對於當前節點的輸出型別為Signed32Unsigned32均生成TruncateInt64ToInt32節點(截斷);改動後,對於當前節點的輸出型別為Unsigned32的情況,還需要檢查use_info的型別,只有在use_info.type_check() == TypeCheckKind::kNone的情況下,才會生成TruncateInt64ToInt32節點。

 

首先通過regress- 1195777.js分析漏洞根因:


 Chromium issue 1196683、1195777分析

 

觸發JIT的foo函式中關鍵程式碼為return -1 < Math.max(0, x, -1)。重點關注 Math.max(0, x, -1)在TurboFan中關鍵階段的優化過程:


1) TyperPhase

Chromium issue 1196683、1195777分析 

Math.max(0, x, -1)對應了56,58節點,58節點輸出作為41節點SpeculativeNumberLessThan<)的輸入。

 

2) TypedLoweringPhase

Chromium issue 1196683、1195777分析 

Math.max(0, x, -1)兩個常量引數0,-1(54,55節點)被替換成了常量節點32和14

 

3) SimplifiedLoweringPhase

Chromium issue 1196683、1195777分析 

原56,58的NumberMax節點,被Int64LessThan + Select節點替換;原41節點SpeculativeNumberLessThan被替換為Int32LessThan。在處理SpeculativeNumberLessThan輸入節點的時候,因為輸入節點(Select)的輸出型別為Unsigned32,從而觸發漏洞,導致76節點TruncateInt64ToInt32被錯誤生成。從而將Math.max(0, x, -1)的結果截斷為Signed32。因此,當Math.max(0, x, -1)中的x為Unsigned32時,會被TruncateInt64ToInt32錯誤截斷為Signed32

 

最終利用該漏洞,通過如下程式碼可以得到一個JIT中非預期值為1的變數x(預期值應為0):


 Chromium issue 1196683、1195777分析


 

3. 漏洞利用分析


根據上面對這兩個漏洞的分析可以知道:這兩個漏洞是TurboFan在做整型資料型別轉換(擴充套件、截斷)時發生的錯誤。利用這兩個漏洞,通過如下程式碼可以得到一個JIT中非預期值為1的變數x。接下來根據在野利用樣本,分析如何根據這個錯誤數值為1的變數x,實現遠端程式碼執行。


具體利用步驟為:

1)藉助這個錯誤數值為1的變數x,構造一個長度為1的Array;

2)通過Array.prototype.shift()獲得一個長度為0xFFFFFFFF的越界陣列;

關鍵程式碼如下:

 Chromium issue 1196683、1195777分析

其中var arr = new Array(x);對應的JIT程式碼:

 Chromium issue 1196683、1195777分析

這裡rdi為陣列的長度,即x的值1。指標壓縮後,左移一位(rdi+rdi),存放在JSArray.length屬性(+0xC)。

 

arr.shift();對應的JIT程式碼:

 Chromium issue 1196683、1195777分析

 

這裡可以看到,arr.shift()後,陣列的長度直接由常量0xFFFFFFFE賦值,其優化過程:


(1)TyperPhase

Chromium issue 1196683、1195777分析 

這裡陣列長度賦值操作主要由152,153節點組成。其中152節點做Array.length-1計算操作。153節點將計算結果儲存在Array.length(+0xC)處。


2LoadEliminationPhase

 Chromium issue 1196683、1195777分析

這裡可以看到,由於在Ignition執行過程中收集的x值為0,這裡做了常量摺疊(0-1=-1),從而得到常量0xFFFFFFFF。左移一位後為0xFFFFFFFE,存放在Array.length(+0xC)處。從而得到一個長度為0xFFFFFFFF的越界陣列。


得到越界陣列後,後面的利用方法就比較通用了,一般為:


3)藉助這個越界陣列,實現addrof/fakeobj


4)藉助addrof/fakeobj,偽造一個JSArray,實現任意地址讀寫;


樣本中利用arr和cor實現任意地址讀寫的記憶體佈局為:

 Chromium issue 1196683、1195777分析

(1)首先利用漏洞獲得一個長度為0xFFFFFFFF的arr(紅框)

2)利用越界的arr和cor實現addrof/fakeobj(綠框)

(3)利用越界的arr修改cor的長度(黃框)

(4)利用越界的cor,洩露cor的map和properties屬性(藍框),構造一個fake JSArray,藉助這個fake JSArray實現任意地址讀寫

 

5)藉助WebAssembly執行shellcode


最後藉助WebAssembly建立一個RWX屬性的記憶體頁,拷貝shellcode至該記憶體頁,執行shellcode


完整的利用演示:

 Chromium issue 1196683、1195777分析

 


4. 結論


經分析,這兩個v8 JIT的漏洞觸發容易且利用簡單,在沒有開啟沙箱的Chromium核心瀏覽器中可以穩定利用。考慮到這兩個漏洞只是Chromium核心瀏覽器渲染程式的遠端程式碼執行漏洞,無法穿透瀏覽器沙箱(預設開啟),建議使用者不要關閉Chromium核心瀏覽器的沙箱,且不要點選不明連結。

 


5. 參考連結


[1] https://chromium-review.googlesource.com/c/v8/v8/+/2820971

[2] https://chromereleases.googleblog.com/2021/04/stable-channel-update-for-desktop.html

[3] https://chromium-review.googlesource.com/c/v8/v8/+/2826114

[4] https://github.com/r4j0x00/exploits/blob/master/chrome-0day/exploit.js

[5] https://github.com/avboy1337/1195777-chrome0day/blob/main/1195777.html


 

6. 團隊簡介


深信服南研安全研究團隊專注於APT攻擊,在野漏洞利用追蹤、研究檢測,攻防對抗等方向的研究工作。團隊成員曾在Windows,MacOS/iOS,Linux/Android等主流作業系統中發現了上百個安全漏洞,在BlackHat USA、BlackHat Europe、BlackHat Asia、HITB、Microsoft BlueHat、CodeBlue、HITCON、Virus Bulletin、Pacsec、看雪SDC、Freebuf CIS等國內外知名安全會議上發表過演講和論文。

 

如果你對以下技術內容感興趣,希望和高手切磋共事,趕緊發簡歷過來吧(郵箱caolei@sangfor.com.cn 工作地點:南京):

[APT攻擊溯源] 惡意程式碼分析,威脅情報研究APT溯源分析

[檢測引擎研發] EDR、XDR等檢測引擎研發

[攻防對抗技術] 紅藍對抗,ATT&CK技術研究,檢測規則編寫

[漏洞挖掘與利用] 在野漏洞利用研究,漏洞挖掘

[雲原生安全] 雲原生安全技術研究和產品研發

[MacOS安全] macOS安全產品核心模組開發,macOS沙箱、EDP、EDR、DLP等安全產品開發

[大資料安全] 研發基於大資料技術的下一代安全產品


相關文章