這段時間最火的漏洞當屬阿聯酋的人權活動人士被apt攻擊所使用的iOS PEGASUS(又稱Trident三叉戟)0day漏洞了。爲了修復該漏洞,蘋果專門發佈了一個iOS 9.3.5版本。這個漏洞的厲害之處在於能夠直接從沙盒內對內核進行攻擊(無需沙盒逃逸),而且同時影響iOS(9.3.4)和OS X (10.11.6)。所以,本篇文章將會從PEGASUS漏洞造成的緣由開始分析,而後一步一步教你們寫出OS X上利用PEGASUS提權的攻擊代碼。html
《iOS冰與火之歌》這一系列文章的目錄以下:ios
Objective-C Pwn and iOS arm64 ROPgit
在非越獄的iOS上進行App Hook(番外篇)github
App Hook答疑以及iOS 9砸殼(番外篇)api
利用XPC過App沙盒安全
UAF and Kernel PWNide
基於PEGASUS(三叉戟)的OS X 10.11.6本地提權 (番外篇)函數
另外文中涉及代碼可在個人github下載: https://github.com/zhengmin19...測試
PEGASUS(三叉戟)其實是由三個漏洞組成,分別是:ui
CVE-2016-4657:Safari的Webkit內核上的內存破壞漏洞。
CVE-2016-4655:內核信息泄露漏洞,可用於繞過KASLR。
CVE-2016-4656:內核UAF漏洞,可用於控制內核並執行任意代碼。
關於CVE-2016-4657目前尚未公開的資料,但Stefan Esser和Pangu分別爆出了另外兩個漏洞CVE-2016-4655和CVE-2016-4656的細節。利用已經曝光的這兩個漏洞,其實已經能夠作到iOS非完美越獄和OS X本地提權了。下面咱們就來說解一下這兩個漏洞造成的緣由以及如何利用。
CVE-2016-4655這個漏洞造成的緣由是內核在序列化和反序列化OSNumber的時候沒有驗證長度的正確性。所以,若是咱們將number的長度設置的很是長,並用io_registry_entry_get_property()去獲取number數據的話,就會形成內核的信息泄露。
咱們知道內核棧中會保存函數的返回地址,所以咱們能夠利用這個返回地址去計算出內核的kslide,從而攻破kaslr的保護。
那麼如何編寫利用代碼呢?咱們先建立一個序列化後的dictionary。對內核來講,這個dictionary應該是這樣的:
<dict> <key>min</key> <number>0x4141414141414141</number> </dict>
可是咱們對OSNumber的長度進行了修改,變成了0x200:
uint32_t data[] = { 0x000000d3, 0x81000001, 0x08000004, 0x006e696d, 0x84000200, //change the length of OSNumber 0x41414141, 0x41414141 };
發送這個給內核後,內核在反序列化的時候就會出現錯誤。隨後咱們使用io_registry_entry_get_property_bytes()這個用戶態函數就能夠獲取到內核返回的數據了。
由於咱們修改了OS number的長度,因此返回的數據不光有咱們發送給內核的number,還有棧上數據,好比函數ret時候的返回地址-0xFFFFFF80003934BF。
經過這個地址咱們就能夠計算出來kslide了。
CVE-2016-4656這個漏洞其實有兩種觸發UAF的方法,咱們這裏先講比較簡單的那一種(兩種方法在Stefan Esser的文章中都有介紹)。簡單UAF漏洞造成的緣由是OSUnserializeBinary支持用OSString和OSSymbol來做爲key,而且支持用OSObject去引用以前的key。可是OSString和OSSymbol不同的地方在於,OSString key轉換爲OSSymbol的過程當中OSString已經被free掉了,但這個OSString卻被加入了對象列表裏。
所以當咱們OSObject類型去引用一個已經被釋放了的OSString的時候,就會產生UAF崩潰:
經過彙編崩潰的位置咱們能夠找到源碼對應的位置是在341行建立OSObject對象的時候:
所以,若是咱們可以在OSString被free的時候,馬上申請一段和OSString同樣大小的內存而且構造好對應的vtable數據,當程序執行到OSObject建立的時候,內核就能成功的被咱們控制。
那麼如何編寫利用代碼呢?咱們仍是先建立一個序列化後的dictionary。對內核來講,這個dictionary應該是這樣的:
<dict> <string>A</string> <bool>true</bool> <key>B</key> <data>vtable data...</data> <object>1</object> </dict>
內核隨後會解析這個dictionary,正如咱們以前分析的,OSString-」A」在建立完後就被free掉了,這時候,咱們馬上建立OSSymbol-」B」以及和OSString-」A」大小相同的OSData,就能夠在OSString-」A」 free後從新控制這塊內存,隨後當內核使用OSObject引用OSString-」A」,並調用retain()函數的時候,其實就是在調用咱們已經控制的vtable了。
首先咱們先申請一塊內存來放vtable和ROP chain,在OS X上有一種取巧的方法,若是咱們是32位的程序的話,可使用NULL page。所以,咱們先用vm_allocate()申請到NULL Page,而後將vtable和ROP chain都保存在NULL page裏:
隨後在OS X上用rop提權的代碼咱們能夠直接使用tpwn的:首先得到當前進程的ucred,而後將cr_svuid設置爲0,最後用thread_exception_return退出進程。
編寫完代碼後,咱們來嘗試執行一下咱們的exp。
首先說一下測試環境:Mac OS X EI Capitan 10.11.6 (15G31),在沒有安裝2016-01的security update的狀況下(這時候內核至關於iOS 9.3.4,若是安裝完2016-01 update就至關於iOS 9.3.5)。
接下來咱們編譯一下咱們的exp:
clang -framework IOKit -framework Foundation -framework CoreFoundation -m32 -Wl,-pagezero_size,0 -O3 exp.m lsym.m -o exp
而後運行:
能夠看到咱們已經成功的獲取了root權限。
這篇文章介紹瞭如何利用PEGASUS(Trident三叉戟)作到內核信息泄露以及內核代碼執行,而後利用rop獲取root權限。另外,由於PEGASUS(Trident三叉戟)同時存在於iOS和OS X,有興趣的同窗能夠在咱們發佈的攻擊代碼的基礎上,嘗試一下iOS攻擊代碼的編寫。
基於PEGASUS(Trident三叉戟)的OS X 10.11.6本地提權exp的下載地址:https://github.com/zhengmin19...