简述:
微软于2020年5月12日发布了一项安全更新,该补丁修补了CVE-2020-1062漏洞,该漏洞是针对IE浏览器旧版脚本引擎jscript.dl的UAF(use-after-free)漏洞。该漏洞可造成远程代码执行,攻击者利用此漏洞可获得与当前用户相同的权限。下面我们将结合poc与官方补丁对该漏洞进行深入的分析。
POC分析:
定位异常:
使用windbg调试开启页面堆的IE进程,加载POC,捕获程序异常,问题出现在jscript.dll的JsArrayPush函数中,对应js代码中的push操作。
根据mozilla的描述:
[].push.call(this,elem):push()方法用于将一个或多个元素添加到数组的末尾,并返回该数组的新长度,该方法被特意设计为通用的,结合call方法,可使[].push认为处理对象为数组,并在一个对象上正常工作。
JsArrayPush分析:
通过分析发现漏洞在JsArrayPush函数中的逻辑为:
- 获取this对象的相关属性;
- 判断长度属性是否为int类型(否);
- 对长度属性进行类型转换(该过程触发toString回调,并执行wirte释放内存);
- 使用已经被释放的指针,程序崩溃。
获取对象”length”属性:
Jscript引擎通过向NameTbl::GetVal函数传递sym参数,获取目标对象的属性。
在此处,我们通过GetVal获取”this”对象的”length”属性,函数返回时将其存储在ebp-4Ch的变量中。
程序继续执行,到如图所示位置时对“length”属性进行类型判断,判断结果会决定是否跳过类型转换步骤,即ConvertToScalar的函数调用,该函数会触发目标toString回调。
关于toString的回调,可以通过对cos函数下断验证:
详细跟踪判断过程,读取ebp-4Ch处对象的vt值,根据官方文档,当该值为3时表示”length”属性为4字节有符号整型,则跳过类型转换过程。
这里通过prototype为布尔原型类添加了”length”属性,使其对应vt值为0x80,从而进入类型转换流程。
程序继续执行,来到ConvertToScalar函数,该函数暂未调用,可以看到ebp-20h处为一个虚表指针,在单步步过ConvertToScalar后,可以看到该虚表指针已被释放。
继续运行,程序尝试调用ebp-20h处的虚表指针时,触发异常,造成UAF漏洞。
深入分析:
POC运行过程中ConvertToScalar函数的执行流程如下图所示,可以看到进入类型转换流程后,程序对传入变量的vt值进行判断,当其为0x87时调用到InvokeDispatchEx函数。经过修改POC测试,我们发现仅有当toString回调重写在父窗口时,即”length”对象与其toString回调分别定义在父窗口与子窗口两个线程中时,才会触发该流程(反之,传入变量的vt值为0x81将调用NameTbl::InvokeInternal)。
为了获取重写的toString回调方法,引擎使用与获取”length”属性时同样的方法,向NameTbl::GetVal函数传递sym参数,通过设置内存访问断点可以看到该过程。
通过对NameTbl::GetVal函数下断并查看其第一个参数,我们发现该过程在触发toString回调之前,会先进行valueOf回调,通过修改POC将toString改为valueOf同样会造成异常。
程序继续运行,执行到cos函数,说明此时已经进入toString内部,并准备运行document.write操作,达到释放的目的。
此时依然存在一个疑点,若没有将”length”对象和toString回调分别定义在两个窗口中,document.wirte完成时也不能成功释放,那么为什么一定要通过父窗口定义toString的方式才能成功完成释放呢?这里猜测是引擎的垃圾回收机制所使用的标记-清除算法出现了问题,我们将在补丁对比中寻求答案。
补丁对比:
使用bindiff对补丁前后的jscript.dll进行对比,(左)补丁后版本为KB4556798 (IE 11.0.190) ;(右) 补丁前版本为KB4550905 (IE 11.0.185) 。
通过补丁前后的函数相似度对比,可以看出补丁的主要修改内容为CSession::Close和CSession::~CSession两个函数,且改动程度比我们预想的要小很多,这对我们的分析非常有利。
在CSession::Close函数中,主要的逻辑块没有发生变化,仔细对比发现图中所示位置删除了IScavengerBase::UnlinkFromGc调用。
而在CSession::~CSession即析构函数中添加了IScavengerBase::UnlinkFromGc调用。
可以明显发现,补丁修改的逻辑仅仅是更改了UnlinkFromGc的调用位置,这符合我们之前的猜测,接下来对其进行验证。
在CSession::Close函数设置断点后,查看栈回溯时发现了document.write和push操作。说明在使用document.write操作清空子窗口文档时,确实会调用到补丁修改的close函数。
调试未打补丁的IE进程,在Close函数调用UnlinkFromGc前断下,手动修改eip的值,将目标指令跳过,继续运行将不再触发异常,且在手动关闭窗口前未发现CSession::~CSession的调用,符合我们的分析与预测。说明补丁通过修正UnlinkFromGc操作的调用时机,从而避免子窗口资源的提早释放,修复了该UAF漏洞。
官方通告:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1062
参考链接:
https://github.com/Accenture/AARO-Bugs/tree/d4c44eb5d686a1e9f1386912bb2a58cb77ccb51e
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
文章出自:安洵信息星际实验室
更多信息请关注:
公众号:安洵信息
来源:freebuf.com 2020-08-03 16:45:43 by: 安洵信息
请登录后发表评论
注册