王 東,張小松,2*,陳 廳
(1. 電子科技大學網(wǎng)絡空間安全研究院 成都 611731;2. 鵬城實驗室網(wǎng)絡安全研究中心 廣東 深圳 518040)
Gartner 公司預測2020 年全世界部署的嵌入式設備在數(shù)量上將達到200 億,相關研究發(fā)現(xiàn)這類設備在開發(fā)設計上缺乏最佳安全實踐,導致存在大量安全漏洞[1-4],針對這類設備的漏洞挖掘已成為研究熱點。文獻[5]基于已知特征使用靜態(tài)方法對大規(guī)模固件進行漏洞挖掘,但無法檢測未知漏洞。文獻[6]基于程序級仿真環(huán)境實現(xiàn)了通過動態(tài)測試來挖掘設備的Web 接口漏洞;文獻[7]基于系統(tǒng)級仿真環(huán)境實現(xiàn)了通過已知特征來檢測漏洞。仿真環(huán)境通常對系統(tǒng)配置的依賴較多,而嵌入式設備的多樣性使得仿真難以具備通用的配置。文獻[8]基于設備控制應用程序進行協(xié)議報文模糊測試,但該方法只對具有控制應用程序的設備有效。文獻[9]提出了一種設備和仿真相結合的方法,但需要較多人工參與。文獻[10]基于符號執(zhí)行實現(xiàn)了MSP430 系列微控制器的漏洞挖掘,但無法用于其它控制器。文獻[11]發(fā)現(xiàn)不同平臺設備的內(nèi)存破壞漏洞具有顯著區(qū)別,基于動態(tài)測試的挖掘方法需要處理其差異。
針對上述問題,本文提出了一種基于模糊測試CGI[12]的嵌入式設備漏洞挖掘方法,其主要特點有:1)受ACW 的啟發(fā),利用覆蓋率來驅(qū)動嵌入式CGI 的模糊測試;2)提出了一種惰性輸入模型,克服了ACW 的固定輸入模型的低效問題;3)設計了一種選擇性外部函數(shù)跟蹤,有效提升了路徑探索能力;4)繼承了動態(tài)測試的優(yōu)勢,即不存在靜態(tài)分析方法的誤報。為驗證上述方法的有效性,本文在原型系統(tǒng)BCFuzzer 進行了相關實現(xiàn),并使用嵌入式設備CGI 程序集進行實驗,結果表明:同ACM 相比,BCFuzzer 能自動發(fā)現(xiàn)更多的代碼路徑,也能更快的發(fā)現(xiàn)更多未知漏洞。
模糊測試(fuzzing)是一種自動化或者半自動化的測試技術,它通過構造隨機的非預期畸形數(shù)據(jù)作為程序輸入,并監(jiān)控執(zhí)行過程中的異常行為來發(fā)現(xiàn)軟件漏洞[13]。模糊測試技術分為黑盒、灰盒和白盒3 種[14]。黑盒模糊測試實用面最廣,因為它不關心被測試程序內(nèi)部的實現(xiàn)細節(jié),但這同時也導致了它的有效性較低[15]。白盒模糊測試需要跟蹤被測試程序內(nèi)部的詳細信息,因此有效性是最高的,但存在諸多符號執(zhí)行的限制[16]。灰盒模糊測試介于黑盒和白盒之間,跟蹤被測試程序的部分內(nèi)部信息,提升了模糊測試的有效性;同時,它的跟蹤方法是輕量級的,能用于實際大型程序。其中,基于覆蓋率驅(qū)動的灰盒模糊測試是已被實踐證明有效的方法[17],如算法1 所示。
ACW 是面向桌面平臺CGI 的漏洞挖掘系統(tǒng),其核心是基于覆蓋率驅(qū)動的模糊測試[18]。算法1 中的代碼是ACW 在經(jīng)典模糊測試器AFL 基礎上實現(xiàn)的核心部分。其中,fixedModel 是預定義的CGI 固定輸入模型;ACW 采用經(jīng)典數(shù)據(jù)變異方法對測試用例進行變異;ParseModel 依據(jù)fixedModel對變異后數(shù)據(jù)進行解析以還原成CGI 需要的環(huán)境變量envList 和標準輸入stdio;最后利用仿真器QEMU 插樁執(zhí)行CGI。為提升執(zhí)行效率,ACW 僅對CGI 的主模塊進行覆蓋率跟蹤。
嵌入式設備多采用精簡的Web 容器和CGI 程序,這使得ACW 應用在嵌入式CGI 漏洞挖掘中會面臨兩大難點,通過圖1 的示例CGI 程序源碼來說明。代碼行04 和07 是位于不同的代碼路徑的兩個漏洞。
圖1 示例CGI 程序的源代碼
難點1:私有環(huán)境變量的生成問題。圖1 所示02 行代碼的SelfHead 不是典型環(huán)境變量,他在ACW 的固定輸入模型中是不存在的。因此,圖1的ACW 模糊測試算法是無法生成該環(huán)境變量的,覆蓋率驅(qū)動也始終無法探索到04 代碼路徑的漏洞。這個難點的核心是,針對不同的CGI 程序,應采用與之對應的輸入模型。BCFuzzer 設計了一種基于反饋的惰性輸入模型來克服該問題。該模型不再主動假定CGI 需要的環(huán)境變量,而是先監(jiān)視運行CGI 程序并反饋其使用的環(huán)境變量,接著根據(jù)反饋生成輸入模型。這是一種惰性的處理方式,只有實際使用到的環(huán)境變量才會被添加到輸入模型。BCFuzzer 通過該方法生成自適應的輸入模型,提升測試效率。
難點2:依賴外部函數(shù)的分支路徑的探索問題。為減少硬件資源的消耗,圖1 的06 行代碼中strcmp 這類基礎函數(shù)在嵌入式平臺上通常被動態(tài)鏈接到外部系統(tǒng)庫,在主模塊中只有調(diào)用描述信息。只跟蹤主模板的ACW 無法對調(diào)用的外部函數(shù)實施覆蓋率驅(qū)動,而一次性變異就生成特征字符串debugger 來觸發(fā)07 代碼路徑上的漏洞是困難的。這個難點的核心是,不能只跟蹤主模塊的覆蓋率信息。BCFuzzer 利用靜態(tài)分析技術來識別CGI 程序中可能受輸入影響的外部函數(shù),然后針對他們也進行額外跟蹤,從而利用覆蓋率驅(qū)動來進入ACW 難以到達的分支路徑。這種有選擇性的外部函數(shù)跟蹤平衡了執(zhí)行效率和代碼路徑的深入,提升了嵌入式CGI 漏洞挖掘的效率。
BCFuzzer 的系統(tǒng)架構如圖2 所示,靜態(tài)分析模塊(StaticAnalyzer)負責自動分析CGI 程序中外部調(diào)用的信息,調(diào)度模塊(Scheduler)通過解析輸入模型來生成測試數(shù)據(jù),并調(diào)用執(zhí)行模塊(QEMU)運行CGI;QEMU 在運行中通過EnvMonitor 組件來監(jiān)視CGI 實際需要的環(huán)境變量,并通過選擇性外部函數(shù)跟蹤組件(ExternCallTracer)跟蹤特定外部函數(shù)。
圖2 BCFuzzer 的系統(tǒng)架構
惰性輸入模型包含兩部分,一部分是圖2 中運行在QEMU 的EnvMonitor,負責監(jiān)控CGI 的環(huán)境變量;另一部分是圖2 中運行在Scheduler 的LazyParser,負責把測試數(shù)據(jù)解析為環(huán)境變量和標準輸入。這兩部分的調(diào)度如算法2 所示。
相比算法1,BCFuzzer 使用了惰性輸入模型來生成測試數(shù)據(jù)。為支持惰性輸入模型,擴展了ACW 的用例數(shù)據(jù)結構Seed,增加一個model 成員來存儲輸入模型。模型解析時,在Seed.model 中每遍歷到一個環(huán)境變量名,就從變異數(shù)據(jù)中讀取字符串作為環(huán)境變量值,從而形成環(huán)境變量鍵值對;然后將未對應到環(huán)境變量名的剩余數(shù)據(jù)作為標準輸入stdio,并形成數(shù)據(jù)長度的環(huán)境變量鍵值對;最后把這些傳遞給QEMU 去執(zhí)行。每當有變異數(shù)據(jù)探索了新路徑,BCFuzzer 再次運行CGI 并加載EnvMonitor 來獲取CGI 需要的環(huán)境變量以生成新路徑的輸入模型。
選擇外部調(diào)用跟蹤包括兩部分:外部函數(shù)調(diào)用的定位和覆蓋率收集。針對外部函數(shù)調(diào)用的定位,BCFuzzer 使用算法3 所述的靜態(tài)切片來識別CGI中特定外部函數(shù)的調(diào)用指令。首先通過GetBinarayCFG獲取控制流圖cfg,其次通過GetInputSource 獲取全部的數(shù)據(jù)輸入指令集合sourceList,然后通過前向切片來分析輸入數(shù)據(jù)傳播到的目標指令,最后通過IsExternCallIns 識別這些指令中的外部調(diào)用指令即得到了可能受輸入影響的外部調(diào)用指令。
算法3:特定外部函數(shù)的調(diào)用指令識別算法
BCFuzzer 使用算法4 所示的基于外部調(diào)用能量的方法對CGI 進行選擇性的外部函數(shù)調(diào)用跟蹤。
算法4:基于基本塊的選擇性外部調(diào)用跟蹤算法
具體來說,該算法的核心機制是對外部函數(shù)進行覆蓋率跟蹤,必須要消耗能量externCallEnergy。具體來說,QEMU 動態(tài)執(zhí)行從CGI 主模板切換到外部函數(shù)時,根據(jù)CGI 的靜態(tài)分析結果來判定這個外部函數(shù)是否需要跟蹤。如果需要,就初始化能量externCallEnergy,這樣在外部函數(shù)代碼執(zhí)行期間就因有能量而被持續(xù)跟蹤以收集覆蓋率信息。最后,QEMU 執(zhí)行返回到主模板時清空能量。
為驗證所提方法的有效性,本文在ACW 的基礎上實現(xiàn)了原型系統(tǒng)BCFuzzer,其采用LD_PRELOAD機制和擴展ACW 的用例數(shù)據(jù)結構來實現(xiàn)惰性輸入模型[19-20],使用IDA Pro 腳本技術[21]和QEMU 動態(tài)插裝實現(xiàn)選擇性外部調(diào)用跟蹤。最后通過固件下載和硬件讀取方式收集多個廠商設備的CGI 程序,并以此作為測試集進行實驗驗證。
表1 是收集的77 個嵌入式設備CGI 程序集的詳情,覆蓋了主流的嵌入式處理器架構MIPS 和ARM,以及數(shù)據(jù)端大小順序。仿真器不支持64 位指令,最后可測試的程序數(shù)量為69 個。
表1 嵌入式CGI 程序測試集
實驗采用了3 種基于覆蓋率驅(qū)動的模糊測試工具:ACW、ACW-Full 和BCFuzzer。ACW 是桌面平臺CGI 模糊測試器,這里整合了運行環(huán)境封裝使其支持嵌入式CGI;ACW-Full 是ACW 的擴展,加入了對全部執(zhí)行代碼的強制插樁以獲得最大化的代碼跟蹤;BCFuzzer 是在ACW 的基礎上整合了惰性輸入模型和選擇性外部調(diào)用跟蹤。
實驗采用Linux 計算機,配置為Intel I7 CPU,6 核12 線程,內(nèi)存64 GB,磁盤512 GB SSD,操作系統(tǒng)Ubuntu1604,采用docker 技術實施CGI 程序的并行測試。
針對基于覆蓋率驅(qū)動的模糊測試方法,路徑探索能力直接影響其漏洞挖掘能力。為驗證BCFuzzer對路徑探索的提升,使用表1 的程序集進行實驗。因測試資源有限,實驗對表1 的67 個CGI 程序進行了精簡,即同一廠商的不同設備的相同名字的CGI 程序僅取一個作為代表,形成最終的34 個程序集。每個CGI 程序僅被測試運行1 h,用時合計102 h。
圖3 是3 種模糊測試工具在每個CGI 程序的測試過程中發(fā)現(xiàn)的路徑數(shù)量。針對該實驗結果分析可知:ACW 的路徑發(fā)現(xiàn)能力最弱,這符合實驗的預期,因為它采用固定輸入模型且不跟蹤外部調(diào)用函數(shù),限制了路徑探索;ACW-Full 的發(fā)現(xiàn)能力優(yōu)于ACW,這也符合實驗的預期,因為ACWFull 通過跟蹤全部執(zhí)行代碼收集了更多覆蓋率信息,從而驅(qū)動發(fā)現(xiàn)更多的代碼路徑;BCFuzzer 針對絕大部分CGI 程序(30 個)的發(fā)現(xiàn)能力都顯著優(yōu)于ACW 和ACW-Full,路徑發(fā)現(xiàn)數(shù)量是他們的兩倍及以上;而針對其他4 個程序,其發(fā)現(xiàn)能力沒有提升。由此可見,針對絕大部分嵌入式CGI 程序,BCFuzzer 在路徑發(fā)現(xiàn)能力上都優(yōu)于現(xiàn)有的模糊測試工具。
圖3 嵌入式CGI 程序路徑發(fā)現(xiàn)實驗結果圖
實驗對CGI 程序分別采用3 種模糊測試進行長時間的自動化測試,以此來驗證他們的漏洞挖掘能力。使用路徑發(fā)現(xiàn)實驗的34 個被測試CGI 程序作為候選測試對象,因測試資源有限對34 個程序進行了二次篩選,根據(jù)他們的體積最終選擇了6 個不同設備的CGI 程序進行獨立的24 h 測試。
圖4 是挖掘?qū)嶒灥慕Y果圖,分析可知:ACW 的漏洞挖掘能力最差,針對6 個嵌入式CGI 沒有發(fā)現(xiàn)一個崩潰;ACW-Full 的漏洞挖掘能力優(yōu)于ACW,發(fā)現(xiàn)了2 個嵌入式CGI 的崩潰;BCFuzzer 的漏洞挖掘能力最強,發(fā)現(xiàn)了5 個嵌入式CGI 的崩潰,數(shù)量是ACW-Full 的2.5 倍;針對ACW-Full 發(fā)現(xiàn)崩潰的2 個CGI 程序,BCFuzzer 發(fā)現(xiàn)的唯一崩潰數(shù)量是ACW-Full 的1.5 倍。由此可見,BCFuzzer 比ACW和ACW-Full 能發(fā)現(xiàn)更多的漏洞,并能更快地發(fā)現(xiàn)漏洞。
圖4 漏洞挖掘?qū)嶒灲Y果圖
BCFuzzer 的惰性輸入模型實現(xiàn)了自動生成CGI必需的環(huán)境變量,選擇外部函數(shù)調(diào)用跟蹤實現(xiàn)了依賴外部函數(shù)的條件分支的覆蓋率驅(qū)動,提升了對嵌入式設備CGI 漏洞的挖掘能力。最后通過實驗驗證了BCFuzzer 的有效性。