qwb growupjs & wctf independence_day writeup
字数 1628 2025-08-04 08:17:33

V8引擎漏洞分析与利用:qwb growupjs & wctf independence_day

1. qwb growupjs漏洞分析

1.1 漏洞概述

这是一个V8引擎中的Uint32LessThan操作符优化错误导致的数组越界漏洞。漏洞存在于src/compiler/machine-operator-reducer.cc文件中,具体表现为:

if (m.IsFoldable()) {                                    // K < K => K
  return ReplaceBool(m.left().Value() < m.right().Value() + 1);
}

正常情况下,比较1 < 1应该返回false,但经过这个修改后会变成比较1 < 2而返回true,导致数组边界检查失效。

1.2 IR分析

1.2.1 正常情况分析

对于正常数组访问:

function main() {
    let arr = [1.1, 2.2, 3.3, 4.4];
    let idx = 3;
    return arr[idx];
}

V8会生成以下关键IR节点:

  1. CheckBounds节点检查索引是否在数组范围内
  2. 在Simplified Lowering阶段转换为CheckedUint32Bounds
  3. 在Effect Linearization阶段转换为Uint32LessThan

1.2.2 边界情况分析

对于越界访问:

function main() {
    let arr = [1.1, 2.2, 3.3, 4.4];
    let idx = 4;
    return arr[idx];
}

V8会:

  1. 引入CheckBounds节点检查索引是否超过Smi::kMaxValue
  2. 生成NumberLessThan节点比较索引和数组长度
  3. 在TyperNarrowingReducer阶段,由于索引类型为(4,4),数组长度类型为(4,4),满足left_type.Min() >= right_type.Max()
  4. NumberLessThan被折叠为false节点

1.3 漏洞利用方法

1.3.1 绕过类型折叠

通过位操作使索引类型不被折叠:

function main() {
    let arr = [1.1, 2.2, 3.3, 4.4];
    let idx = 4;
    idx = idx & 0xffff;  // 使索引类型变为(0,4)
    return arr[idx];
}

1.3.2 完整利用步骤

  1. 分配两个数组:一个double数组,一个object数组
  2. 通过漏洞覆盖object数组的map为double map,泄露对象地址
  3. 在array elements区域伪造一个arraybuffer
  4. 将double数组的map覆盖为object数组map,取出伪造的arraybuffer
  5. 利用伪造的arraybuffer进行任意地址读写
  6. 找到wasm函数中的rwx内存区域,写入并执行shellcode

2. wctf independence_day漏洞分析

2.1 漏洞概述

该漏洞源于V8禁用了code dependencies机制(第一个patch),同时禁用了wasm利用方式(第二个patch)。具体修改在src/objects/code.cc中:

void DependentCode::InstallDependency(Isolate* isolate,
                                    const MaybeObjectHandle& code,
                                    Handle<HeapObject> object,
                                    DependencyGroup group) {
#if 0  // 禁用了依赖安装
    // 原有代码...
#endif
}

2.2 IR分析

2.2.1 非stable map情况

对于非stable map的数组访问,V8会插入CheckMaps节点到effect chain中进行检查。

2.2.2 stable map情况

对于stable map的数组访问,正常情况下会注册compilation dependencies回调到map中。但由于漏洞patch禁用了这个机制,导致没有类型检查,产生type confusion。

2.3 漏洞利用方法

2.3.1 PoC构造

arr = [1.1, 2.2, 3.3,4.4];
// 使map变为stable
arr.x = 1;

function foo(idx) {
    return arr[idx];
}

// 优化函数
for (i = 0; i < 100000; i++){
    foo(1);
}

// 改变arr为dictionary map
arr[0x100000] = 5.5;
console.log(foo(1000));  // 触发越界访问

2.3.2 替代wasm的利用方法

由于wasm被禁用,可以采用以下方法构建ROP链:

  1. 从堆中泄露二进制指针
  2. 从IAT读取kernel32指针
  3. 从kernel32的IAT读取kernelbase指针
  4. KERNELBASE!BasepCurrentTopLevelFilter+8处找到存储的栈指针
  5. 构建ROP链实现利用

3. 总结

这两个漏洞展示了V8引擎中不同类型的漏洞模式:

  1. qwb growupjs:展示了编译器优化过程中引入的边界检查错误,通过IR分析理解漏洞触发条件,并利用位操作绕过类型系统的保护。

  2. wctf independence_day:展示了依赖系统被禁用导致的类型混淆漏洞,通过改变对象布局绕过优化编译器假设。

两种漏洞都最终实现了内存任意读写,但采用了不同的后续利用策略,反映了现代JavaScript引擎漏洞利用的多样性和复杂性。

V8引擎漏洞分析与利用:qwb growupjs & wctf independence_ day 1. qwb growupjs漏洞分析 1.1 漏洞概述 这是一个V8引擎中的Uint32LessThan操作符优化错误导致的数组越界漏洞。漏洞存在于 src/compiler/machine-operator-reducer.cc 文件中,具体表现为: 正常情况下,比较 1 < 1 应该返回 false ,但经过这个修改后会变成比较 1 < 2 而返回 true ,导致数组边界检查失效。 1.2 IR分析 1.2.1 正常情况分析 对于正常数组访问: V8会生成以下关键IR节点: CheckBounds 节点检查索引是否在数组范围内 在Simplified Lowering阶段转换为 CheckedUint32Bounds 在Effect Linearization阶段转换为 Uint32LessThan 1.2.2 边界情况分析 对于越界访问: V8会: 引入 CheckBounds 节点检查索引是否超过 Smi::kMaxValue 生成 NumberLessThan 节点比较索引和数组长度 在TyperNarrowingReducer阶段,由于索引类型为(4,4),数组长度类型为(4,4),满足 left_type.Min() >= right_type.Max() NumberLessThan 被折叠为 false 节点 1.3 漏洞利用方法 1.3.1 绕过类型折叠 通过位操作使索引类型不被折叠: 1.3.2 完整利用步骤 分配两个数组:一个double数组,一个object数组 通过漏洞覆盖object数组的map为double map,泄露对象地址 在array elements区域伪造一个arraybuffer 将double数组的map覆盖为object数组map,取出伪造的arraybuffer 利用伪造的arraybuffer进行任意地址读写 找到wasm函数中的rwx内存区域,写入并执行shellcode 2. wctf independence_ day漏洞分析 2.1 漏洞概述 该漏洞源于V8禁用了code dependencies机制(第一个patch),同时禁用了wasm利用方式(第二个patch)。具体修改在 src/objects/code.cc 中: 2.2 IR分析 2.2.1 非stable map情况 对于非stable map的数组访问,V8会插入 CheckMaps 节点到effect chain中进行检查。 2.2.2 stable map情况 对于stable map的数组访问,正常情况下会注册compilation dependencies回调到map中。但由于漏洞patch禁用了这个机制,导致没有类型检查,产生type confusion。 2.3 漏洞利用方法 2.3.1 PoC构造 2.3.2 替代wasm的利用方法 由于wasm被禁用,可以采用以下方法构建ROP链: 从堆中泄露二进制指针 从IAT读取kernel32指针 从kernel32的IAT读取kernelbase指针 在 KERNELBASE!BasepCurrentTopLevelFilter+8 处找到存储的栈指针 构建ROP链实现利用 3. 总结 这两个漏洞展示了V8引擎中不同类型的漏洞模式: qwb growupjs :展示了编译器优化过程中引入的边界检查错误,通过IR分析理解漏洞触发条件,并利用位操作绕过类型系统的保护。 wctf independence_ day :展示了依赖系统被禁用导致的类型混淆漏洞,通过改变对象布局绕过优化编译器假设。 两种漏洞都最终实现了内存任意读写,但采用了不同的后续利用策略,反映了现代JavaScript引擎漏洞利用的多样性和复杂性。