亚洲日本免费-啊轻点灬太粗太长了三男一女-麻豆av电影在线观看-日韩一级片毛片|www.grbbt.com

通過灰盒Fuzzing技術(shù)來發(fā)現(xiàn)Mac OS X安全漏洞

通過灰盒Fuzzing技術(shù)來發(fā)現(xiàn)Mac OS X安全漏洞

原文地址:security.di.unimi.it/~joystick/pubs/eurosec14.pdf

注:部分不太重要的沒有翻譯。

內(nèi)核是所有操作系統(tǒng)的核心,它的安全性非常重要。任何地方一個漏洞,都足以危害整個系統(tǒng)的安全。非特權(quán)用戶如果找到這樣的漏洞可以輕松的使整個系統(tǒng) 崩潰,也或者取得管理員權(quán)限。可見,內(nèi)核對攻擊者來說更具吸引力,內(nèi)核漏洞的數(shù)量也在以一個不安的趨勢在上升。因為太復(fù)雜。在內(nèi)核層挖掘漏洞是一件讓人畏懼的事情。的確,現(xiàn)代內(nèi)核是非常的復(fù)雜還含有很多子系統(tǒng),有些是第三方開發(fā)的。通常,第三方開發(fā)的內(nèi)核擴(kuò)展組件沒有內(nèi)核本身那樣安全。因為第三方組件不是 開源的,也缺乏足夠的測試。另外,內(nèi)核有太多的用戶數(shù)據(jù)接口。系統(tǒng)調(diào)用,文件系統(tǒng)和網(wǎng)絡(luò)連接等允許用戶提交數(shù)據(jù)到重要的代碼路徑。如果在其中找到一個 bug,足以威脅到系統(tǒng)安全。測試用戶層到內(nèi)核的接口十分重要,因為它能夠?qū)崿F(xiàn)提權(quán)攻擊。這是現(xiàn)在大多數(shù)攻擊者想做的。

Windows和Linux系統(tǒng)的內(nèi)核接口已經(jīng)被深入的分析,并且有很多工具用來進(jìn)行檢測。但在Mac OS X上,內(nèi)核提供給擴(kuò)展的接口交互方法相對來說還沒有被廣泛深入的分析。另外,OS X系統(tǒng)的市場份額正在穩(wěn)步提升,它將吸引更多的網(wǎng)絡(luò)犯罪分子的注意力。本文中,筆者闡述了一個自動在內(nèi)核擴(kuò)展中發(fā)現(xiàn)漏洞的framework。 LynxFuzzer的設(shè)計和實現(xiàn)。其可以自動加載Mac OS X的內(nèi)核組件。OS X內(nèi)核擴(kuò)展稱作Kext。使用蘋果公司提供的IOKit framework來進(jìn)行開發(fā)。LynxFuzze使用灰盒fuzzing技術(shù)動態(tài)的生成測試數(shù)據(jù)。其機(jī)理是自動從內(nèi)核擴(kuò)展中提取數(shù)據(jù),并使用它們來動態(tài) 生成輸入數(shù)據(jù)。進(jìn)一步說,筆者在LynxFuzzer中實現(xiàn)了3種不同的fuzzing引擎:簡單數(shù)據(jù)引擎的是根據(jù)內(nèi)核擴(kuò)展定義來產(chǎn)生偽隨機(jī)輸入數(shù)據(jù)。突 變引擎是根據(jù)嗅探到的合法數(shù)據(jù)來進(jìn)行變異來生成輸入數(shù)據(jù)。最后一個是進(jìn)化引擎,根據(jù)進(jìn)化算法,使用代碼覆蓋率來作為主要的驗證特征。

筆者決定在開源的,通過硬件輔助的虛擬化內(nèi)核調(diào)試器HyperDbg的基礎(chǔ)上開發(fā)LynxFuzzer。主要是因為Mac OS X在現(xiàn)有的虛擬化軟件中運(yùn)行會遇到很多困難。實際上蘋果公司一向以其定制化硬件出名。并不能被普通的調(diào)試器模擬。這個缺點阻礙了LynxFuzzer測試 一些OS X上的驅(qū)動。另外,一個硬件輔助環(huán)境可以保證在系統(tǒng)崩潰時,收集到關(guān)于機(jī)器的動態(tài)信息。總的來說筆者的工作做出了一下幾點成果:

筆者設(shè)計了LynxFuzzer來自動發(fā)現(xiàn)內(nèi)核擴(kuò)展的漏洞,比如動態(tài)的加載內(nèi)核模塊。筆者解決了幾個實際困難來實現(xiàn)這一有效的fuzzing系統(tǒng)。

筆者發(fā)明了一些有效的透明的技術(shù)來自動生成fuzzing輸入,從而減少輸入的搜尋范圍,提高對Mac OS X用戶態(tài)和內(nèi)核交互接口fuzzing的效率。

筆者擴(kuò)展了一種fuzzing系統(tǒng)。并且在一些擴(kuò)展上做了實踐。筆者的實驗發(fā)現(xiàn)了6個bug。在筆者分析的17個擴(kuò)展之中。其中兩個已經(jīng)在OS X 10.9種被修補(bǔ)。其CVE編號為CVE-2013-5166和CVE-2013-5192。

01 IOKit基礎(chǔ)

在這一節(jié)中,筆者將要簡要介紹IOKit framework。這是理解LynxFuzzer的基礎(chǔ)。

Mac OS X是蘋果公司開發(fā)的操作系統(tǒng),用于蘋果電腦。在它的眾多組件中,IOKit是對筆者來說是特別重要的。IOKit是一個系統(tǒng)框架,庫,工具和其他資源的集 合。用來在OS X上開發(fā)設(shè)備驅(qū)動。它提供了一個面向?qū)ο蟮木幊汰h(huán)境,和一些使得開發(fā)內(nèi)核組件更加簡單,用戶體驗更好的抽象對象。在下面結(jié)合筆者的工作來做一些闡述。

任何一個OS的基本組件就是用戶態(tài)與內(nèi)核空間的交互通信組件。Windows和Linux通過系統(tǒng)調(diào)用system call和特殊的虛擬文件(例如:/dev/urandom)。IOKit支持這兩種技術(shù),但是還新增了一種新奇的更加復(fù)雜的機(jī)制,叫做設(shè)備接口 (DevieceInterface)。

1

為了實現(xiàn)這種機(jī)制,內(nèi)核擴(kuò)展定義了一系列的可以在用戶態(tài)被調(diào)用的方法。這些方法返回的參數(shù)的數(shù)量和數(shù)據(jù)的類型是被限制的。這些方法的列表和參數(shù)的限 制都都存貯在被極度重要的結(jié)構(gòu)體里面:這就是分派表(dispatch table)。每一個kext都可以定義一個或多個分派表。每個表都是一組結(jié)構(gòu)體。每一個都包含了一個函數(shù)指針,允許的輸入值和輸出值,還有該方法允許接 收或返回的值的數(shù)量和大小。如果輸入結(jié)構(gòu)體的大小不需要在輸入前檢驗,可以將大小在表中聲明為ffffffff,然后由接收函數(shù)進(jìn)行檢驗。任何驅(qū)動都 可以擁有一個以上的分派表。IOKit允許擴(kuò)展在同一時刻提供給用戶空間程序以多個接口。每個kext都必須為每一個接口定義一個UserClient的 子類。這些子類的實例隨后與kext一起加載到內(nèi)核內(nèi)存(圖2)。每一個UserClient對象都包含一個與它提供接口對應(yīng)的分派表。

2

用戶態(tài)程序可以通過IoConnectCallMethod()來調(diào)用kext的方法,前提是這個方法已經(jīng)在kext分派表中。當(dāng)然,用戶態(tài)程序需 要必須先找到目標(biāo)實例。想解釋這一過程,筆者首先需要介紹一個IOKit抽象類:IOService。每一個IOKit設(shè)備驅(qū)動都是繼承于它的對象,一個 kext可以同時擁有不同的IOService對象。舉例說明,具有代表性的就是同時有幾個USB設(shè)備連接到電腦,每個都需要它自己的驅(qū)動。這些驅(qū)動都被 包含在IOUSBFamily kext中,每一個都是一個特殊的IOService的子類。當(dāng)一個用戶態(tài)程序想要和一個設(shè)備交互時,像前面提到的一樣,它會與IOKit建立一個 mach連接,然后尋找合適的服務(wù)來適應(yīng)設(shè)備。這個過程叫做Device Matching。

如果找到服務(wù)成功,交互通道也成功建立,用戶態(tài)程序就會使用IoConnectCallMethod()來調(diào)用目標(biāo)方法。在真正執(zhí)行目標(biāo)函數(shù)之前, 程序會將控制權(quán)交給IOKit framework,由IOKit framework執(zhí)行一系列操作。首先,它查詢UserClient對象的分派表入口。入口地址隨后被傳送給externalMethod()函數(shù),同 時還有其他被執(zhí)行調(diào)用kext方法所允許的參數(shù)。只有參數(shù)符合分派表要求的情況下,方法才會被調(diào)用,不然就會被阻止。

相對于一般的機(jī)制,如ioctl,整個IOKit輸入控制機(jī)制提供了一個保護(hù)層。參數(shù)檢查會在由用戶層進(jìn)入驅(qū)動層之前進(jìn)行。顯而易見,這些約束都使 得fuzzing工作變得更加復(fù)雜。使用完全隨機(jī)的參數(shù)大小來對kext的函數(shù)進(jìn)行fuzz幾乎是無效的。絕大多數(shù)的調(diào)用請求都會被IOKit檢查并丟棄 掉。筆者在下一節(jié)會看到,筆者fuzzer的重要一個特性就是能自動從目標(biāo)中提取到參數(shù)限制,之后動態(tài)適應(yīng)限制,讓fuzzing更加的高效。

02 LynxFuzzer

筆者fuzzer的目的是在能被用戶態(tài)程序調(diào)用到的kext code中發(fā)現(xiàn)bugs。一個可以從用戶態(tài)激發(fā)的bug可以讓非特權(quán)用戶崩潰掉整個系統(tǒng)的。也甚至是執(zhí)行任意內(nèi)核代碼。從而達(dá)到提權(quán)攻擊。所以,筆者決定 將筆者的注意力集中到設(shè)備接口跨界機(jī)制(DeviceInterface boundary-crossing mechanism),因為它是OS X內(nèi)核擴(kuò)展機(jī)制中用戶層和內(nèi)核交互的標(biāo)準(zhǔn)。

在上一節(jié)中,需要指出的是在調(diào)用一個kext方法時,很多的約束必須得到考慮。對于每個kext來說是不同的。知道分派表中的約束能減小筆者 fuzzing工作量。提高fuzzing的效率。所以筆者設(shè)計的LynxFuzzer能夠全自動的提取信息,然后自動的進(jìn)行fuzz。當(dāng)然,筆者的 fuzzing基礎(chǔ)設(shè)計的自動化功能不止于此。事實上,筆者能提取到在用戶態(tài)和內(nèi)核態(tài)組件非人工交互的合法有效輸入向量。這些輸入可以經(jīng)過精心使用來加強(qiáng) 筆者的fuzzing策略。

3

LynxFuzzer的基本結(jié)構(gòu)可以從圖3中看到,框架擁有兩個主要的組件:一個在用戶態(tài),有4個子組件構(gòu)成。另一個構(gòu)建在調(diào)試器分析框架上。圖3 中還說明了LynxFuzzer內(nèi)部組件的主要交互行為。tracer和調(diào)試器(hypervisor)交互得到目標(biāo)分派表。一旦發(fā)現(xiàn),調(diào)試器就從內(nèi)核內(nèi) 存中取回分派表的地址,返回給tracer,tracer將其保存到data manager中以待后面使用。sniffer使用這些信息來攔截非人工的IoConnectCall()調(diào)用,收集到一些有效的輸入。最后fuzzer 組件開始使用自定義的參數(shù)來調(diào)用目標(biāo)方法。等待最后的異常。fuzzer可以使用之前存貯的數(shù)據(jù)生成新的輸入數(shù)據(jù)或者使用覆蓋突變方法來生成輸入,這取決 于fuzzer引擎的選擇。

2.1 Tracer

tracer是LynxFuzzer的第一個運(yùn)行的組件,它的任務(wù)是找到fuzz的目標(biāo)。舉例,它必須確定目標(biāo)的哪個方法是能夠被調(diào)用的。這些信息 包含在目標(biāo)kext的分派表中。然而,定位一個kext的分派表并不簡單,因為IOKIt使用很多抽象層來對用戶層隱藏信息。筆者的解決方案是:任何時候 用戶態(tài)程序調(diào)用IoConnectCallMethod(),IOKit將會調(diào)用它的externalMethod()函數(shù),筆者對此進(jìn)行監(jiān)視。通過以下 方法來實現(xiàn),LynxFuzzer調(diào)試器對externalMethod()函數(shù)下一個斷點,截斷對它的調(diào)用。一旦這個陷阱(trap)被設(shè)置 好,tracer就對目標(biāo)kext發(fā)起一個請求,其selector參數(shù)為0。當(dāng)調(diào)試器截斷externalMethod(),就提取分派表的基地址。然 后dump整個分派表,將它返回給tracer。最終,tracer存貯分派表到data maanger,分享給其它組件使用。

分派表的大小事先是不知道的。也不在被截斷函數(shù)的參數(shù)里面。為了解決這個問題,LynxFuzzer分析分派表的結(jié)構(gòu)推斷出其擁有多少個入口,然后 dump下來。事實上,每個表的入口由一個指針,該指針必須在目標(biāo)的內(nèi)存范圍內(nèi)。和4個連續(xù)的整數(shù),其中兩個必須在0-15之間。

2.2 Sniffer

除了IOKit的檢查,kext自己可以實現(xiàn)對輸入的約束。所以LynxFuzzer包含了一個sniffer組件。該組件用來截斷目標(biāo)方法的執(zhí) 行,提取到它們的參數(shù)。為了實現(xiàn)這個筆者再次利用LynxFuzzer的調(diào)試器,它可以透明的無縫的截斷筆者感興趣的函數(shù),通過檢查目標(biāo)kext的內(nèi)存來 dump它的參數(shù)。

特別的,調(diào)試器對于externalMethod()函數(shù)來說是透明的。該函數(shù)的參數(shù)包含了足夠的信息來獲取有效的輸入。事實上,調(diào)試器用 dispatch參數(shù)來區(qū)分出是哪一個kext是這次截斷的目標(biāo)。用selector參數(shù)來確定是哪一個方法被調(diào)用。 IOExternalMethodArguments結(jié)構(gòu)中包含了真正的傳遞進(jìn)來的參數(shù)。這種結(jié)構(gòu)中還包含了參數(shù)的數(shù)量和大小。它們都將會被保存到 data manager。

2.3 Fuzzer

4

fuzzer是LynxFuzzer的主要組件。當(dāng)tracer盒sniffer獲取了足夠的輔助信息可以進(jìn)行fuzz一個kext 時,fuzzer生成對kext方法的測試集,然后通過IOKit設(shè)備接口來調(diào)用方法。圖4顯示了該組件的結(jié)構(gòu):一個請求生成器,一組fuzzing引擎 和一個監(jiān)視器。 請求生成器是一個通用的組件:它必須獨立于目標(biāo)kext和選擇的fuzzing引擎來運(yùn)轉(zhuǎn)。在一次典型的執(zhí)行中,它從fuzzing引擎中接收到測試數(shù)據(jù) 之后,檢查數(shù)據(jù)是否符合分派表中聲明目標(biāo)方法的要求,適當(dāng)?shù)恼{(diào)整以符合最后在kext中執(zhí)行目標(biāo)方法的IoConncetCallMethod()函數(shù). 如果測試數(shù)據(jù)沒有導(dǎo)致崩潰,kext發(fā)出一個回應(yīng),由monitor來接收。monitor根據(jù)接收到的放回數(shù)據(jù)和當(dāng)前的fuzzing引擎來決定是否繼 續(xù)使用當(dāng)前的引擎。所以后一個測試基于前一個測試反饋的。突變引擎和進(jìn)化引擎都會使用該模式。

LynxFuzzer實現(xiàn)了基于會話的fuzzing:筆者不多余操作,只需要發(fā)出尋找bug的請求。但是筆者要從每個fuzzing會話開始記錄 每一個請求。這種方法很常見,特別是在fuzzing基于狀態(tài)的網(wǎng)絡(luò)協(xié)議的時候,在這種情景下也是適用的。事實上kext也擁有一種狀態(tài)。這種狀態(tài)會隨著 大量不同的fuzzing請求而變化,直到進(jìn)入非正常的狀態(tài),一個bug被觸發(fā)。出于這種原因,使用基于會話的記錄,代替單個的請求會極大的保證一個 bug的可重現(xiàn)性。記錄fuzzer和目標(biāo)kext之間的交互會話,每一個請求都被存貯在data manager中,最終fuzzer對輸入數(shù)據(jù)的生成也是由影響的。LynxFuzzer三種不同引擎的細(xì)節(jié)筆者馬上給出。

2.3.1 隨機(jī)引擎(Generation Engine)

這是最簡單快速的引擎。它的生成過程可以簡述如下,第一步,它生成可以包含輸入數(shù)據(jù)到目標(biāo)方法的數(shù)據(jù)結(jié)構(gòu)。第二步,生成偽隨機(jī)數(shù)據(jù)來填充這個結(jié)構(gòu)體。最后,將數(shù)據(jù)通過IoConnectCallMethod()發(fā)送給目標(biāo)。如果系統(tǒng)沒有崩潰就繼續(xù)反復(fù)這一過程。

2.3.2 突變引擎(Mutation Engine)

這種fuzzing方法遵循一個原則就是站在前者數(shù)據(jù)的對立面:每一個新的輸入數(shù)據(jù)都是從sniffer組件收集到的有效輸入數(shù)據(jù)變化生成。 fuzzing的過程也比較簡單:使用不同的突變函數(shù)將sniffer收集到的有效輸入數(shù)據(jù)進(jìn)行變異,然后使用突變后的數(shù)據(jù)進(jìn)行請求。如果系統(tǒng)沒有崩 潰,monitor會檢查kext給出的返回值。盡可能的將會導(dǎo)致kext返回error的輸入值排除在下一個突變生成之外。這極大的提高了fuzzer 的效率。特別是在輸入結(jié)構(gòu)時可變大小的時候,因為它逐步去除了那些在目標(biāo)方法中被檢查非法的輸入。這個引擎使用的突變函數(shù)有:位翻轉(zhuǎn),字節(jié)翻轉(zhuǎn),字節(jié)交換 和大小改變。

2.3.3 進(jìn)化引擎(Evolution Engine)

進(jìn)化引擎試圖突破其他引擎的限制。盡量少的使用偽隨機(jī)。利用進(jìn)化算法來生成新的輸入數(shù)據(jù)。

任何進(jìn)化算法的核心就是適應(yīng)函數(shù)(fitness function)。它定義了生成器使用的最佳元素。在LynxFuzzer里,筆者開發(fā)了兩種適應(yīng)函數(shù):一個測量輸入向量的代碼的覆蓋率。另一個測量輸 入和最佳輸入向量(導(dǎo)致崩潰的輸入)的差距。在第一種情況中,筆者極力去生成一組輸入向量來給筆者最佳的代碼覆蓋率。第二種情況在筆者想在定制一個給定向 量(比如一個會觸發(fā)bug的向量)的時很有用。

代碼覆蓋率分析。筆者的代碼覆蓋率分析方法如下:在開始調(diào)用kext方法之前,fuzzer組件告知調(diào)試器kext的代碼范圍。調(diào)試器將相應(yīng)代碼內(nèi) 存段的可執(zhí)行屬性在EPT(Extended Page Tables)入口中移除。這樣只要kext執(zhí)行相應(yīng)頁的代碼時就會觸發(fā)一個EPT違規(guī)。調(diào)試器跟蹤到導(dǎo)致違規(guī)的指令。為了繼續(xù),調(diào)試器重新將不可執(zhí)行夜 標(biāo)志為可執(zhí)行,同時讓程序單步執(zhí)行。當(dāng)調(diào)試器由于調(diào)試異常而重新獲得控制權(quán),它再將這個可執(zhí)行權(quán)限移除,所以下一個指令還是會產(chǎn)生執(zhí)行違規(guī)。當(dāng)被fuzz 的方法返回,fuzzer發(fā)出調(diào)用來解除跟蹤。調(diào)試器存貯收集到的信息到fuzzer的一塊空間中,讓用戶空間的組件來計算相應(yīng)調(diào)用的代碼覆蓋率。

5

03 實驗評估

本節(jié)介紹下筆者測試LynxFuzzer效率的的實驗。筆者測試了17個同的內(nèi)核擴(kuò)展。找到了6個bug。其中2個已經(jīng)在OS X 10.9中得到了修復(fù)。已經(jīng)被蘋果公司定義為CVE-2013-5166和CVE-2013-5192。剩下的4個還沒有被修復(fù)。也許會在以后版本中修 復(fù)。

所有的的實驗都是在安裝來Mac OS X 10.8.2系統(tǒng)的蘋果電腦(Intel i5 CPU 12G RAM)上進(jìn)行的。由于蘋果內(nèi)核的安全機(jī)制。筆者找到的漏洞沒有一個可以簡單溢出進(jìn)行提權(quán)的攻擊的。

評價fuzzer效率的的其中一個指標(biāo)就是代碼覆蓋率水平。這個指標(biāo)也許不是那么的絕對:一個fuzzer也許代碼覆蓋率達(dá)到100%也獲取不了一個bug。但是通常都會報告這一指標(biāo),所以筆者統(tǒng)計了LynxFuzzer的代碼覆蓋率。

雖然筆者的調(diào)試器可以輕松的追蹤每一條指令。但是給出一個精確的覆蓋率還是相當(dāng)不容易的。筆者通過靜態(tài)動態(tài)混合分析技術(shù)來估算出可以有分派表達(dá)到的 代碼總量。首先,筆者靜態(tài)的計算導(dǎo)出方法的指令數(shù)。塞選出所有控制轉(zhuǎn)移指令CTI(control transfer instrction)。然后,對于每個CTI,如果跳轉(zhuǎn)目標(biāo)是同一個kext的另一個方法,筆者就將其統(tǒng)計到總數(shù)中。

不幸的是這還是有不足之處。由于內(nèi)核的面相對象特性,kext包含很多間接CTI,無法靜態(tài)跟蹤。對于這類指令,筆者采用動態(tài)分析:筆者改進(jìn)了 LynxFuzzer代碼覆蓋率分析模型,讓它dump每一條kext中每一條CTI指令的目標(biāo)。如果目標(biāo)在靜態(tài)分析中沒有被檢測到,筆者還是將這個指令 計算到總數(shù)中。

表1顯示了一部分代碼覆蓋率的實驗結(jié)果。在覆蓋率欄筆者顯示了3種不同的覆蓋率百分比:導(dǎo)出方法的指令數(shù),混合分析的指令數(shù),kext中指令總數(shù)。

筆者還估算了在3.3中描述的代碼覆蓋率方法的開銷。為此,筆者在10個不同kext上運(yùn)行隨機(jī)引擎fuzz每個方法。將代碼覆蓋率統(tǒng)計模塊分別開 啟和關(guān)閉,統(tǒng)計kext每秒可以處理的請求數(shù)。出于精確性,筆者在每個模塊上進(jìn)行了10次重復(fù)。結(jié)果取平均值。平均開銷是3.45x,最優(yōu)和最差分別是 1.73x和5.99x。表2給出了細(xì)節(jié)。筆者可以看到,筆者為獲取高精度,在沒有優(yōu)化目標(biāo)時付出了較大的代價,但是相對其他技術(shù)來說也算是很低了。

6

最后,評估了引擎的效率,特別指出,通過不同配置的筆者的引擎都能用于發(fā)現(xiàn)bug,但是基于代碼覆蓋率的進(jìn)化引擎是最快的,隨機(jī)引擎最慢。

上一篇:如何破解勒索軟件

下一篇:Hacking Team:攻擊向量之Bios Rootkit