Hacking Team Flash 0day漏洞学习笔记
生活随笔
收集整理的這篇文章主要介紹了
Hacking Team Flash 0day漏洞学习笔记
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
? ? ??周日的夜晚,與囧桑下載下來Hacking Team之前爆出的flash 0day漏洞,懷著緊張激動的心情,在自己的機子上做了實驗,經(jīng)測試,在我的虛擬機(一個sp3的XP,貌似沒裝Flash)上根本跑不出Flash漏洞,在我的Win10宿主機上跑,貌似剛升級的Flash,洞被補上了,也不能用。最后在囧桑的Win7機子上實驗,點擊了網(wǎng)頁上的按鈕,出現(xiàn)了測試用的程序--計算器。那一瞬間老激動了。
言歸正傳,下面開始Hacking Team的Flash 0day漏洞學(xué)習(xí)。感謝Hacking Team 公司的挖洞專家們這么敬業(yè),給了一個有注釋有README的項目,讓我這初學(xué)者表示可以慢慢啃了。 漏洞原理分析 漏洞成因在于Flash對ByteArray內(nèi)部的buffer使用不當(dāng),而造成了Use After Free漏洞,被釋放后的內(nèi)存區(qū)域可以立即被新創(chuàng)建的Vector對象重用,從而出現(xiàn)UaF漏洞。 漏洞利用代碼分析 MyClass類 核心類,用于觸發(fā)UaF漏洞。 MyClass1類 是ByteArray的子類,其中包含4個對象。 MyClass2類 是MyClass1類的子類,也是ByteArray的子類,有四個對象,且用重復(fù)且大量的屬性來擴充MyClass2類的大小。 本人新手,將對整個代碼進行分析,以免自己以后忘記。 首先是繪制整個flash區(qū)域的代碼。紅框框里將點擊事件與函數(shù)btnClickHandler進行綁定。 隨后看看這個btnClickHandler函數(shù)。 關(guān)鍵就是這個TryExpl函數(shù),它實際上就是觸發(fā)整個漏洞的關(guān)鍵,相當(dāng)于整個Flash利用程序的入口點。這個函數(shù)的主要目的是為了破壞Vector.<uint>的長度值,再接著查找破壞后的內(nèi)存區(qū)域,尋找受破壞的Vector對象,然后根據(jù)操作系統(tǒng)的位數(shù),以及操作系統(tǒng)的特征決定到底執(zhí)行哪個PayLoad代碼。 首先定義一個長為90的數(shù)組a,數(shù)組以3個元素為一組,元素1為一個MyClass2的實例,元素2為一個ByteArray即字符數(shù)組,當(dāng)new一個ByteArray時,AVM將會為數(shù)組分配0x1000大小的內(nèi)存(相當(dāng)于操作系統(tǒng)的內(nèi)存申請機制,每次申請大小為0x1000,為一個內(nèi)存區(qū)塊),隨后這個數(shù)組的長度設(shè)置為0xfa0。而a這個數(shù)組里將會有30個ByteArray數(shù)組。 ? ?? 然后數(shù)組a的末尾開始修改倒數(shù)第二個ByteArray,行為是將一個MyClass的對象賦給那個ByteArray的第四個元素,這個元素類型為Byte而MyClass是個對象,所以AVM會試圖將其轉(zhuǎn)化為Byte類型,從而調(diào)用MyClass類中的valueOf方法。 valueOf函數(shù)中new一個5個元素的數(shù)組_va,隨后修改靜態(tài)變量ByteArray數(shù)組_ba的長度為0x1100,這是關(guān)鍵,由于這個操作會觸發(fā)ByteArray的緩沖區(qū)buffer的重新分配(原來這個buffer長度為0xfa0,占地0x1000,現(xiàn)在長度要求為0x1100了,所以要重新分配內(nèi)存),舊的buffer區(qū)域被釋放。緊接著分配5個Vector.<uint>對象,每個對象長度為0x3f0,占地0x1000字節(jié),且Vector對象的長度值存儲于Vector緩沖區(qū)的前四位區(qū)域。這時分配的區(qū)域?qū)噲D使用之前已經(jīng)釋放的ByteArray _ba的內(nèi)存區(qū)域。而_va[x]指向的就是之前_ba的地址,且該地址仍然在這個函數(shù)的調(diào)用方的棧中存儲,即esi這個寄存器中存儲著_ba[3]的地址,而這個地址現(xiàn)在實質(zhì)上已經(jīng)指向了_va[?]這個Vector的第四位,返回的0x40就被寫到了這個內(nèi)存中了。隨后的_va[x]前四位如下所示。(具體哪個被分配到了_ba釋放的內(nèi)存不得而知,但是只有出現(xiàn)UaF的_va[x]才會出現(xiàn)異常的長度,從而被檢測。) _va[x]: ? ? f0 ? ? 03 ? ? 00 ? ? 00 ? ? => ? ? va[0]: ? ? f0 ? ? 03 ? ? 00 ? ? 40 那么以后再去讀取這個Vector的長度就會錯誤的返回一個超巨大的長度0x400003f0。? ? ? ?繼續(xù)對TryExpl進行分析,因為_ba[3]已經(jīng)指向在MyClass.valueOf里重新分配的區(qū)域,所以不出意外這里返回_ba[3]的值是0不會變化。接著對_va中的每個Vector.<uint>對象進行檢測,找到那個被我們剛才改了長度值的Vector的首地址。再接著令k等于1094,相當(dāng)于一個足夠遠離首地址的位置,檢查v[k]中的內(nèi)容是否為0x11223344,即該指針是否還處于MyClass2的范圍內(nèi),并逐漸接近Vector的首地址。當(dāng)找到非0x11223344的地址時,該區(qū)域就是MyClass2的a0這個變量的位置,這個位置為MyClass2的id。之后令這個位置為MyCLass2實例mc,改變mc的長度為0x123. ? ? ?隨后就是根據(jù)k走過的距離是不是大于30來確定是不是在64位系統(tǒng)上運行的程序,再確定系統(tǒng)類型,是win還是Mac來,32位還是64位。 ? ? ? PayLoad代碼分析- ? ? ?ShellWin64類 是MyClass的子類,是Win64上的PayLoad代碼,為的就是打開計算器程序。
- ? ? ?ShellMac64類 是MyClass的子類,是Mac上的PayLoad代碼,為的也是打開計算器程序。
- ? ? ?ShellWin32類 是MyClass的子類,是Win32上的PayLoad代碼,為的也是打開計算器程序。
?
Payload是個FunctionObject類型,最終對其調(diào)用call的時候最終到達FunctionObject::AS3_call,其內(nèi)部調(diào)用core()->exec->call跳轉(zhuǎn)到Payload對象JIT(Just In Time,即時編譯)出來的代碼。由于是FunctionObject和ExecMgr的繼承關(guān)系,可以通過自身結(jié)構(gòu)定位到ExeMgr的虛函數(shù)表。 在剛進入AS3_call時,ecx也就是隨后的esi指向了Payload對象,也就是esi=p(GetAddress(Payload))。參考上述匯編代碼中紅色字體部分,可知ExecMgr對象的虛函數(shù)表位于[[[[esi+8]+0x14]+4]+0xB0],偏移0處就是PayLoad的虛函數(shù)表,就是CallVP中的ptbl所指。后三行的三個Get指令表明,虛函數(shù)表的首地址ptbl的值存入p1中,需要執(zhí)行VirtualProtect的首地址存放于payload實際地址+0x1c位置,取出放于p2中,地址區(qū)域長度為xLen,存放于payload實際地址+0x20位置,取出存放于p3中。core->exec->call會牽涉一些其他虛函數(shù)的調(diào)用,所以以上CallVP對虛函數(shù)表上下共0x400字節(jié)全部備份。然后在被備份的那段內(nèi)存區(qū)域改寫0x1C處為VirtualProtect的地址,0x20處填寫需要改寫執(zhí)行權(quán)限的內(nèi)存區(qū)域地址長度。而args設(shè)置為一個存放了0x41個元素的數(shù)組(為什么是0x41,不該是0x40么,多個1不就是NO_access么)。 現(xiàn)在調(diào)用Payload.call就會跳轉(zhuǎn)到VirtualProtect執(zhí)行了。觀察上述的匯編代碼,core->exec->call(env,thisArg,argc,argv)和VirtualProtect(lpAddress,dwSize,flNewProtect,lpflOldProtect)一樣都是四個參數(shù)。其中argc和argv好理解,就是CallVP中調(diào)用Payload.call傳入的參數(shù)個數(shù)和參數(shù)所在數(shù)組,只要讓參數(shù)個數(shù)為0x40,flNewProtect就變成RWX,而argv本來只想存儲參數(shù)的可寫堆內(nèi)存,就不用管了(這里還是不清楚為什么上面的args的長度為0x41,這樣argc不就等于0x41了么,就不是執(zhí)行權(quán)限了啊),前兩個參數(shù)實際上是位于Payload對象的0x1c和0x20位置的,如下圖所示,其中左側(cè)為Payload對象的內(nèi)存,右側(cè)是core->exec->call()的棧。 如此一來,直接改寫Payload的內(nèi)存就可以控制VirtualProtect的參數(shù)了。代碼中的apply(null,args)就是call(null*0x41)。之所以是0x41個null而非0x40個null,是因為第一個null是調(diào)用者而不是參數(shù)。call(object,param1,param2...)等價于call.apply(object,new Array(param1,param2,...))。args按說完全是參數(shù)數(shù)組了,長度還要設(shè)置為0×41是因為apply的調(diào)用者為call,而object指針不會從apply向call傳遞。在call看來傳過來參數(shù)包含了object指針和參數(shù),所以數(shù)組的第一個參數(shù)就作為了object指針,也就是這種傳遞過程會吃掉一個參數(shù)。 調(diào)用VirtualProtect后再恢復(fù)修改過的虛函數(shù)表和Payload內(nèi)存就可以執(zhí)行shellcode了。 執(zhí)行Shellcode 上述執(zhí)行VirtualProtect的方法用于執(zhí)行shellcode也是可行的。但是人家偏不復(fù)用,非要換個方法,就是直接替換掉Payload的MethodEnv->Methodinfo里存儲的JIT后的代碼地址,這個與Core Security提出的繞過CFG方法相當(dāng)類似(見參考鏈接2)。 Payload對象中0x1C偏移的位置存儲了MethodEnv指針,而MethodEnv中的0x8偏移的位置指向了MethodInfo,而MethodInfo的0x4偏移的位置就是_implGPR,存儲了JIT后的代碼地址,所以調(diào)用Shellcode的代碼就變成了如下圖所示。 隨后替換了Payload函數(shù)對象中JIT后的代碼地址為shellcode的地址。 隨后對利用Payload.call進行shellcode的觸發(fā),但是上次是替換了ExecMgr的虛函數(shù)call,這次是直接替換了JIT后的代碼地址。JIT代碼的調(diào)用不在CFG監(jiān)測的范圍之內(nèi),而ExecMgr的虛函數(shù)表由于頻繁使用考慮性能也沒有CFG守護。(CFG:control flow guard控制流保護,見參考鏈接3)。 其實使用JIT的方法調(diào)用shellcode好處還在于,shellcode可以返回需要的結(jié)果,并讓ActionScript獲取指導(dǎo)下一步操作,比如EAX存儲了CreateProcessA的執(zhí)行結(jié)果,若返回前構(gòu)造一個這樣的代碼,就可以讓EAX轉(zhuǎn)化為atom。 1 04DDE32D SHL EAX,3 2 04DDE330 ADD EAX,6 3 04DDE333 LEAVE 4 04DDE334 RETN
?
當(dāng)執(zhí)行完call之后,AS3可以根據(jù)進程創(chuàng)建情況判斷沙箱的限制,來決定是否進一步部署內(nèi)核漏洞利用代碼進行提權(quán)。 結(jié)語 ? ??HackTeam的Flash Exploit在超長Vector獲取前的堆分布,獲得后的代碼執(zhí)行階段加入了不少獨辟蹊徑的技巧,對不同版本和操作系統(tǒng)的考量也讓利用代碼異常穩(wěn)定。只是如今隨著Adobe在18.0.0.209時引入了Vector內(nèi)存隔離和類似對抗JIT-Spray的長度異或校驗(見參考鏈接[4]),這套利用模板已經(jīng)不能走得更遠了。一整年的喧囂后,Flash大概也想清靜一下了。? 參考:轉(zhuǎn)載于:https://www.cnblogs.com/crazyDogge/p/4718047.html
總結(jié)
以上是生活随笔為你收集整理的Hacking Team Flash 0day漏洞学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell -nginx启动脚本
- 下一篇: javamail读取并发送完整的html