作者:启明星辰ADLab
原文链接:https://mp.weixin.qq.com/s/yeu9IZSNrp1f_lK5oIdL9A

4月13日,国外安全研究人员在社交媒体上发布了Chrome 的0Day 漏洞[1],漏洞编号为CVE-2021-21220,并在github上公开了该漏洞的POC以及利用代码,相关的利用代码在关闭沙盒的情况下可达到远程代码执行。由于chromium 相关框架的广泛应用,该漏洞在其他浏览器或脚本引擎中仍有存在的可能。该漏洞在chrome 90.0.4430.72版本已经修复,提醒广大用户及时更新到最新版本[2],以规避该漏洞存在的攻击风险。

启明星辰ADLab分析发现,该漏洞存在于Chrome 的JavaScript 解析引擎V8中,POC主要代码如下:

在POC line4执行异或操作,(2**31)^0=-2147483648。根据ECMA标准[3],异或的结果是32位整数:

在v8 SimplifiedLowering阶段,增加了对异或的结果执行ChangeInt32ToInt64的操作:

SimplifiedLowering 执行后,异或的类型被标记为Word32:

在MachineOperatorOptimizer阶段,由于是和0做异或,所以用左操作数代替异或操作。

此时的结构图如下,可以看出异或的结果是Word32|TypeUint32:

在指令选择时,对于VisitChangeInt32ToInt64操作,根据其输入类型选择操作码:

所以,这里的操作码是kX64Movl操作码,该指令在将源操作数移至目的位置时并不做符号扩展,这样在POC line4中x的值为2147483649,于是在poc line12的位置,编译器其实使用的是x=1的值作为创建数组的长度。这是编译器未曾预料到的情况。

在变量的范围分析中,编译器认为创建的数组长度是0:

在执行POP时,会先判断数组的长度是否为0,如果不是就会将其长度减1:

由于数组长度固定,编译器在LoadElimination 的过程中会进行常量折叠,在代码路径走到这里的时候通过StoreField操作将数组的长度直接赋值为-1:

由于是smi,所以是0xfffffffe:

打印数组长度:

这时超长的数组就出炉了,任由你玩了。从补丁对比上来看[4],对于ChangeInt32ToInt64将其输入作为有符号对待,这样就避免了该漏洞通过该路径触发。

关于利用的部分,基本是老套路,不再赘述。

参考链接:
[1] https://twitter.com/r4j0x00/status/1381643526010597380
[2] https://www.google.com/chrome/
[3] https://www.ecma-international.org/publications-and-standards/standards/ecma-262/
[4] https://chromium-review.googlesource.com/c/v8/v8/+/2820971/3/src/compiler/backend/x64/instruction-selector-x64.cc#1379


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1563/