【摘 要】 為有效提高嵌入式軟件在投入生產(chǎn)環(huán)境前發(fā)現(xiàn)潛在安全問題的效率,本文對嵌入式環(huán)境下軟件開發(fā)中的代碼安全控制進行了深入分析與研究,闡述了在資源受限環(huán)境下軟件安全測試的方法和技術(shù),并重點介紹了在軟件編譯鏈接之后,通過對二進制文件進行測試進一步發(fā)現(xiàn)嵌入式軟件安全問題的方法。
【關(guān)鍵詞】 嵌入式 代碼安全 模糊測試
1 引言
據(jù)調(diào)查顯示,全球嵌入式系統(tǒng)市場收入在6年內(nèi)增長達40%,從2015年的1590億美元增長到2021年的22534億美元。這一增長的主要驅(qū)動力是市場對節(jié)能、智能的電子設(shè)備日益增長的需求。此外,行業(yè)提供的新可能性及在嵌入式系統(tǒng)中使用多核架構(gòu)提供的新應(yīng)用也加速了這種增長。嵌入式系統(tǒng)是一種包含微處理器和軟件的電子產(chǎn)品,廣泛應(yīng)用于工業(yè)生產(chǎn)、醫(yī)療電子、汽車電子、網(wǎng)絡(luò)通信、軍事航天等領(lǐng)域。嵌入式系統(tǒng)一般都包含相對固定的組件,如芯片、閃存、固件等。組件組成主要包括硬件和軟件部分,其中軟件部分直接與硬件交互,因此對于其安全性和可靠性有著更高的要求。
近20年來,有關(guān)嵌入式軟件的零日(0Day)漏洞層出不窮,而分析其中大多數(shù)漏洞成因往往是較為低級的錯誤導(dǎo)致的。如果能在軟件的開發(fā)階段或應(yīng)用驗證階段通過一系列測試方法及流程,將可能引發(fā)的安全問題盡可能規(guī)避掉,將大大提高軟件的安全性。這一需求在無法經(jīng)常更新迭代的嵌入式環(huán)境下顯得尤為重要。本文將針對C/C++環(huán)境的嵌入式系統(tǒng)中常見的軟件安全問題進行討論,并介紹幾種常見的測試方法,以提高嵌入式軟件的安全性、健壯性。
2 嵌入式系統(tǒng)常見的安全問題
在安全方面,針對嵌入式系統(tǒng)的攻擊可大體分為3類,分別是針對嵌入式軟件的攻擊、針對網(wǎng)絡(luò)的攻擊和側(cè)信道攻擊。本文將針對嵌入式軟件的安全問題和幾種常見的影響系統(tǒng)穩(wěn)定性的編碼問題進行討論。
2.1 緩沖區(qū)溢出漏洞
緩沖區(qū)溢出是各類軟件中十分普遍的安全問題,不僅在嵌入式軟件中存在,在其他應(yīng)用軟件和操作系統(tǒng)中也十分常見。表1為國家信息安全漏洞庫(CNNVD)收錄的2022年6月漏洞類型統(tǒng)計表,從表中可以看出緩沖區(qū)錯誤類型漏洞占比高達8.4%。緩沖區(qū)溢出問題的根本原因在于過于信任輸入,而沒有正確檢查動態(tài)空間的邊界,開發(fā)者將長于目標的數(shù)據(jù)進行拷貝,因此覆蓋了與目標相鄰的區(qū)域。緩沖區(qū)溢出的問題十分嚴重,可能導(dǎo)致目標系統(tǒng)宕機、命令執(zhí)行等后果。實踐得出,緩沖區(qū)溢出可以發(fā)生在堆、棧、bss等存放變量的任何區(qū)域,攻擊者可以通過事先計算好的長度構(gòu)造payload來修改函數(shù)的返回地址,或替換成惡意代碼的起始地址,以完成攻擊。
表1 2022年6月漏洞類型統(tǒng)計表(只截取前10種)
2.2 內(nèi)存泄漏
內(nèi)存泄漏是指程序中已被動態(tài)分配的堆區(qū)內(nèi)存由于編程人員或者其他原因而未進行釋放,造成的系統(tǒng)內(nèi)存浪費,內(nèi)存泄漏問題并沒有泄漏大小之分,無論內(nèi)存泄漏多么輕微,都會導(dǎo)致程序運行性能降低,最終將會在有限的時間內(nèi)消耗掉全部內(nèi)存,導(dǎo)致系統(tǒng)的崩潰。內(nèi)存泄漏問題在嵌入式系統(tǒng)下顯得格外重要,嵌入式系統(tǒng)的內(nèi)存資源通常比其他平臺要小得多,如果存在內(nèi)存泄漏問題,將在更短的時間內(nèi)造成嚴重后果。
2.3 空指針引用
空指針引用顧名思義就是使用了一個沒有指向合法地址空間的指針,通常是由這個指針沒有被初始化、正確賦值或原本指針指向的內(nèi)存空間已經(jīng)被釋放等原因?qū)е碌摹H绻幊倘藛T在使用一個指針之前沒有對其進行非空判斷,都有可能造成空指針引用,原因是在C/C++環(huán)境中即使使用了malloc/new內(nèi)存分配函數(shù)對其賦值,如果不對返回結(jié)果進行檢查,也無法確保此時的內(nèi)存分配是成功的。空指針引用問題比內(nèi)存泄漏問題更為嚴重,因為前者可能導(dǎo)致系統(tǒng)直接崩潰。
2.4 格式化字符串漏洞
格式化字符串漏洞主要利用C語言中print系列的函數(shù),如printf、sprintf、fprinf等C庫函數(shù)。格式化是為了控制顯示文本的樣式,如%d是以整數(shù)的形式輸出,%p打印指針地址等,在使用此類函數(shù)前,如果能給定預(yù)料之內(nèi)的參數(shù),并不會有任何安全問題。但是若對輸入格式不進行控制,支持用戶任意輸入,將會造成嚴重的安全問題。其攻擊原理可以泄露特定寄存器和棧上的值,從而給攻擊者創(chuàng)造了發(fā)揮的空間,造成系統(tǒng)內(nèi)存信息泄露、控制代碼執(zhí)行邏輯、遠程命令執(zhí)行(RCE)等嚴重后果。
3 嵌入式軟件安全測試的方法和技術(shù)
3.1 靜態(tài)測試
靜態(tài)測試主要通過靜態(tài)測試工具對軟件的源代碼進行安全掃描,一般靜態(tài)測試常用的工具有Fortify SCA(Static Code Analyzer)、VCG(Visual Code Grepper)等。此類工具的基本思想都是從源代碼中提取原始特征,如字符串、基本塊、指令序列、語法樹、函數(shù)調(diào)用圖等,之后再對這些特征與先準備的軟件安全規(guī)則庫進行匹配來確定源代碼中是否存在相應(yīng)的漏洞。靜態(tài)分析是在不執(zhí)行源程序的情況下對代碼進行安全檢測的方式,它包含很多方面的技術(shù),如控制流分析、數(shù)據(jù)流分析、常量傳播和指針分析等。靜態(tài)測試作為一種保證源代碼安全的測試方法,可以較為有效地檢測出空指針引用、格式化字符串等問題,將軟件的安全問題控制在編碼階段。靜態(tài)測試的流程如圖1所示。
圖1 靜態(tài)安全測試流程
3.2 動態(tài)測試
動態(tài)測試是針對軟件或系統(tǒng)非常有效的測試方法,同時也是使用最多的針對嵌入式設(shè)備的動態(tài)漏洞分析技術(shù)。動態(tài)測試是在真實環(huán)境或者模擬環(huán)境中對運行中的程序通過對輸入進行隨機變換,觀察在不同的輸入下程序的運行結(jié)果,分析和判斷其結(jié)果是否滿足預(yù)期。例如,對于內(nèi)存泄漏問題,通常可以使用一些開源的內(nèi)存泄漏掃描工具,在被測程序源碼中進行插樁,檢查程序從開始到運行結(jié)束的內(nèi)存釋放情況。當然,無論何種工具,都存在誤報的情況,但使用工具的好處是可以盡量縮小范圍,再由研究人員分析當前結(jié)果是否為安全問題。
動態(tài)測試在理論上幾乎可以驗證所有存在的安全問題,其誤報率也比靜態(tài)測試少。但是,動態(tài)測試也存在著過于依賴程序運行、程序分支路徑覆蓋不全、漏報等缺點。動態(tài)測試還與測試人員的能力及測試用例的準備密切相關(guān),如果被測系統(tǒng)規(guī)模過大,測試用例集合也隨之增大,則會導(dǎo)致漏報率提高。
3.3 嵌入式軟件二進制模糊測試
靜態(tài)和動態(tài)測試方法可能無法有效避免全部的安全問題,若要進一步挖掘安全問題,還需要借助一些其他測試方法。發(fā)現(xiàn)嵌入式系統(tǒng)中的安全問題是一項具有挑戰(zhàn)性的工作,因為嵌入式系統(tǒng)與其他傳統(tǒng)計算機相比,具備體積小、可移植性好、直接與應(yīng)用程序集成等特點;在運行時,它們占用較少的內(nèi)存資源和空間,而相應(yīng)的安全機制占用較多的存儲空間,降低了內(nèi)存的可利用率。因為在受限的嵌入式系統(tǒng)沒有額外的安全機制,模糊測試技術(shù)(Fuzz)作為尋找安全問題最有效的手段之一,一直受到安全測試人員的青睞。在安全程序中使用模糊測試技術(shù)可以幫助發(fā)現(xiàn)系統(tǒng)中未知的漏洞。對于嵌入式環(huán)境下的安全測試,針對二進制文件的模糊測試是十分必要的選擇,此方法可用來排除在編碼過程中出現(xiàn)的大部分安全問題。模糊測試通過向目標插入事先構(gòu)建的輸入來發(fā)現(xiàn)漏洞和故障,對于查找程序問題的效率較高,如內(nèi)存錯誤、空指針引用、格式化字符串、死鎖、無限循環(huán)、不當?shù)馁Y源管理等。如圖2所示,二進制模糊測試一般分為以下5個階段。
圖2 模糊測試一般流程
首先是準備階段,將準備好的被測二進制格式文件進行輸入;其次是模糊數(shù)據(jù)生成,一般模糊數(shù)據(jù)生成就是改變特定的數(shù)據(jù);接下來將模糊數(shù)據(jù)作為輸入進行執(zhí)行和檢測,如果未結(jié)束,將回到數(shù)據(jù)生成階段;周而復(fù)始,直至程序崩潰;最后生成報告。
在通過對二進制代碼進行模糊測試的過程中,測試人員可能面臨的難題是在不同的嵌入式環(huán)境下系統(tǒng)所產(chǎn)生的不同二進制代碼,如不同的編譯器的代碼生成算法、不同的指令集等,導(dǎo)致安全測試人員難以通過相似性來判斷存在的安全問題。為了克服這種困難,可以借助一些第三方開源模糊器加QEMU等仿真器對嵌入式環(huán)境下的二進制代碼進行模糊測試。目前常見的模糊器有以下2種。
(1)American Fuzz Lop
American Fuzz Lop(AFL)是一款基于覆蓋引導(dǎo)的模糊測試工具,其原理是通過記錄輸入樣本的代碼覆蓋率,從而調(diào)整輸入樣本以提高覆蓋率,提高發(fā)現(xiàn)漏洞的概率,AFL模糊器的工作流程大致如下:
①在編譯階段進行插樁(在每個基本塊的開頭插入一段匯編代碼),用來記錄源碼的覆蓋率;
②選擇輸入文件,作為初始測試集;
③將讀入的文件按照策略進行“變異”(按位反轉(zhuǎn)、替換邊界等);
④如果文件更新了范圍,將其保留;
⑤在循環(huán)以上步驟時,若觸發(fā)了crash的文件,將被記錄。
(2)PTFuzzer
PTFuzzer是在AFL的基礎(chǔ)上實現(xiàn)的一款模糊測試工具,它采用了Intel Processor Trace硬件部件來收集程序執(zhí)行的路徑信息,優(yōu)化了原來AFL通過編譯插樁方式獲取程序執(zhí)行路徑信息的方法。由于AFL要Fuzz二進制格式文件,需要借助QEMU的虛擬化支持,在這方面PTFuzzer要優(yōu)于AFL,但是PTFuzzer需要使用Intel系列芯片的PT支持,造成PTFuzzer有一定的局限性,導(dǎo)致在測試嵌入式軟件時可能需要解決嵌入式軟件的平臺支持問題。
綜合比較以上工具特點,使用QAFL(QEMU與AFL的組合)更適合針對嵌入式軟件進行模糊測試,其原因是使用QAFL的組合不依賴于特定的芯片支持,能夠保證在多變的嵌入式環(huán)境下順利進行軟件的模糊測試。
使用二進制Fuzz的方法可以在不依賴程序源碼或者真實運行環(huán)境下對嵌入式軟件進行測試,當與其他漏洞檢測方法如使用代碼靜態(tài)測試工具、人工審查、逆向工程(通過對二進制文件進行反編譯,分析各個代碼模塊的邏輯內(nèi)容與調(diào)用關(guān)系,從而發(fā)現(xiàn)嵌入式系統(tǒng)中可能存在的漏洞的一種技術(shù)手段)進行比較時,基于二進制的模糊測試可以更高效率地發(fā)現(xiàn)諸如緩沖區(qū)溢出、內(nèi)存泄漏、空指針引用、格式化字符串等安全問題。此外,它還具有可以進行大規(guī)模測試且無人值守的優(yōu)勢,因為模糊過程通常是自動化的。模糊測試的技術(shù)特點使其漏洞檢測的準確率接近100%,并且可為每個漏洞提供詳細的回溯調(diào)試信息,降低運維成本,消除誤報帶來的噪音。但是,由于誤報的原因,在進行模糊測試后,還需手動驗證測試結(jié)果以精確定位程序存在的安全問題。
4 結(jié)語
本文歸納了嵌入式環(huán)境中安全風(fēng)險較大的幾種常見安全問題,并討論了嵌入式環(huán)境下的一些測試方法,主要介紹了靜態(tài)測試、動態(tài)測試和幾種二進制的模糊測試工具的特點和原理。但是本文提出的測試方法僅僅是處于軟件測試或軟件開發(fā)周期的其中一個階段,如果希望嵌入式軟件更為健壯、安全,還需要控制好各個環(huán)節(jié),從編碼開發(fā)、測試、維護等階段來提高嵌入式軟件的安全性。
(原載于《保密科學(xué)技術(shù)》雜志2023年2月刊)