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