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