-
-
[原创]CVE-2017-11893 Math.Max.apply方法破坏执行流程导致类型混淆
-
发表于: 2018-1-24 12:04 4282
-
source:https://bugs.chromium.org/p/project-zero/issues/detail?id=1379
poc如下所示
执行poc出现如下crash信息
在这里this指针为0x1234是浮点数2.3023e-320的16进制表示因此我们猜测此处发生了类型混淆
根据poc可知程序在多次循环执行之后进行JIT,JIT之后生成如下所示的代码,sub_1ebdd8d092f
sub_1ebdd8d092f对应于poc中的
JIT生成的另一个函数是sub_1ebdd8d017d
JIT生成的sub_1ebdd8d017d对应POC中的
在JIT的环境下程序执行的流程如下
JavascriptMath::MaxInAnArray
对应于Math.max.apply
,注意只有在JIT环境下才会调用这个函数。
apply是javascript中一种调用函数的方法类似于同样效果的call方法,根据MDN的描述
语法
fun.apply(thisArg, [argsArray])
参数
thisArg
在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined
时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
argsArray
一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。
call()方法的作用和 apply() 方法类似,只有一个区别,就是 call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。对于Math.Max方法来说,Math.Max接受的是参数的列表比如
而使用apply方法则需要传入数组,如
</br>
在chakra中总共有两类数据类型可以被用于调用Math.Max.apply方法,分别是JavascriptNativeArray
和JavascriptTypedArray
,其中JavascriptNativeArray
包含JavascriptNativeIntArray
和JavascriptNativeFloatArray
,而JavascriptTypedArray
包含Uint8Array
、Int16Array
、Uint32Array
、Float32Array
等
</br>
</br>
这些调用由函数JavascriptMath::MaxInAnArray
负责分发
但是如果传入的参数不属于JavascriptNativeArray
和TypedArray
那么会调用JavascriptFunction::CalloutHelper
调用外部函数
对于POC来说则是会执行
这一函数被调用之后会使得原来的数组类型由JavascriptNativeArray变为JavascriptArray,之后的访问就会造成类型混淆,接下来细节分析一下这个过程。
在poc的如下代码片段中,代码被重复执行触发JIT生成
会导致最终调用到Math.max.apply
对应的JavascriptMath::MaxInAnArray
调用流程如下
当传入{}
调用opt函数时会因为参数不符合Math.Max.apply的处理要求而进行bailout
首先来看一下进行bailout之前数组arr的情况
对应的segment对象在执行arr[0] = 1.1;
之后
当未进行bailout并且执行arr[0] = 2.3023e-320;
之后segment对象情况如下
当进行bailout之后,调用JavascriptFunction::CallFunction
,执行poc中的arr[0] = {};
,之后arr的类型会由NativeArray转变为Array,如下
其对应的segment对象也相应发生改变(但地址未变)
注意其中地址为0x0000020840E58158的第一个元素的值变成一个对象的指针
之后由于JIT中的代码会对segment中的第一个元素赋值导致发生了类型混淆
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!