zoukankan      html  css  js  c++  java
  • CVE-2013-3893(IE、UAF实例分析)

    POC代码&crash

    POC

    crash
    crash

    这里的一个小技巧是,使用js里的三角函数公式插入原POC文件,使调试能够以一句html语句为粒度进行调试。具体做法是

    bp jscript!sin
    bp jscript!cos
    bp jscript!tan
    

    每次命中断点说明即将调试下一句代码

    分析

    从第一行开始逐语句进行分析

    document.createElement("sup");
    

    参考freebuf分析的原文说

    在CDocument::createElement下断,获取ld_0和ld_1的element对象地址。

    理解一下在这里下断点的原因是:document是一个类,在IE内部表示为CDocument,再根据函数名,顾名思义很容易理解在CDocument::createElement下断点。然而,给出的图却是断在了mshtml!CElement::CElement函数,从这里得到了element对象地址。这该怎么理解呢?只能理解为在CDocument::createElement函数内部又调用了mshtml!CElement::CElement函数。根据原文贴图的堆栈调用可以验证上述猜想。

    根据上图,断在682a482d,那么edi就是新创建的element的地址,为什么edi是新创建的element的地址?先看代码

    mshtml!CElement::CElement:
    682a480f 8bff            mov     edi,edi
    682a4811 55              push    ebp
    682a4812 8bec            mov     ebp,esp
    682a4814 53              push    ebx
    682a4815 8b5d0c          mov     ebx,dword ptr [ebp+0Ch]
    682a4818 56              push    esi
    682a4819 57              push    edi
    682a481a 8bf8            mov     edi,eax
    682a481c 8bf7            mov     esi,edi
    682a481e e80c300800      call    mshtml!CBase::CBase (6832782f)
    682a4823 83672400        and     dword ptr [edi+24h],0
    682a4827 c707b0541668    mov     dword ptr [edi],offset mshtml!CElement::`vftable' (681654b0)
    682a482d 8b03            mov     eax,dword ptr [ebx] 
    

    想了一下原因,在地址682a4827,把CElement类的虚函数指针赋值给了[edi],根据C++类的相关概念,那么不就说明了这是一个element类在初始化吗?想想当前函数名称CElement::CElement,这样我们就想通了为什么在这儿下断点edi就指向我们创建的element。

    同时也得出一点心得:element在IE中是一个独立的类CelementCdocument类创建一个element,也就是实例化了一个Celement对象。

    在我的调试中

    id0 = 070a7fd8
    id1 = 05bd1fc8
    
    • appendChild分析
    	document.body.appendChild(id_0);
    	document.body.appendChild(id_1);
    

    CElement::appendChild下断。推测这样下断点的原因是因为document.body也是属于CElement类。CElement::appendChild函数递归调用了CTreeNode::CTreeNode函数,返回值是id0对应的CTreeNode对象

    堆栈回溯

    0:005> kb 8
    ChildEBP RetAddr  Args to Child              
    0460e0f8 672d0d02 06e63fb0 00000000 05c2af30 mshtml!CTreeNode::CTreeNode
    0460e198 672b1c01 05c2af30 070a7fd8 0460e1bc mshtml!CMarkup::InsertElementInternal+0x23d
    0460e1d4 672b1b36 070a7fd8 00000000 00000001 mshtml!CDoc::InsertElement+0x8a
    0460e268 672b2222 00000000 0460e284 0460e3b8 mshtml!CCommentElement::`scalar deleting destructor'+0x23e
    0460e2d0 672b2148 08e5bfd8 00000000 0460e30c mshtml!CElement::InsertBeforeHelper+0xd1
    0460e2ec 672b20fe 06cdcfd0 08e5bfd8 00000001 mshtml!CElement::insertBefore+0x3c
    0460e32c 672b1436 06cdcfd0 08e5bfd8 0460e3b8 mshtml!CElement::appendChild+0x3a   //----> CElement::appendChild
    

    id0对应的CTreeNode=(05de4fb0),第一个成员就是id0的实例化对象

    0:005> dc eax
    05de4fb0  070a7fd8 06e63fb0 ffff0060 ffffffff  .....?..`.......
    05de4fc0  00000000 00000000 00000000 00000000  ................
    

    id1 CTreeNode(08eeafb0)

    0:005> dc eax
    08eeafb0  05bd1fc8 06e63fb0 ffff0075 ffffffff  .....?..u.......
    08eeafc0  00000000 00000000 00000000 00000000  ................
    
    • 什么又是CTreeNode对象?

    表示DOM中element之间的父子关系的树。appendChild将元素插入了DOM树中。

    • 再回头看element

    id0 element

    0:005> dc 070a7fd8
    070a7fd8  671b70e0 00000002 00000008 00000000  .p.g............
    070a7fe8  05d1af00 05de4fb0(id0 CTreeNode) 00000060 00010200  .....O..`.......
    

    id1 element

    05bd1fc8  671dc2e8 00000002 00000008 06d7afe8  ...g............
    05bd1fd8  05d1aed0 08eeafb0(id1 CTreeNode) 00000075 00010200  ........u.......
    
    

    id0,id1,0x14偏移处05de4fb0,08eeafb0是对应的CTreeNode

    • applyElement分析
    id_1.applyElement(id_0);
    

    类似于document.body.appendChild,也是改变element之间的父子关系。查找文档

    applyElement方法
    语法:
    object.applyElement ( oElement , sWhere )
    参数:
    oElement :  必选项。对象(Element)。要被添加的对象。
    sWhere :  可选项。字符串(String)。(outside:默认值)。将 oElement 添加为 object 的父对象。
    

    mshtml!CElement::applyElement下断,在jscript!cos断下后继续运行,断在了applyElement,如图看到和appendChild的堆栈回溯差不多,new了一个CTreeNode。然而这个CTreeNode的第一个成员指向了id0的element。

    调试截图

    再回头看之前的id0,id1的CTreeNode。发现id0的CTreeNode已经release掉了。id1没有realse。


    那么也就是说id0换了新的CTreeNode(07079fb0)。

    根据说明,现在id0是id1的树的父节点。对比前后的图,可以发现CTreeNode偏移0x4处,是指向父节点CTreeNode的指针。因为id1的CTreeNode现在指向id1的CTreeNode。进步一说明之前id0,id1偏移0x4处的06e63fb0就是body元素的CTreeNode。

    接下来是一个设置,ld0的onlosecapture(失去聚焦时执行的函数),页面清空。

    再下来这句id_0[‘outerText’]="";,这个执行之后id0会从DOM树脱离下来。Id1作为子节点也会脱离DOM树。


    id0,id1CTreeNode释放了

    0:005> dc 07079fb0
    07079fb0  ???????? ???????? ???????? ????????  ????????????????
    07079fc0  ???????? ???????? ???????? ????????  ????????????????
    0:005> dc 08eeafb0
    07079fb0  ???????? ???????? ???????? ????????  ????????????????
    07079fc0  ???????? ???????? ???????? ????????  ????????????????
    

    此时element(备用)

    0:005> dc 070a7fd8
    070a7fd8  671b70e0 00000005 00000010 08ed4fe8  .p.g.........O..
    070a7fe8  05d1af01 05ca9fb0 80000060 8a010200  ........`.......
    070a7ff8  00000002 05c2af30 ???????? ????????  ....0...????????
    070a8008  ???????? ???????? ???????? ????????  ????????????????
    070a8018  ???????? ???????? ???????? ????????  ????????????????
    070a8028  ???????? ???????? ???????? ????????  ????????????????
    070a8038  ???????? ???????? ???????? ????????  ????????????????
    070a8048  ???????? ???????? ???????? ????????  ????????????????
    0:005> dc 05bd1fc8
    05bd1fc8  671dc2e8 00000001 00000008 06d7afe8  ...g............
    05bd1fd8  05d1aed0 00000000 80000075 80010000  ........u.......
    05bd1fe8  00000002 08f86fe8 08e12ff4 00000000  .....o.../......
    05bd1ff8  00000000 00000000 ???????? ????????  ........????????
    05bd2008  ???????? ???????? ???????? ????????  ????????????????
    05bd2018  ???????? ???????? ???????? ????????  ????????????????
    05bd2028  ???????? ???????? ???????? ????????  ????????????????
    05bd2038  ???????? ???????? ???????? ????????  ????????????????
    
    • CDoc::SetMouseCapture分析
      接下来,关键点
        id_0.setCapture();
        id_1.setCapture();
    

    首先,先看看crash时的堆栈调用

    堆栈调用显示在CDoc::PumpMessage+0x3e4调用的CDoc::HasContainerCapture+0x14语句中出现的error.

    重新运行程序在CDoc::SetMouseCapture函数下断,然后不断g,发现了有意思的事情。因为tan函数,可以知道,第一次id_0.setCapture();时,只断下来一次;在id_1.setCapture();时,在crash之前却断下来3次。说明2次的执行流程并不相同,第一次正常,第二次可能会有些问题所以出现了crash。并且,在第二次的执行流程中,断下来3次,根据堆栈调用的情况来看,在id_1.setCapture();函数返回之前,向下又调用了CDoc::SetMouseCapture函数。

    在IDA里看到函数CDoc::SetMouseCapture,分析一下这个函数

    CDoc::SetMouseCapture函数的前2个参数由eax,ecx传参,根据动态调试,eax在2次断下时先后为id0,id1的element地址。在IDA中命名为有意义的形参名。

    因为2次调用lpMem都是同一个地址,且eax值非空,所以都进入LABEL_33.接下来

    到了这里,情况有所不同,v11的值在id0时为空,在id1时非空。在id1非空后,创建CMessage对象,进入CDoc::PumpMessage函数。其中有函数CDoc::ReleaseDetachedCaptures,这个函数再一次以eax=0为参数调用了CDoc::SetMouseCapture函数。

    因为eax=0,执行

    这句是清除capture,因为id1设置capture没有完成,所以此时是清除id0的capture,这样会触发id_0.onlosecapture设置的处理语句--清空整个页面--带来的影响是会对所有element都release掉。包括CBodyelement

    进入CDoc::ReleaseDetachedCaptures前

    06e63fb0 是CBodyelement的CTreeNode

    从CDoc::ReleaseDetachedCaptures返回后

    此时好奇这个[esp+10h]=06e63fb0是怎么来的,通过下内存写断点发现是从后面的地址跳过来的,和我看到的xp的分析不太一样

    然后再接着执行几步

    把已经释放了的CBodyelement的CTreeNode给edi,传递给函数CDoc::HasContainerCapture。所以出现这样的crash

    mshtml!CDoc::HasContainerCapture+0x14:
    673c1f60 8b0f            mov     ecx,dword ptr [edi]  ds:0023:06e63fb0=????????
    
  • 相关阅读:
    基于apache httpclient 调用Face++ API
    布隆过滤器(BloomFilter)持久化
    布隆过滤器
    基于firebird的数据转存
    kafka和rabbitmq对比
    python操作rabbitmq
    TCP窗口
    python操作kafka实践
    python使用etcd
    快速排序的python实现
  • 原文地址:https://www.cnblogs.com/Lnju/p/5260820.html
Copyright © 2011-2022 走看看