现代Chrome浏览器攻击:优化与反优化
引言
2019年底,我在Azimuth Security内部会议上介绍了通过JavaScript引擎攻击Chrome的研究工作。当时我重点研究了反优化机制,特别是反优化器中的漏洞。本文基于一年前为Azimuth Security撰写的内部技术报告,经授权后公开发布。
动机
相关提交
要理解这个安全漏洞,需要深入V8内部机制。首先分析修复提交:
|
|
该提交修复了src/compiler/simplified-lowering.cc中的VisitFrameState和VisitStateValues函数。
漏洞概述
这是TurboFan简化降低阶段处理FrameState和StateValues节点时的bug。这些节点与反优化相关。在代码生成阶段,TurboFan使用这些节点构建反优化输入数据。当运行时跳转到反优化器时,反优化器利用这些数据重建正确的执行帧。
通过此漏洞,可以使代码生成错误构建反优化输入数据,导致反优化器实例化伪造对象,并将执行重定向到使用任意对象指针的Ignition字节码处理器。
内部机制
Ignition解释器
概述
V8使用名为Ignition的解释器,它是基于寄存器的虚拟机。许多操作码使用累加器作为隐式操作数。每个操作码都有对应的处理程序,执行字节码主要是获取当前操作码并分派到正确的处理程序。
处理程序示例
|
|
调试技巧
启用ignition调试功能:
--trace-ignition:跟踪字节码执行--trace_feedback_updates:跟踪反馈向量更新
简化降低阶段
三个阶段
- 截断传播阶段:向后传播截断信息
- 类型传播阶段:向前传播类型反馈信息
- 降低阶段:实际降低节点并插入转换
节点处理示例
以SpeculativeNumberModulus节点为例,当两个输入都是无符号32位类型时,会调用VisitWord32TruncatingBinop,指示对前两个输入进行word32截断。
反优化机制
高级概述
反优化涉及多个V8组件:
- 指令选择:构建FrameState和StateValues节点描述符
- 代码生成:构建反优化输入数据(包括Translation)
- 反优化器:运行时将优化代码帧转换为解释器帧
反优化跟踪
使用--trace-deopt可以跟踪实际的反优化过程:
|
|
案例研究:错误的BigInt重新实例化
回到简化降低
FrameState节点期望6个输入,其中累加器输入的使用信息为UseInfo::Any()。对于BigIntAsUintN节点,输出表示为kWord64,类型为BigInt。
在简化降低阶段,累加器输入被替换为TypedStateValues节点,其MachineType计算为MachineType::AnyTagged()。这导致代码生成时将BigInt值当作指针处理。
实验1:读取任意堆数字
通过反优化到加法操作处理程序,可以实现任意堆数字读取:
|
|
实验2:获取任意对象引用
通过反优化到属性存储处理程序,可以实现任意对象引用:
|
|
变体分析
后续提交修复了类似问题:
- ObjectState节点的相同bug
- 表示转换器中的rematerialization问题
- 内联bug(缺少参数检查)
指针压缩的影响
V8 8.0引入指针压缩,Smi和压缩指针存储为32位值。这影响了利用策略,需要调整指针处理方式。
结论
本文深入分析了V8的多个组件:Ignition解释器、TurboFan简化降低阶段和反优化机制。虽然该漏洞提供了强大的原语,但缺乏信息泄露能力,需要与其他漏洞结合使用。
特别感谢V8团队构建了如此出色的JavaScript引擎!如需反馈或问题,欢迎通过Twitter联系。