执行POC,异常触发在箭头所示位置
首先这里var是0x1234
就是不合法的,因为0x1234理应是个TaggedInt,但是它的49位却为0
var带着值0x1234执行函数RecyclableObject::FromVar
导致异常。
可以看下如下对TaggedInt的验证
向上追溯到ProfiledLdElem
,箭头所指触发异常
这里element是0x1234,由箭头上一句知element是ProfiledLdElem_FastPath返回值。查看array
地址0x00000224949BC3E0处正是0x1234
之后我们可以看到在ProfilingHelpers::ProfiledLdElem_FastPath
中针对array 0x224949bc380
进行的操作
至此我们明白了0x00000224949BC3D8是数组元素储存的地址
针对0x000022494a255e0进行分析
因此这个数组本应是储存DynamicObject的,并且也把element1作为DynamicObject解析了,因此我们可以明确这是一个类型混淆导致的crash。
经简化后的POC如下
调试得知arr[1] = 2.3023e-320 + parseInt('a'.replace('a', f));
对应的hex值即为0x1234。
</br>
在此我们猜测for循环0x1000次只是为了给opt()
函数生成JIT代码,而当对JIT代码传递exp函数进行执行时就会触发漏洞。
</br>
为什么传递exp函数会触发crash?
猜测是JIT后的代码执行exp函数造成了arr由float类型混淆为Object类型数组。
梳理一下,多次调用后opt()被JIT,之后Jstring.prototype.replace
调用用户定义exp()
,而exp()
暗含类型混淆的操作导致crash发生。
梳理清这点之后,可以提出几个问题:
为解决这些问题,需要定位string.prototype.replace
函数,经调试发现函数会调用以下函数N次(for)
推测string.prototype.replace
对应于RegexHelper::StringReplace
,查看RegexHelper::StringReplace
对应的三个参数
根据POC可以得到对应关系
根据RegexHelper::StringReplace
发现一重载函数,replace参数为JavascriptFunction*
同时这里可以根据调用关系提取出JIT函数,这个JIT函数就是对应于POC中的opt()
的
由JIT执行的函数流程如下
未经JIT的opt()函数是由bytecode解释执行的,执行流程如下。
之后通过仔细观察Js::RegexHelper::StringReplace
函数的代码,发现是以下代码调用了用户自定义的函数(注意其中的replacefn->GetEntryPoint)
为了进一步解决问题,我们根据补丁的情况发现修补前的代码如下
修补后如下
可以看到是以ExecuteImplicitCall替换了CALL_FUNCTION来调用用户提供的函数
通过观察上面的函数可以发现,只有当满足一定的条件时,用户定义的implicitCall才会被调用,否则会返回undefined。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课