日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Hacking Team Flash 0day漏洞学习笔记

發布時間:2024/4/15 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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代碼,為的也是打開計算器程序。
ShellWin32 首先觀察ShellWin32的初始化操作,v是中間被我們修改的Vector向量,而v[k]則是MyClass2中的變量a0,那么v[k-4]則是MyClass2中的o1,即該MyClass2對象的實際地址,與0xfffff000相與可以獲得其前5位即該MyClass2對象所在的0x1000塊的首地址,這時減去0x1000就獲得了中間Vector的首地址,再加上8則是跳過了Vector頭部的8位到達了Vector中存儲值的首地址,即v[0]的實際地址,接著將該實際地址存入vAddr中。 這個vAddr作為實際地址相當有用。 通過v[(address-vAddr)>>>2]就可以訪問任意地址內存了,這個在ShellWin32中被封裝成了Get。 通過mc.o1=obj ;返回v[k-4]-1就可以返回任意對象的絕對地址了。即先將obj放入到MyClass2的o1中,再去讀取o1這個位置中的值,該值減一就是該對象的絕對地址。這個也在ShellWin32中被封裝成了GetAddr。 首先初始化,將一些參數存入ShellWin32的內部變量中,隨后通過驗證v[vAddr-8]位置存儲的值和v中的長度是否一致,確保傳入的v和vAddr是否匹配。 隨后進入執行函數。 第一部分是獲取shellcode這個Vector.<uint>對象的首地址,隨后獲取shellcode中的數據區地址。其中的_isDbg在MyClass中定義。 其中Vector實際存儲的緩沖區指針,即真正的shellcode位置在Release和Debug版分別放置于0x18和0x1c的位置。為了顧全所有版本,還注意到Flash11.4版本之前是不存在這個便宜區別的,11.4之后的Debug版才在緩沖區指針前加入了一個0x00000001字段。下圖中是Vector的內存分布,左側是11.4之前的Release和Debug,右側是11.4以后的Release和Debug。不得不說HackTeam寫代碼為了保證向后兼容以及針對Release和Debug版本,也是做了很多工作的。 開啟ShellCode執行權限 隨后進入獲得kernel32.VirtualProtect()地址的流程。 進入FindVP函數。 b是dll或者exe文件中的虛函數表指針。將b指針對齊0x10000,再減去0x400000,隨后減去_vAddr得到PE文件頭部,看看DOS_HEADER,(真的嗎,我也不清楚這里為何如此,有人知道的話請給我留言,么么噠~),隨后一路推導到達NT_HEADER,獲得了IMPORT_DIRECTORY導入目錄,在導入目錄中尋到了kernel32.dll。 隨后再在kernel32.dll中找到了VirtualProtect API的地址。 接著調用VirtualProtect開啟shellcode這段區域的執行權限。 首先生成一個FunctionObject類的對象Payload,然后獲得該對象的地址。隨后的一段比較難以理解。剛開始以為要把AS3里的許多結構體都擼明白才能算出偏移,其實沒這么蛋疼,看看Flash中的FunctionObject::AS3_call就全明白了。 1 int AS3_call(void *this, int thisArg, int *argv, int argc) 2 push ebx 3 push esi 4 mov esi, ecx 5 mov ecx, [esp+8+thisArg] 6 mov eax, [esi] 7 mov edx, [eax+8Ch] 8 push edi 9 push ecx 10 mov ecx, esi 11 call edx 12 mov ebx, eax 13 mov eax, [esi+8] 14 mov ecx, [eax+14h] 15 mov edx, [ecx+4] 16 mov eax, [esi] 17 mov edi, [edx+0B0h] 18 mov edx, [eax+90h] 19 lea ecx, [esp+0Ch+thisArg] 20 push ecx 21 mov ecx, esi 22 call edx 23 mov ecx, [esp+0Ch+argv] 24 mov eax, [eax] 25 mov edx, [edi] 26 mov edx, [edx+1Ch] 27 push ecx 28 mov ecx, [esp+10h+argc] 29 push ecx 30 push ebx 31 push eax 32 mov ecx, edi 33 call edx 34 pop edi 35 pop esi 36 pop ebx 37 retn 0Ch

?



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大概也想清靜一下了。? 參考:
  • http://www.freebuf.com/vuls/73074.html
  • https://blog.coresecurity.com/2015/03/25/exploiting-cve-2015-0311-part-ii-bypassing-control-flow-guard-on-windows-8-1-update-3/
  • http://drops.wooyun.org/tips/4839
  • http://googleprojectzero.blogspot.com/2015/07/significant-flash-exploit-mitigations_16.html
  • 轉載于:https://www.cnblogs.com/crazyDogge/p/4718047.html

    總結

    以上是生活随笔為你收集整理的Hacking Team Flash 0day漏洞学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。