李珍,鄒德清,5,王澤麗,金海
(1. 華中科技大學計算機科學與技術學院,湖北 武漢 430074;2. 華中科技大學服務計算技術與系統(tǒng)教育部重點實驗室,湖北 武漢 430074;3. 華中科技大學集群與網(wǎng)格計算湖北省重點實驗室,湖北 武漢 430074;4. 華中科技大學湖北省大數(shù)據(jù)安全工程研究中心,湖北 武漢 430074;5. 深圳華中科技大學研究院,廣東 深圳 518057)
計算機科學技術的發(fā)展在為人類帶來便利的同時,也給惡意分子提供了犯罪的工具。尤其是在網(wǎng)絡空間安全領域,黑客攻擊、數(shù)字資產(chǎn)盜竊、用戶隱私信息泄露等各種網(wǎng)絡安全事件屢屢出現(xiàn),嚴重危害了網(wǎng)絡的進一步發(fā)展和用戶對其的信任度。軟件系統(tǒng)作為網(wǎng)絡空間的核心組件,其本身存在的漏洞是導致這些攻擊的根本原因。軟件漏洞是指軟件在其生命周期(即開發(fā)、部署、執(zhí)行整個過程)中存在的缺陷,而這些缺陷可能會被不法分子利用,繞過系統(tǒng)的訪問控制,非法竊取較高的權限從而任意操縱系統(tǒng),如觸發(fā)特權命令、訪問敏感信息、冒充身份、監(jiān)聽系統(tǒng)運行等。隨著現(xiàn)有軟件系統(tǒng)愈加復雜龐大,漏洞出現(xiàn)頻率不斷提升,急需針對漏洞檢測領域開展系統(tǒng)的研究工作,以便高效及時地發(fā)現(xiàn)軟件系統(tǒng)的漏洞,實時修補,提高網(wǎng)絡空間的安全等級。
依據(jù)分析對象,軟件漏洞靜態(tài)檢測可以分為二進制漏洞檢測和源代碼漏洞檢測兩類。二進制漏洞檢測方法通過直接分析二進制代碼檢測漏洞,漏洞檢測的準確度較高,實用性廣泛;但缺乏上層的代碼結構信息和類型信息,分析難度較大,因此基于二進制代碼的漏洞檢測研究工作相對較少。而源代碼相對于編譯后的二進制代碼擁有更豐富的語義信息,因此更利于快捷地找出漏洞,得到了漏洞檢測研究人員的廣泛關注。
源代碼漏洞檢測針對軟件設計開發(fā)階段,通過提取源代碼模型和漏洞規(guī)則,基于靜態(tài)程序分析技術檢測源代碼中的漏洞,具有代碼覆蓋率高、漏報低的優(yōu)點,但對已知漏洞的依賴性較大,誤報較高。源代碼漏洞檢測方法主要包括基于中間表示的漏洞檢測和基于邏輯推理的漏洞檢測?;谥虚g表示的漏洞檢測方法首先將源代碼轉換為有利于漏洞檢測的中間表示,然后對中間表示進行分析,檢查是否匹配預定義的某個漏洞規(guī)則,從而判斷源程序中是否含有對應漏洞規(guī)則相關的漏洞?;谶壿嬐评淼穆┒礄z測方法將源代碼進行形式化描述,然后利用數(shù)學推理、證明等方法驗證形式化描述的一些性質,從而判斷程序是否含有某種類型的漏洞?;谶壿嬐评淼穆┒礄z測方法由于以數(shù)學推理為基礎,因此分析嚴格,結果可靠。但對于較大規(guī)模的程序,將代碼進行形式化表示本身是一件非常困難的事情?;谥虚g表示的漏洞檢測方法沒有上述局限性,適用于分析較大規(guī)模程序,因此得到了更為廣泛的應用。
本文針對基于中間表示的源代碼漏洞檢測方法開展研究。依據(jù)對中間表示的分析技術,漏洞檢測方法可以分為4類:基于代碼相似性的漏洞檢測、基于符號執(zhí)行的漏洞檢測、基于規(guī)則的漏洞檢測以及基于機器學習的漏洞檢測。其中,第一類方法主要針對由于代碼復制(code clone)導致的相同漏洞進行檢測;后三類方法基于漏洞模式,針對各種原因導致的漏洞進行檢測。
基于代碼相似性進行漏洞檢測的核心思想是相似的代碼很可能含有相同的漏洞,主要包括3個屬性:代碼表征、代碼段級別和比較方法。具體來講,通過代碼表征和代碼段級別抽象地描述代碼段,然后利用比較方法說明如何依據(jù)兩個代碼段表征判斷它們的相似性。
1) 代碼表征
代碼表征的方式有5種,分別是文本、度量、標記、樹和圖表?;谖谋镜谋碚饔捎谌鄙賹Υa語法和語義信息的表達,很少用于檢測或預測漏洞。
基于度量的表征通過從代碼段采集不同的度量,用相應的度量值衡量代碼相似度,主要用于漏洞檢測領域。Chowdhury等[1]基于復雜性、內聚和耦合 3個度量自動預測漏洞。Neuhaus等[2]發(fā)現(xiàn)漏洞構件具有相似的導入和函數(shù)調用的集合,基于此預測一個新的構件是否含有漏洞?;诙攘康谋碚鞣椒ò绦虻恼Z法信息,容易擴展到多類編程語言中,但無法表示比較單元的全部特征,限定條件較多,檢測效果的好壞需要進一步驗證。
基于標記(token)的表征不需要語法分析,僅通過詞法分析將源代碼轉換為一個標記序列,通過比較這些標記數(shù)組的行來發(fā)現(xiàn)相似代碼。ReDeBug[3]能夠迅速發(fā)現(xiàn)操作系統(tǒng)規(guī)模代碼庫中未打補丁的漏洞代碼。它使用特征散列法編碼位向量中的n個標記,使ReDeBug以cache高效方式執(zhí)行相似性檢測,并借助diff補丁代碼段發(fā)現(xiàn)漏洞代碼。Li等[4]將每個文件按行標記,即每行作為一個標記,滑動窗口大小為n,每n個標記作為比較的基本單位。從diff補丁代碼段中提取得到漏洞代碼,當漏洞代碼的n個標記集合為目標代碼的n個標記集合的子集時,則發(fā)現(xiàn)代碼復制。Scandariato等[5]對應用軟件中的構件源碼進行文本挖掘,每個構件用源碼中一系列術語及出現(xiàn)頻率標識,基于這些特征來預測含有漏洞的構件。Yamaguchi等[6]將每個函數(shù)表示為主要 API使用模式的組合。通過抽取每個函數(shù)的類型名和函數(shù)名,嵌入向量空間,使用機器學習方法得到API使用模式,基于此輔助發(fā)現(xiàn)源碼中的漏洞。CP-Miner[7]采用頻繁子序列挖掘技術,以程序中的基本塊為單位識別基本的復制粘貼代碼段,之后發(fā)現(xiàn)復制粘貼代碼段中的缺陷?;跇擞浀谋碚鞣椒ㄔ谠~法級別對代碼復制漏洞有良好的檢測效果,但未考慮到語法語義信息。
在基于樹的表征中,采用樹來表示源代碼中變量、常量、函數(shù)調用以及其他標記的語法結構。Yamaguchi等[8]從源碼中提取所有函數(shù)的抽象語法樹,嵌入向量空間中,使用機器學習方法分析函數(shù)的結構模式,利用函數(shù)的結構模式組合來發(fā)現(xiàn)漏洞。SecureSync[9]采用擴展的抽象語法樹(xAST)來表征漏洞代碼段,用于復制源碼的再現(xiàn)漏洞檢測?;跇涞谋碚鞣椒m然檢測效果較好,但復雜度高,難以用在大規(guī)模軟件系統(tǒng)中。
在基于圖的表征中,圖的節(jié)點表示表達式或語句,邊表示控制流、控制依賴或數(shù)據(jù)依賴。通過分析源代碼的語法結構以及函數(shù)調用關系、控制依賴關系、數(shù)據(jù)流等,構建程序依賴圖(PDG)。匹配圖中的節(jié)點,由這些節(jié)點組成的連通圖稱為相似子圖,由此判斷代碼的相似性。這種語義表征已用于復制檢測、缺陷檢測和漏洞檢測。在漏洞檢測方面,Yamaguchi等[10]采用代碼屬性圖表征函數(shù)源碼來發(fā)現(xiàn)漏洞,代碼屬性圖結合了抽象語法樹、控制流圖和程序依賴圖。CBCD[11]用子圖同構匹配來確定缺陷代碼的 PDG是否是軟件系統(tǒng)PDG的子圖,并提供了4種PDG查詢的優(yōu)化方法。SecureSync[9]采用基于圖的 API(xGRUM)來表征漏洞代碼段,用于檢測針對共享庫的再現(xiàn)漏洞。基于圖的表征方法綜合考慮程序的語法和語義特征,有很好的檢測能力,但建立圖結構代價非常高,尋找圖相似的匹配算法復雜度高,時空效率低,較難運用于大型軟件檢測。
2) 代碼段級別
代碼段是程序比較的單位,這意味著代碼需要以特定的粒度級別進行抽象?,F(xiàn)有的工作包括5個級別的代碼段:不帶上下文的補丁級、切片級、帶上下文的補丁級、函數(shù)片段級和文件/構件代碼段級。在不帶上下文的補丁級別,通過提取前綴為“-”的連續(xù)行(表示刪去的行),從 diff文件中獲取代碼段。這種粒度已用于錯誤檢測。在切片級別,基于程序依賴圖對程序進行切片。由于切片通常保留了程序依賴圖的結構,因此代碼相似性通過子圖間的同構來表示。切片級粒度已用于代碼復制檢測[12]和漏洞檢測[13]。在帶上下文的補丁級別,通過提取前綴為“-”的行和沒有前綴的行,從diff補丁文件中獲取片段。這種粒度已用于缺陷檢測[7]和漏洞檢測[3,4]。在函數(shù)片段級別,函數(shù)作為獨立的單位,已用于漏洞檢測[6,8]和代碼復制檢測[1]。在文件/構件代碼段級別,每個文件/構件都被視為一個單元,這種粗粒度級別主要用于漏洞預測[1-2]。
3) 比較方法
代碼相似性方法中的比較主要包括兩種方法:向量比較和近似/精確匹配。向量比較方法首先將漏洞的表征和目標程序的表征轉換為向量,然后通過比較這些向量來檢測漏洞。近似/精確匹配方法是通過包含關系[3,4,7]、子串匹配[14]、完整子圖同構匹配或近似γ-同構匹配,在目標程序的代碼表征中查找漏洞表征。
基于代碼相似性的漏洞檢測方法只需要單個漏洞代碼實例就可以檢測目標程序中的相同漏洞,但它局限于檢測類型I和類型II的代碼復制[15](即相同或幾乎相同的代碼復制)和部分類型 III的代碼復制[15](如語句的刪除、插入和移動)引發(fā)的漏洞。即使使用人工定義的特征來增強基于代碼相似性的漏洞檢測能力,也很難檢測那些不是由代碼復制引發(fā)的漏洞,因此當用來檢測不是由代碼復制引發(fā)的漏洞時,會導致很高的漏報率。
基于符號執(zhí)行的漏洞檢測方法使用中間語言,結合符號執(zhí)行和約束求解來檢測漏洞。通過使用符號執(zhí)行技術,將程序中變量的值表示為符號值和常量組成的計算表達式,而一些程序漏洞可以表現(xiàn)為某些相關變量的取值不滿足相應的約束。通過判斷表示變量取值的表達式是否滿足相應的約束,來檢測程序是否存在相應的漏洞。約束求解過程一方面判斷路徑條件是否可滿足,根據(jù)判斷條件對分析的路徑進行取舍,另一方面檢查程序存在漏洞的條件是否可以滿足。符號執(zhí)行的過程常常需要利用一定的漏洞分析規(guī)則,分析規(guī)則描述在什么情況下需要引入符號,以及在什么情況下程序可能存在漏洞等信息。通過對漏洞分析初步結果進行進一步的確認處理,得到最終的漏洞分析結果。
Liang等[16]提出了一個基于LLVM中間表征的靜態(tài)分析工具,結合符號執(zhí)行和Z3 SMT解釋器來發(fā)現(xiàn)缺陷,能夠檢測3種類型的程序缺陷,即除零錯誤、指針溢出和死代碼。Cassez等[17]提出了一個靜態(tài)分析工具,能夠分析LLVM中間表征,并檢查是否存在可以到達LLVM中間表征中某個指定錯誤塊的一次運行。Thome等[18]提出一個搜索驅動的約束求解技術,采用基于蟻群優(yōu)化元啟發(fā)式算法的混合約束求解過程,作為任何現(xiàn)有字符串求解器提供的復雜字符串操作的補充。沈維軍等[19]基于動靜態(tài)相結合的程序分析與符號執(zhí)行技術,通過數(shù)值變量符號式提取、靜態(tài)攻擊流程分析以及高精度動態(tài)攻擊驗證來檢測和分析軟件中可能存在的數(shù)值穩(wěn)定性相關安全漏洞。
基于符號執(zhí)行的漏洞檢測方法能夠生成觸發(fā)漏洞的具體輸入,能夠利用符號執(zhí)行工具生成的輸入驗證并分析漏洞。然而由于約束求解器無法求解所有形式的約束,符號執(zhí)行的分析精度也會受到影響;同時由于開銷大,往往無法擴展到大規(guī)模程序。
基于規(guī)則的漏洞檢測方法由專家針對各類漏洞人工分析生成漏洞規(guī)則,在詞法語法解析基礎上,對源代碼建模[20],進行數(shù)據(jù)流分析、污點分析等。數(shù)據(jù)流分析是一種用來獲取相關數(shù)據(jù)沿著程序執(zhí)行路徑流動的信息分析技術,分析對象是程序執(zhí)行路徑上的數(shù)據(jù)流動或可能的取值。數(shù)據(jù)流分析可以獲得程序變量在某個程序點上的性質、狀態(tài)或取值等關鍵信息,而一些程序漏洞的特征恰好可以表現(xiàn)為特定程序變量在特定程序點上的性質、狀態(tài)或取值不滿足程序安全的規(guī)定,因此數(shù)據(jù)流分析可直接應用于檢測程序漏洞。污點分析[21]是一種跟蹤并分析污點信息在程序中流動的技術。在漏洞分析中,使用污點分析技術將所感興趣的數(shù)據(jù)標記為污點數(shù)據(jù),然后通過跟蹤和污點數(shù)據(jù)相關信息的流向,可以分析這些信息是否會影響某些關鍵的程序操作,進而挖掘程序漏洞。
常見的軟件漏洞檢測工具包括開源工具Flawfinder、RATS、ITS4[22-24],商業(yè)產(chǎn)品Checkmarx、Fortify、Coverity[25-27]等。開源工具一般采用簡單的解析器和漏洞規(guī)則,因此誤報漏報高;商業(yè)產(chǎn)品Checkmarx基于源代碼進行數(shù)據(jù)流分析,不需要編譯,解析能力明顯優(yōu)于開源工具;商業(yè)產(chǎn)品Fortify和Coverity基于中間語言進行數(shù)據(jù)流分析,需要對源代碼進行編譯,檢測效果一般優(yōu)于直接分析源代碼的方法,但專家生成的漏洞規(guī)則仍然不夠完善。
基于規(guī)則的漏洞檢測方法中漏洞規(guī)則的生成依賴人類專家,因此主觀性強。漏洞檢測能夠精確定位到漏洞行,但由于人工定義的漏洞規(guī)則很難考慮全各種區(qū)分有漏洞和無漏洞的情況,規(guī)則的不完善導致漏洞檢測具有較高的誤報和漏報[28]。
機器學習技術可以分為3種主要方法。1) 監(jiān)督學習:學習系統(tǒng)基于一組標記的訓練樣本學習所需的模型,其中每個樣本由輸入數(shù)據(jù)(通常是向量)和所需的相應輸出值(標簽)組成。2) 無監(jiān)督學習:在沒有標記訓練數(shù)據(jù)的情況下,學習系統(tǒng)的目標是識別給定數(shù)據(jù)集中的模式和結構。3) 強化學習:通過與動態(tài)環(huán)境的互動來接受獎勵和懲罰,訓練學習系統(tǒng)達到某個目標。應用于漏洞檢測的機器學習技術目前主要涉及前兩種,下面按照是否需要人類專家定義特征分為基于傳統(tǒng)機器學習方法和基于深度學習方法兩類,并分別對其進行介紹。
傳統(tǒng)的機器學習方法通過人工定義特征屬性,然后采用機器學習方法,如支持向量機、k近鄰等進行分類?;趥鹘y(tǒng)機器學習的漏洞檢測方法包括兩類:針對特定漏洞類型的方法和漏洞類型無關的方法。
針對特定漏洞類型的方法前提是借助專家知識(如漏洞原理)將漏洞分為不同類型,而某種類型的漏洞,通過機器學習技術學習漏洞模式。Yamaguchi等[29]針對C程序缺少檢查漏洞,提出了一個在源代碼中自動識別缺少檢查的方法Chucky,靜態(tài)地對源代碼加污點,并識別與安全關鍵對象關聯(lián)的異常條件或缺少的條件;針對 C程序污點類型漏洞,提出了自動推斷搜索模式的方法,給定一個安全敏感的 sink,如內存函數(shù),該方法自動識別相應的source-sink系統(tǒng)以及構建系統(tǒng)中數(shù)據(jù)流和凈化的模式[30]。此外,還有針對格式化字符串漏洞[31]、信息泄露漏洞等的漏洞檢測[32]等。針對特定漏洞類型的方法中,每種方法僅限于檢測一種類型漏洞,而且要求專家定義幫助識別特定類型漏洞的特征。
漏洞類型無關的方法針對各種類型的漏洞,采用機器學習技術,如支持向量機、k近鄰等學習漏洞模式依靠專家手工定義特征來刻畫漏洞。Grieco等[33]采用系統(tǒng)調用作為特征來刻畫漏洞,以整個程序為粒度來檢測漏洞。Neuhaus等[34]采用導入和函數(shù)調用作為特征來刻畫漏洞,以構件為粒度來預測漏洞,采用依賴的名字來預測哪個包中含有漏洞。Shin等[35]采用復雜度、代碼變化和開發(fā)人員活動作為特征來刻畫漏洞,以文件為粒度來預測漏洞。Moshtari等[36]針對跨項目的漏洞預測,對復雜性、耦合度以及新提出的耦合度量指標集進行了評價和比較。Scandariato[37]等將每個構件表征為一系列的源代碼中的詞以及出現(xiàn)的頻率,通過對構件源代碼的文本挖掘來預測一個構件是否含有漏洞。
基于傳統(tǒng)機器學習的漏洞檢測方法依賴于專家手工定義特征屬性,采用機器學習模型自動對漏洞代碼和無漏洞代碼進行分類。但由于輸入機器學習模型的代碼粒度通常較粗,無法確定漏洞行的確切位置。
基于深度學習的方法不需要專家手工定義特征,可以自動生成漏洞模式,在漏洞檢測方面的相關研究目前剛剛起步。Lin等[38]針對跨項目情況,采用深度學習模型在函數(shù)級別檢測漏洞。Xu等[39]采用神經(jīng)網(wǎng)絡方法在函數(shù)級別進行基于代碼相似性的二進制漏洞檢測。Rajpal等[40]針對模糊測試發(fā)現(xiàn)漏洞的過程,采用神經(jīng)網(wǎng)絡從過去模糊探測的輸入文件中學習模式來指導未來的模糊探測。Russell等[41]針對C/C++開源軟件代碼,開發(fā)了一個大規(guī)模函數(shù)級漏洞檢測系統(tǒng),針對詞法解析后的源代碼學習深度特征表征,并利用3個不同的靜態(tài)分析檢測工具的結果構建了一個開源軟件數(shù)據(jù)集。Harer等[42]針對 C/C++程序,采用機器學習方法進行數(shù)據(jù)驅動的漏洞檢測,基于一個靜態(tài)分析器的結果構建了開源函數(shù)數(shù)據(jù)集,比較了應用到源代碼和編譯后代碼的效果。然而目前基于深度學習的漏洞檢測方法存在很多不足,主要表現(xiàn)在以下4個方面:1) 無法精確定位各種類型漏洞,目前工作的漏洞檢測粒度基本都在函數(shù)級,粒度太粗導致無法定位漏洞的具體位置;2) 缺少涵蓋各種類型漏洞的大規(guī)模標注數(shù)據(jù)集;3) 現(xiàn)有工作面向漏洞檢測采用的深度學習模型有限,哪種深度學習模型更適合檢測漏洞,或者更適合檢測哪種類型的漏洞尚不清楚;4) 現(xiàn)有工作只能檢測是否含有漏洞,無法提供更全面的漏洞信息。
在軟件缺陷預測方面,Yang等[43]采用深度學習技術來預測代碼更改中的缺陷。Wang等[44]采用深度信念網(wǎng)絡從源代碼中自動學習程序的語義表征,在文件級預測軟件缺陷。Phan等[45]利用表征程序執(zhí)行流程的控制流圖來自動學習缺陷特征,進行缺陷預測。Li等[46]提出了基于卷積神經(jīng)網(wǎng)絡進行缺陷預測的框架DP-CNN,基于程序的抽象語法樹,利用深度學習來生成有效的特征。Dam等[47]提出能夠自動學習源碼特征,采用樹結構的長短期記憶網(wǎng)絡,來直接匹配抽象語法樹表征的源代碼,用于缺陷預測。然而這些軟件缺陷預測方法無法用于漏洞檢測,因為文獻[43]提出的缺陷預測方法適用于檢測代碼更改中的缺陷,無法針對整個目標程序,文獻[44-47]的方法在文件級或程序級表征程序進行缺陷預測,若應用于漏洞檢測,則粒度太粗導致無法定位漏洞。
在軟件缺陷檢測方面,通常結合針對缺陷報告的信息檢索技術來檢測和定位源代碼中的缺陷。Huo等[48]利用詞法和程序結構信息,學習來自自然語言和編程語言源代碼中的統(tǒng)一特征,提出了一個卷積神經(jīng)網(wǎng)絡NP-CNN,依據(jù)缺陷報告自動定位潛在的缺陷代碼。Xiao等[49]采用卷積神經(jīng)網(wǎng)絡和級聯(lián)森林提取語義和結構特征,根據(jù)缺陷報告來定位缺陷文件。然而缺陷檢測方法不能用于檢測漏洞,主要原因是:一方面,缺陷不一定是漏洞;另一方面,上述缺陷檢測通常依賴缺陷報告,而在漏洞檢測中是無法提供漏洞報告的。
此外,深度學習技術也開始應用到程序分析中與漏洞檢測相關性較小的其他研究領域,如異常檢測[50]、軟件語言建模[51]、代碼復制檢測[52]、API學習[53]、二進制函數(shù)邊界識別[54]、惡意 URL、文件路徑檢測和注冊表鍵檢測[55]、修復程序錯誤[56]、軟件的可追溯性[57]、預測程序的屬性[58]、代碼作者歸屬[59]等。
基于深度學習的漏洞檢測方法不需要專家手工定義特征,可以自動生成漏洞模式,有望改變軟件源代碼漏洞檢測方法,使面向各種類型漏洞的漏洞模式從依賴專家手工定義向自動生成轉變,并且顯著提高漏洞檢測的有效性。然而目前該方法的相關研究剛剛起步,在漏洞定位、數(shù)據(jù)集構建、深度學習模型解釋等方面有待深入研究。
代碼復制的廣泛存在使一個軟件漏洞可能存在于多個應用程序中,修補主機的某個漏洞并不意味著能夠完全排除該漏洞對主機的潛在威脅。因此,當有針對某個漏洞的補丁公布時,應及時檢查主機中其他軟件是否也存在該漏洞,即在給定漏洞和源代碼的前提下,能夠自動判斷源代碼中是否含有該漏洞,如果有,給出具體位置,以便于及時修補。上述問題主要面臨兩個挑戰(zhàn):一是尚不存在能夠用來評測基于代碼相似性進行漏洞檢測研究的數(shù)據(jù)集;二是不存在某個代碼相似性算法適用于所有漏洞。
針對上述問題與挑戰(zhàn),在構建用于評價的數(shù)據(jù)集基礎上,基于漏洞代碼特征,實現(xiàn)基于源代碼相似性的漏洞檢測系統(tǒng) VulPecker[60],降低誤報與漏報。系統(tǒng)整體結構圖1所示,包括兩個階段:學習階段和檢測階段。學習階段用來選擇對給定漏洞有效的代碼相似性算法,選擇的算法反過來指導漏洞簽名的生成以及檢測階段的復制漏洞檢測。
給定一個漏洞及其補丁,該漏洞可以通過描述漏洞補丁的diff文件來刻畫。漏洞補丁diff文件由一個或多個diff塊組成,對于每個diff塊,定義以下兩個特征集合:基本特征和修補特征,如表1所示?;咎卣鲗?中的類型1,包括漏洞的唯一標識符CVE ID、描述漏洞類型的通用弱點枚舉標識符CWE ID、廠商、受影響的產(chǎn)品和漏洞嚴重度。修補特征對應表1中的類型2~類型 6,描述了從修補前代碼段到修補后代碼段的代碼變化。
表1 漏洞diff塊特征
圖1 VulPecker的結構
為了構建數(shù)據(jù)集,首先選擇具有一系列發(fā)布版本且由C/C++語言開發(fā)的開源軟件產(chǎn)品,從美國國家漏洞庫(NVD)中篩選出19個軟件產(chǎn)品?;诤Y選后的產(chǎn)品,構建了一個包含1 761個漏洞(含3 454個漏洞補丁diff 塊)的漏洞補丁數(shù)據(jù)庫(VPD)和一個包含455個漏洞代碼復制實例的漏洞代碼實例漏洞庫(VCID)。diff塊數(shù)量和漏洞代碼復制實例數(shù)量的差距表明,許多 diff塊沒有得到對應的漏洞代碼復制實例。
基于上述構建的數(shù)據(jù)集,直接從 NVD漏洞庫中提取類型1的特征;通過對diff塊進行文本分析和簡單的語法分析,分別提取類型 2和類型6的特征;接著針對漏洞代碼和修補后代碼,采用 Joern[10]工具在函數(shù)級分別生成各自的抽象語法樹(AST),通過gumtree算法[61]對兩棵AST中節(jié)點進行匹配,根據(jù)匹配節(jié)點集合以及不匹配節(jié)點信息,生成從漏洞代碼到修補后代碼的編輯操作序列,最后根據(jù)編輯操作對應的節(jié)點信息提取出diff塊具有類型3~類型5的特征。
代碼相似度算法選擇引擎是 VulPecker的核心部分,用于確定哪個代碼相似性算法對哪個漏洞有效。通過向算法引擎中輸入候選代碼相似性算法、漏洞diff塊特征向量、準確率閾值和VCID數(shù)據(jù)庫,引擎會自動輸出 CVE-算法映射表。整個過程主要包括以下3個步驟,如圖2所示。首先,選擇能夠區(qū)分漏洞代碼和修補后代碼的代碼相似性算法;然后,識別具有最合適代碼段級別的代碼相似性算法;最后,選擇對于VCID具有最低漏報率的代碼相似性算法。
基于上述步驟選擇合適的代碼相似性算法后,需要生成漏洞簽名。漏洞簽名的生成包括兩個步驟。首先,通過提取前綴為“-”的行和沒有前綴的行來獲取漏洞diff代碼,通過提取前綴為“+”的行和沒有前綴的行來獲取修補后diff代碼。根據(jù)每個diff塊以及為該diff塊選擇的代碼相似性算法所使用的代碼段級別,從漏洞軟件的源代碼中提取出漏洞代碼段。然后,對于每個diff塊,對上一步獲得的漏洞/修補后diff代碼和漏洞代碼段進行預處理并表示。因為diff塊中給出的代碼語句可能不完整,因此對于基于樹或圖的代碼相似性算法,需要從漏洞代碼段中提取缺失的部分。根據(jù)為diff塊選擇的代碼相似性算法所使用的代碼表征,來表示預處理后的漏洞/修補后diff代碼和漏洞代碼段,作為漏洞簽名用于漏洞檢測。
圖2 代碼相似性算法的選擇過程
最后,基于已有的 CVE-算法映射表進行漏洞檢測。CVE-算法映射表能夠提供關于指定diff塊的代碼相似性算法及其代碼片段級別、代碼表征和比較方法的信息。給定diff塊和目標程序,在對目標程序經(jīng)過有關空格、格式和注釋等預處理后,通過為diff塊選擇的代碼相似性算法使用的代碼表征生成目標程序簽名。漏洞檢測引擎采用為diff塊選擇的代碼相似性算法使用的比較方法從目標程序簽名中搜索漏洞簽名。如果找到漏洞簽名,則報告目標程序中漏洞的位置。
針對3個開源軟件產(chǎn)品(即Firefox、FFmpeg和Qemu)在2013到2015年公布的246個漏洞,使用上述漏洞的漏洞簽名和 CVE-算法映射表判斷目標產(chǎn)品中是否含有上述漏洞中的一個或多個。VulPecker檢測出了40個在NVD漏洞庫中沒有公布的漏洞。在這些漏洞中,有18個未知漏洞,已報告廠商。對于剩余的22個漏洞進行了手動檢查和確認,在相關軟件的后續(xù)發(fā)布版本中默默地進行了修補,從漏洞發(fā)布到修補的首個版本發(fā)布的平均時間為7.3個月。
現(xiàn)有的漏洞靜態(tài)分析方法存在兩個問題。第一,依賴人類專家定義漏洞特征。由于漏洞特征復雜,即使對專家而言也是一個冗長乏味、主觀性強、易出錯的工作。不同專家定義的漏洞特征可能不同,漏洞特征的質量決定了漏洞檢測系統(tǒng)的有效性。第二,現(xiàn)有的漏洞檢測方法漏報較高。一個具有高誤報的漏洞檢測系統(tǒng)是不可用的,而具有高漏報的漏洞檢測系統(tǒng)是無用的。理想的漏洞檢測系統(tǒng)是同時滿足低誤報和低漏報的,但通常二者很難同時滿足,更好的處理方法是強調低漏報,只要誤報在可接受的范圍內。
借鑒計算機視覺領域中的目標檢測過程,將深度學習用于漏洞檢測領域,主要存在以下三方面挑戰(zhàn):一是目標檢測能夠很自然地利用圖像中的紋理、邊緣和顏色等信息定義候選區(qū)域,漏洞檢測則沒有明顯的細粒度代碼結構來描述漏洞的候選區(qū)域;二是目標檢測擁有海量的人工標注類別的圖像數(shù)據(jù)集,但目前沒有標注好的涵蓋各種類型漏洞的大規(guī)模數(shù)據(jù)集,且人工標注漏洞的難度遠比標注圖像大得多;三是目標檢測采用適合圖像處理的卷積神經(jīng)網(wǎng)絡(CNN)模型來學習特征,然而程序源代碼與圖像不同,更關注語句上下文信息,且漏洞源代碼數(shù)據(jù)具有自身的特點。
為了解決上述問題,本文開展了基于深度學習的漏洞檢測研究。該方法具有很大潛力,因為深度學習不需要人類專家定義特征,但同時也具有挑戰(zhàn),因為深度學習不是為漏洞檢測這種應用而產(chǎn)生的。本文主要探討了將深度學習用于漏洞檢測的指導原則,包括將深度學習用于漏洞檢測的程序表征、代碼粒度以及神經(jīng)網(wǎng)絡的選擇。具體來說,采用代碼段(code gadget)來表征程序,其中代碼段是語義相關的多行代碼(可以不連續(xù)),通過編碼為向量作為深度學習模型的輸入。針對緩沖區(qū)漏洞和資源管理異常漏洞,構建了含61 638個代碼段的訓練集,以代碼段為粒度檢測漏洞,提出了基于深度學習的漏洞檢測系統(tǒng)VulDeePecker[62],漏洞檢測過程如圖3所示。
基于雙向長短期記憶網(wǎng)絡模型(BLSTM)自動學習生成漏洞模式,在不需要人類專家定義特征的前提下,自動檢測目標程序是否含有漏洞,并給出漏洞代碼的位置。該模型包括兩個階段:學習階段和檢測階段。學習階段針對訓練程序,包括以下4個步驟。
步驟1生成代碼段。首先提取庫/API函數(shù)調用,然后針對庫/API函數(shù)調用的每個參數(shù)提取一個或多個程序切片,最后將針對同一個庫/API函數(shù)調用的多個切片組合成為一個代碼段。
步驟 2為代碼段加標簽。根據(jù)已知的漏洞信息及漏洞位置,給生成的代碼段加漏洞標簽“1”或無漏洞標簽“0”。
步驟 3將代碼段轉換為向量。首先將代碼段轉換為符號表征來容納更多的語義信息,然后將符號表征轉換為向量,作為BLSTM神經(jīng)網(wǎng)絡的輸入。
步驟 4訓練 BLSTM 神經(jīng)網(wǎng)絡。將轉換為向量的代碼段及其標簽輸入標準的BLSTM神經(jīng)網(wǎng)絡進行訓練。
檢測階段針對目標程序,包括步驟5~步驟7,其中步驟5與步驟1類似,步驟6與步驟3類似。在步驟7中,對代碼段進行分類。采用學習階段訓練好的BLSTM神經(jīng)網(wǎng)絡,對目標程序的代碼段進行分類,若分類為 1,則為有漏洞,否則為無漏洞。
本文針對能否同時處理多類漏洞、人類經(jīng)驗能否改進有效性、與其他靜態(tài)檢測方法的有效性比較這3個方面對VulDeePecker的有效性進行了評價。實驗結果表明,VulDeePecker可以應用到多類漏洞,其有效性與安全相關庫/API函數(shù)的個數(shù)有關;人類經(jīng)驗可用于選擇和安全有關的庫/API函數(shù),能夠改進 VulDeePecker的有效性;VulDeePecker比人工定義規(guī)則的靜態(tài)分析工具(開源工具和商業(yè)工具)更有效,比基于代碼相似性的漏洞檢測方法具有更低的漏報,其有效性受數(shù)據(jù)量的影響。此外,VulDeePecker在 Xen、Seamonkey和Libav這3個開源軟件產(chǎn)品中檢測到4個在NVD漏洞庫中未公布的漏洞,這些漏洞在相應軟件的后續(xù)版本中默默地進行了修補。而這些漏洞幾乎未能被其他漏洞檢測系統(tǒng)檢測到。更準確地說,一個漏洞檢測系統(tǒng)檢測出了4個漏洞中的1個,漏掉了3個,而其他漏洞檢測系統(tǒng)漏掉了全部。
圖3 VulDeePecker的漏洞檢測過程
本節(jié)對第6節(jié)和第7節(jié)實例解決方案的局限性進行闡述,并展望了未來的漏洞檢測研究工作。
基于源代碼相似性的漏洞檢測系統(tǒng)VulPecker的局限性主要表現(xiàn)在以下方面:首先,目前的實驗集中于 C/C++開源軟件,雖然VulPecker本身對語言沒有限制,但需要針對其他語言程序(如Java或者python)的效果進行實驗研究,也有待于擴展到中間語言等級別;其次,VPD和VCID數(shù)據(jù)庫的構建尚不完善,如在創(chuàng)建VPD的過程中使用了啟發(fā)式方法。盡管通過取樣并進行人工分析驗證了啟發(fā)式能產(chǎn)生相對正確的結果,但有待通過大規(guī)模的實驗進行進一步的驗證。最后,在未來的工作中,需要在性能方面進行改進,使其能夠針對大規(guī)模軟件進行檢測,提高可擴展性。
面向源代碼的軟件漏洞智能檢測系統(tǒng)VulDeePecker雖然檢測效果比傳統(tǒng)的漏洞檢測方法更好,但仍存在一些局限性。第一,目前只能處理C/C++程序,未來工作希望能夠適用于處理更多其他的編程語言。第二,目前只能處理與庫/ API函數(shù)調用相關的漏洞,如何針對其他類型漏洞提取代碼段需要進一步研究。第三,雖然代碼段可同時基于數(shù)據(jù)依賴和控制依賴分析,但是目前借助商業(yè)工具提取的代碼段只涵蓋了數(shù)據(jù)依賴。提高數(shù)據(jù)依賴分析的利用以及采用控制依賴提高漏洞檢測能力是未來的一項重要工作。第四,在標記代碼段、轉化為符號表征等階段使用了啟發(fā)式方法,未來需要對啟發(fā)式給漏洞檢測結果的有效性影響進行評估。第五,采用的深度學習模型局限于BLSTM神經(jīng)網(wǎng)絡,對其他可用于漏洞檢測的神經(jīng)網(wǎng)絡的有效性需要進一步研究。最后,目前用于實驗的數(shù)據(jù)集僅包含緩沖區(qū)漏洞和資源管理異常漏洞,需要利用更多漏洞類型、更大規(guī)模的數(shù)據(jù)集對方法的有效性進行評測。
總體來說,未來將陸續(xù)開展以下三方面的研究工作:1) 研究面向訓練程序的代碼段標注,基于公開漏洞數(shù)據(jù)庫中的大量數(shù)據(jù),對訓練程序中的代碼段進行自動標注,并實現(xiàn)已標注代碼段的數(shù)據(jù)量擴充,有望構建涵蓋各種類型漏洞的大規(guī)模標注數(shù)據(jù)集;2) 研究面向訓練程序的漏洞模式智能化學習,采用面向漏洞代碼數(shù)據(jù)特性的深度學習模型實現(xiàn)各類型漏洞模式的自動生成,有望給出哪種深度學習模型更適合檢測哪種類型的漏洞;3)研究面向目標程序的漏洞檢測與模型解釋,基于代碼段進行多層級漏洞檢測,有望提供除是否含有漏洞外更全面的漏洞信息,并且基于漏洞檢測結果進行深度學習模型的解釋,進一步改進模型的有效性。
基于源代碼的軟件漏洞靜態(tài)檢測是保障網(wǎng)絡空間安全技術的重要研究領域。通過對給定源代碼進行分析,檢測軟件系統(tǒng)中存在的安全缺陷,從而維護整個系統(tǒng)的穩(wěn)定運行。本文從實現(xiàn)源代碼漏洞檢測的方法角度出發(fā),以采用的技術類型為分類依據(jù),總結了現(xiàn)有的源代碼漏洞檢測研究工作,并重點闡述了基于源代碼相似性的漏洞檢測系統(tǒng)以及基于深度學習的軟件漏洞智能檢測系統(tǒng)兩個方案。在此基礎上,分析了源代碼漏洞檢測研究存在的問題,并對未來的研究工作進行了展望。