-
-
[原创]CVE-2016-7202:Overflow in Array.reverse
-
发表于:
2017-11-13 11:02
4408
-
[原创]CVE-2016-7202:Overflow in Array.reverse
这是一个natashenka在16年报的漏洞,关注浏览器的同学应该都有看过她的《The ECMA and the Chakra
-Hunting bugs in the Microsoft Edge Script Engine》
poc首先定义了一个array a和object o,之后给object o设置一个getter。并将a的proto设为o,之后对a调用Array.prototype.reverse。
https://bugs.chromium.org/p/project-zero/issues/detail?id=925
异常出现在如下函数
其中length的值为0x000003ea,size值为1,导致Assert抛出异常。
观察函数可以知道nextLeft为JavascriptArray::MaxArrayLength也就是0xffffffff
而size = min(size, nextLeft - left)
,length值为我们设置的1002(0x000003ea)是正常值,nextLeft和length值为正常说明left值存在问题。
观察left值来源
跟踪函数流程,发现是由以下函数调用到的
由文档可知JavascriptArray::ReverseHelper
对应于Array.prototype.reverse
reverse方法用于将数组中元素的位置颠倒
首先来看下Array.prototype.reverse是怎么实现的
1.Let O be ToObject(this value).
2.Let len be ToLength(Get(O, "length")).
3.Let middle be floor(len/2).
4.Let lower be 0.
首先获取长度设为len,取中间值设为middle,起始值设为lower为0
之后就是循环交换upper和lower指向的值,如下图
对应到Chakra的代码中则是如下情况
其中ReverseSegment函数负责真正的置换操作,根据数组元素的类型执行对应的模版函数。
其中length是由上层函数传递的,seg->length是从对象中获取的,调试发现这两个值有所不同
length为1000,而seg->length为1002,这里相减产生负值导致crash发生。
根据POC猜测这里对象中的length改变是由于对a数组设置的getter
根据调试发现ForEachOwnMissingArrayIndexOfObject中调用ES5Array::GetItem触发了Getter导致array的segment发生变化
那么getter中的j.fill.call(a, 7.7)
存在的意义是什么呢,如果只是把a.length设为1002,虽然array object的length会变成1002但是array对应的segment的length和size并不会变成1002,因为这块内存并没有实际使用因此就不会更改segment的长度,从而无法触发漏洞。
至此我们明确了漏洞产生的原因在于segment的长度可以在函数执行过程中被改变(比如通过getter)。
这里的seg->left是直接使用上层传递的参数length进行运算的,因此length是固定的但是seg->length是可以通过user callback控制的,从而使得用户可以控制seg值。
此外还有一个版本的POC是通过Proxy劫持getPrototypeOf
实现的user callback篡改segment长度,基本原理一致不再详细分析。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课