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节点:
CheckBounds节点检查索引是否在数组范围内- 在Simplified Lowering阶段转换为
CheckedUint32Bounds - 在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会:
- 引入
CheckBounds节点检查索引是否超过Smi::kMaxValue - 生成
NumberLessThan节点比较索引和数组长度 - 在TyperNarrowingReducer阶段,由于索引类型为(4,4),数组长度类型为(4,4),满足
left_type.Min() >= right_type.Max() 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 完整利用步骤
- 分配两个数组:一个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中:
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链:
- 从堆中泄露二进制指针
- 从IAT读取kernel32指针
- 从kernel32的IAT读取kernelbase指针
- 在
KERNELBASE!BasepCurrentTopLevelFilter+8处找到存储的栈指针 - 构建ROP链实现利用
3. 总结
这两个漏洞展示了V8引擎中不同类型的漏洞模式:
-
qwb growupjs:展示了编译器优化过程中引入的边界检查错误,通过IR分析理解漏洞触发条件,并利用位操作绕过类型系统的保护。
-
wctf independence_day:展示了依赖系统被禁用导致的类型混淆漏洞,通过改变对象布局绕过优化编译器假设。
两种漏洞都最终实现了内存任意读写,但采用了不同的后续利用策略,反映了现代JavaScript引擎漏洞利用的多样性和复杂性。