针对网页木马(CVE-2011-1260)的分析与实践(1)
本文假设你对漏洞挖掘,漏洞分析,汇编这些不太了解,但是对C,C++有一定了解。首先我们找一个具体的公开的例子——CVE-2011-1260,释放后重用漏洞。首先我们上网找一下这个漏洞的POC,得到如下运行环境XP SP3,IE8,开启DEP稍后解释什么是DEP)):
- <html>
- <body>
- <script language=;javascript;>
- document.body.innerHTML+="<object hspace=;1000; width=;1000;>TAG_1</object>";
- document.body.innerHTML+="<a id=;tag_3; style=;bottom:5000px;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px; >TAG_3</a>";
- document.body.innerHTML += "AAAAAAA";
- document.body.innerHTML+="<strong style=;font-size:1000pc;margin:auto -25000px auto auto;; dir=;ltr;>TAG_11</strong>";
- </script>
- </body>
- </html>
0×1 漏洞分析
我们双击打开,发现IE崩溃了,到底是什么原因呢?
我们用windbg附加进程调试IE最好还是用微软的调试器,毕竟微软主场):附加后,按g,回车,如果限制了activeX控件运行,就按允许,然后windbg在崩溃的时候停止了:
从eax+70的地址取出数据,显然这个地址不合法,所以导致错误。我们按knL回车,从栈查看函数的调用情况:
不清楚栈的看这里,清楚的跳过:函数调用有很多种,这里指stdcall,在每一次调用之前,都会将参数压栈,从右到左,比如Void Aint a,int b),汇编就类似push,push,call,Call指令会将call指令的下一条指令的地址压栈,所以最后栈看起来是这样的:注意,压栈是从高往低压)
对应源代码:
所以我们从栈中可以看出崩毁之前调用过什么函数,以及现在在什么函数里面,函数返回地址等等很多信息。
这里我们可以看到是在CElement::Doc函数里面崩毁,看看附近的汇编指令:
取ecx地址的内容返回给eax,但是eax是0,导致后来的内存读取错误,显然ecx出了问题。一般情况下,在thiscall中,第一个参数是this指针(用ecx传递),而对象+0x0h的地方储存的是虚函数表的地址,所以可得这里是取虚函数表偏移0×70的地方的虚函数指针,再调用这个虚函数。
显然这里的ecx就是CElement对象,这个对象是IE里面很多元素的父类,如(CObjectElement,对应<object>标签,CImgElement,对应<img>标签等等),而我们从POC中可以看出我们生成了一个<object>标签,所以我们可以推断这个是CObjectElement对象,那么这个对象从哪里来的呢?再看进入这个函数之前的汇编代码:
取ebx地址的内容给ecx,那么ebx哪里来?我们用ida反汇编这个函数看看在mshtml.dll)
Ebx就是this指针,即ebx指向的地方就是CTreeNode,然后CTreeNode对象+0x0h的地方传给ecx(即偏移0x0h保存了对应的CElement指针),再传入CElement::Doc。那么CTreeNode和CElement有什么关系呢?
我们重新运行,然后定如下两个断点:
- bu mshtml!CObjectElement::CreateElement+0x18 ".printf \"[%08x]\\n\",eax;g"
在mshtml!CObjectElement::CreateElement+0×18出断下,并且打印eax的值,然后继续运行。从文字可以看出这个是构造CObjectElement的函数,里面会调用CObjectElement的构造函数,eax一般是函数返回的值,即这个对象的指针。
函数中分配了一个0xDC的堆,显然这是这个对象的大小。
- bu mshtml!CTreeNode::CTreeNode+0x8c ".printf \"allocated CTreeNode at %08x, ref to CElement %08x of tbale %08x\\n\", eax, poi(eax), poi(poi(eax));dds poi(eax) L 1;g"
这个断点是在CTreeNode+0x8c地方断下,打印对象指针,对应的CElement指针(CTreeNode+0×0处保存对应CElement对象),以及对应的CElement对象的虚函数表地址。
定好断点,GO!
从图可以看出,最后创建了一个CObjectElement对象在00201c30,然后立马又创建了与之对应的CTreeNode对象0338aa18,到了程序崩毁的地方,ebx(即CTreeNode对象)还是0338aa18,但是与之对应的CObjectElement对象(ecx)却改变了。
我们看00201c30的地方:
这里已经不是CObjectElement的虚函数表,说明这个对象已经被释放,所以与之对应的CTreeNode也在崩溃之前释放了,所以这里CTreeNode+0×0的CObjectElement指针也是错误的,所以指向的地方是00000000,然后读取虚函数表出错。我们定下断点:
- bu mshtml!CTreeNode::Release+0x19 ".printf \"freeing CTreeNode at %08x, CElement at %08x, of table %08x\\n\", edx, poi(edx), poi(poi(edx)); g"
这里可以看出,在IE崩溃前,CTreeNode已经释放了,然后崩溃时又引用了这个对象对应的CElement对象,然后call虚函数,导致程序出错。为什么会释放呢?因为<object>标签没指明clsid值,所以IE会释放这个标签,那么接下来我们可以干什么呢?
