首页
社区
课程
招聘
[原创]CVE-2016-7202:Overflow in Array.reverse
发表于: 2017-11-13 11:02 4409

[原创]CVE-2016-7202:Overflow in Array.reverse

2017-11-13 11:02
4409

这是一个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指向的值,如下图
捕获.PNG-94.8kB

对应到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长度,基本原理一致不再详细分析。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错!
2017-11-14 20:38
0
游客
登录 | 注册 方可回帖
返回
//