胡 飛,陳 昊,王 媛,弋 雯,胡 穎,劉寶英
(1.西北大學 信息科學與技術學院,陜西 西安 710100;2.中國勞動關系學院,北京 100048;3.新華社技術通信局,北京 100803)
以5G通信、物聯網、大數據[1]為代表的先進技術已經融入人們的生活當中,計算機軟件在人們的生活中隨處可見,軟件已經成為經濟、軍事、文化和社會的重要引擎。近年來網絡攻擊[2]、軟件崩潰[3]、信息泄露[4]等事件屢見不鮮,給國家和社會造成了巨大的經濟損失,因此軟件安全問題不可忽視,軟件漏洞的檢測也迫在眉睫[5]。
最近幾年來美國國家漏洞數據庫[6](National Vulnerability Database,NVD)的軟件漏洞數量持續增加,據NVD報告,2019年統計的漏洞數量達到了140 000條,這一數量相比1999年增長了將近10倍。軟件的快速發展和擴大同樣也引起了更多的軟件漏洞產生。由于諸多原因,在軟件開發過程中,無論是軟件的復雜度還是開發者協作,又或者是程序員在編程時缺乏安全的編碼意識,都會引發軟件安全問題,因此軟件漏洞的產生無可避免。
序列化是軟件開發過程中一種用于捕獲程序狀態的機制,用于持久化運行時狀態或跨進程邊界的過程調用。它涉及到將內部運行時表示轉換為二進制或字符數據流并返回[7]。簡單來說,序列化就是將對象的狀態信息持久化存儲,比如保存到文件或者數據庫中用于持久化,反之,反序列化就是將序列化的數據反向重新構建對象,恢復對象的狀態信息。早在2006年反序列化漏洞就已經出現,但由于造成的影響較小,因此未引起大多數安全研究人員的注意[8]。2015年Java反序列化漏洞迎來了關注,Apache Commons Collections庫中報告發現一個漏洞,包含該漏洞的開源組件Commons Collections庫被各種主流的Web應用所使用,影響范圍十分廣泛,從此之后,有關反序列化漏洞的研究開始流行起來,該漏洞使得許多企業系統可被遠程代碼執行利用。2016年,反序列化漏洞攀升至OWASP[9](Open Web Application Security Project)前十的第八位。從圖1可以看到,自2015年,每年報告在通用漏洞披露[10](Common Vulnerabilities and Exposures, CVE)中的Java反序列化漏洞數量一直不低于30條,在2016年達到了最高,高達65條。

圖1 Java反序列化漏洞CVE數量統計圖
許多面向對象編程的語言都支持序列化,大多數這些語言的標準庫中都包含了對序列化的支持。在Java語言中,本地序列化對象是用非語言構造的,例如繞過構造函數,對象狀態是由反序列化的數據恢復的。反序列化漏洞除了在Java中存在,在腳本語言PHP、Python中同樣也存在。反序列化漏洞相較于其他漏洞,如SQL注入[11](SQL Injection)、拒絕服務[12](Denial Of Service,DOS)、緩沖區溢出[13](Buffer Overflow)等,它通常所需要的權限較低,但是卻能獲得較高的管理權限,因而造成的風險危害大,具有很高的威脅性。
目前,人工智能領域的快速發展,機器學習和深度學習技術的不斷深入,為軟件安全漏洞領域提供了新的檢測思路,研究人員應用這些技術和方法取得了較好的效果。針對Java反序列化漏洞[14],該文旨在運用圖神經網絡檢測Java反序列化漏洞調用鏈。圖神經網絡是基于圖結構知識訓練神經網絡模型,能夠捕獲漏洞更深層的語義和語法信息,為漏洞檢測研究領域提供了方向。通過分析Java反序列化調用鏈的模式和行為,使用圖神經網絡深度學習模型來識別反序列化漏洞,從而檢測出Java反序列化漏洞調用鏈。
針對Web漏洞,許多學者依據上述漏洞檢測方法進行了研究。Jovanovic[15]通過靜態源代碼分析,來解決Web應用程序易受攻擊的問題,使用上下文敏感的數據流分析來檢測程序中的漏洞。他提出靜態分析[16]工具Pixy,用于檢測PHP腳本程序中的跨站腳本攻擊(Cross Site Script Attack,XSS)和SQL注入漏洞[11]。Livshits[17]提出對象污點傳播的方法,從源頭(Source)到匯聚點(Sink)進行分析來檢測漏洞。Viktoria等人[18]使用動態分析的方法觀察Web應用程序的運行過程定制正確的行為規范,借助符號執行[19]的方法識別出違反正確規范的程序路徑,從而檢測應用程序的邏輯錯誤。Li等人[20]提出了檢測C語言程序漏洞的檢測系統VulDeePecker,通過提取程序源碼的函數塊進行數據流分析,對函數體切片,使用自然語言處理領域的向量嵌入技術Word2vec[21]對代碼切片編碼,將編碼的向量輸入到雙向長短記憶神經網絡(Bidirectional Long Short Term Memory Networks,BiLSTM),選擇二分類監督學習來檢測漏洞。然而,上述的這些漏洞檢測方法在應用到Java反序列化漏洞檢測時效果不佳。
Apache Commons Collections中的反序列化漏洞在2015年被公布,研究人員描述了Java反序列化漏洞調用鏈的執行過程[22]。為了更好地挖掘反序列化漏洞,Federico Dotta在2016年開發出Java Deserialization Scanner[23]開源插件,該插件可以用于Burp Suite上檢測和利用反序列化漏洞。Carettoni則提出了針對Java反序列化漏洞的防御方案Serial Killer,即采用白名單或者黑名單的方式,手動控制添加禁止危險的工具類[24]。還有一些類似Java Deserialization Scanner的一系列小插件Freedy[25]、SuperSerial[26]等等,它們依托NCC組織開發的Burp插件,作為Burp的擴展來利用反序列化漏洞。這些反序列化漏洞檢測工具可以加深漏洞安全研究人員對反序列化漏洞調用鏈執行過程的理解,給反序列化漏洞調用鏈的檢測提供了參考,但缺乏自動化檢測的能力,并且需要人工專家進行審計,因而存在較大的局限性。
2018年,Netflix高級安全軟件工程師Ian Haken提出了一種基于Java字節碼分析的反序列化漏洞調用鏈檢測方法Gadget Inspector[27]。該工具基于靜態分析的方法首先將Java開發工具包(Java Development Kit,JDK)中所使用到的jar包以及第三方公共組件庫解析成字節碼,確立調用鏈的Source和Sink,應用污點分析的技術判斷入口點到匯聚點的連通路徑是否可達,從而檢測可以利用的反序列化調用鏈。該方法是目前使用廣泛的反序列化漏洞調用鏈檢測方法,但是由于采用基于靜態污點分析的技術,Gadget Inspector存在一定的缺陷,由于搜索路徑沒有覆蓋到完整的子類和接口實現類,存在較高的誤報率和漏報率。
本節將介紹基于圖網絡的反序列化漏洞調用鏈檢測方法SerialFinder。文章首先對反序列化漏洞調用鏈的檢測流程進行概述,然后介紹多關系邊圖神經網絡模型學習,包括多邊關系圖構建、學習節點和邊的向量化表示、基于圖多邊調用關系的聚合,最后介紹圖神經網絡模型的訓練和檢測。
該文利用圖神經網絡構建反序列化漏洞檢測模型。該方法的主要思想是將已知的包含反序列化漏洞調用鏈的公共組件庫作為輸入,然后進行數據收集工作。對于數據收集過程,首先會將公共組件庫解析保存至圖數據庫,然后基于多關系邊提取調用鏈子圖并對數據標注,完成訓練數據的收集工作。對收集到的調用鏈子圖進行特征提取和多關系邊調用圖構建,使用工具對節點和邊進行向量初始化。將調用鏈子圖處理后的向量信息輸入到GIN進行訓練,保存驗證集上效果最好的模型。最后,使用訓練好的圖網絡模型對未知的公共組件庫進行檢測,檢測未知公共組件庫中的反序列化漏洞調用鏈。
圖2詳細描述了SerialFinder檢測框架。

圖2 SerialFinder檢測框架
依據調用鏈節點的執行順序構建調用圖,構建完好的多關系邊調用圖如圖3。其中每一個調用鏈子圖對應一個多關系邊調用圖。調用圖為有向圖,圖包含方法節點和鄰接關系邊。函數調用圖可用于描述方法之間的一般調用,多關系邊調用圖在函數調用圖的基礎上進行了改進,擴展為由6種關系邊組成的調用圖。為了學習到每個方法節點的向量表示,在圖網絡模型學習階段,在每個節點上增添Self-Loop邊,使邊的數量加倍,這些Self-Loop邊有利于不同調用圖之間的信息傳播。下面分別對6種關系依賴邊進行介紹。
(1)ALIAS邊:保存Java多態機制中的動態鏈接關系。
(2)InvokeStatic邊:靜態方法調用指令,保存方法節點對靜態方法的調用關系。
(3)InvokeSpecial邊:保存類中私有方法節點、構造方法節點的方法調用關系。
(4)InvokeVirtual邊:動態分配調用指令,保存方法節點對實例方法的調用關系。
(5)InvokeInterface邊:接口調用指令,保存接口引用對實例方法的調用關系。
(6)InvokeDynamic邊:方法句柄調用指令,保存方法句柄發起的調用關系。

圖3 調用鏈屬性圖和多關系邊調用圖示例
為了將調用鏈子圖轉化為圖神經網絡模型可以輸入的上下文表示向量,首先將提取出的方法節點信息和邊的關系信息進行向量化。具體操作步驟如下:
(1)構建方法節點的語料庫。將方法節點的方法簽名進行預處理,分離出方法簽名的信息,包括方法所屬的類、方法的返回類型、方法名、方法的參數列表。基于所有存儲在圖數據庫中的方法節點,收集了數十萬方法節點的方法簽名用作構建方法節點的語料庫。
(2)構建邊關系的語料庫:方法節點和邊關系為調用鏈子圖的不同信息,因而對于邊關系,單獨將邊的關系提取出來構建語料庫。其中包含ALIAS、InvokeStatic、InvokeSpecial、InvokeInterface、Invoke-Virtual、InvokeDynamic這6種調用邊關系。
(3)訓練word2vec模型:選擇了一種較為流行的向量化工具─word2vec,它是語言模型的一種,能從大量的文本語料中以無監督學習的方式來學習知識模型,廣泛應用于自然語言處理領域。該文選擇CBOW模型用來學習方法節點和邊關系在詞典中的向量表示。CBOW的處理方式是在已知詞wt的上下文,例如上下文為wt-3、wt-2、wt-1、wt+1、wt+2、wt+3的情況下預測當前詞wt的概率。CBOW模型與神經網絡十分類似,主要包含三層:首先是輸入層,讀取上下文的詞向量;然后是隱藏層,對輸入層的詞向量進行累積求和;最后是輸出層,原理上是一個哈夫曼樹,基于Softmax函數來輸出預測的概率。將收集到的方法節點的語料庫輸入到CBOW模型,模型對語料庫中的詞的向量進行隨機初始化,然后基于隨機梯度下降(Stochastic Gradient Descent,SGD)的學習方式更新模型的參數和詞的向量,學習完成后可以得到一個詞典,詞典是一個詞和詞向量對應的映射表。通過學習得到的CBOW模型,可以將方法節點和邊關系進行向量化。
(4)為了捕獲調用鏈子圖的完整信息,將調用鏈子圖的方法節點和邊關系經過CBOW模型嵌入向量后按照調用順序進行拼接,其中每一個調用鏈子圖對應一個N×100維的向量。
GAT、GCN等流行的圖神經網絡大多采用鄰居節點聚合的方式,該文所使用的圖同構網絡也采用了這種設計,但在此基礎上進行了改進。圖4展示了圖同構網絡的相鄰節點聚合方式。所有的節點均有自己的特征向量,圖中展示了3種類型的節點,分別是1號節點、2號節點、3號節點。其中1號節點位于最外層,1號節點與2號節點相連,它們將自己的特征向量以一種特定規則聚合計算合并到2號節點,同樣2號節點聚合特征向量到3號節點。每個節點由其鄰居節點的狀態和信息所得到。每一次迭代都會進行若干次聚合,在重復了固定次數的迭代之后,計算聚合了相鄰節點信息的節點的特征向量。

圖4 多關系相鄰節點聚合圖
該文對多關系邊調用圖的聚合進行改進,在計算相鄰節點聚合時,采用MLP機制。圖5為多關系邊調用圖的聚合方式,其中在第一層不采用MLP,因為節點的初始特征向量不用于MLP的計算。使用多層感知機(MLPs)對函數建模,符合節點的單射性計算。

圖5 多關系邊調用圖聚合圖
相比于傳統機器學習需要對特征進行人工定義,該文采用的圖同構網絡對嵌入的向量進行自動化學習。圖同構網絡在流行的圖神經網絡上進一步革新,保證圖結構的單射性,提升了圖神經網絡檢測的準確率。
模型的參數對于模型效果有很大影響,為了提升模型的準確率,該文選擇一個基準數據用于模型的參數調優。由于GPU資源條件限制,使用多個批次進行網絡的訓練。對于深度學習網絡,模型需要依靠損失函數計算損失值,從而對模型的參數進行更新。該文使用交叉熵損失函數,因為它十分適合圖的分類任務。神經網絡的神經元需要通過激活函數激活,因而激活函數的選擇也十分重要。在圖網絡的初始層選擇Tanh激活函數,在隱藏層采用Tanh激活函數,在消息傳遞層選擇Relu激活函數,使用不同的激活函數能提升模型的學習能力。對于圖神經網絡,考慮到相鄰節點的聚合方式,選擇Sum的聚合函數,考慮相鄰所有節點的特征向量。對于圖的二分類問題,模型的最后一層需要將高維向量映射到[0,1]空間,Softmax函數提供了這種能力。選擇Softmax作為圖同構網絡的最后一層,經過Softmax層,可以得到圖網絡模型對圖的一個分類結果,即0或1,其中0代表圖是不包含漏洞的,1代表圖包含漏洞,即存在反序列化漏洞。
在模型檢測階段,首先對公共組件庫生成對應的圖數據庫進行保存, 然后依據圖搜索算法提取并篩選由Source到Sink的調用鏈子圖。對調用鏈子圖提取靜態特征和多關系邊調用圖,經向量化嵌入后輸入到訓練好的圖網絡模型進行預測,從而檢測出反序列化漏洞調用鏈。
將調用鏈子圖作為圖神經網絡的輸入,當模型給出的預測結果為1時,則表明調用鏈子圖存在反序列化漏洞調用鏈。該檢測方案可以定位到調用鏈子圖,實現反序列化漏洞的細粒度定位。
為了訓練一個有效的深度學習模型來實現對Java反序列化漏洞調用鏈的檢測,文中的訓練數據來自于現實世界真實存在的反序列化漏洞。在實驗中,從多個受影響的公共組件庫中進行數據搜集工作,涉及到的公共組件庫有Commons-Collections-3.1、Commons-Collections4-4.0、FileUpload1.3.1、XStream1.4.15、Hibernate5.0.7.Final等。由于實際存在漏洞的調用鏈極其缺乏,設計了基于多關系邊提取調用鏈子圖的方法,對包含漏洞調用鏈的子圖進行提取擴充,因為調用鏈是已經被證實存在反序列化漏洞的,因而包含漏洞調用鏈的子圖即為存在漏洞的數據。該文按照反序列化漏洞調用鏈所屬的組件不同進行分類,表1給出了具體的數據信息。其中Commons-Collections、JDK、Hibernate都是基于JDK的反序列化API引發漏洞,可以歸結為JDK API類,而XStream反序列化依靠fromXML()函數進行,因而將XStream單獨歸為一類。調用鏈主要來自于4個公共組件庫,從原始調用鏈數目來看導致反序列化漏洞的調用鏈實際上非常少,這對于深度學習模型的訓練來說是十分欠缺的。基于文中的調用鏈子圖提取方法,提取出的調用鏈子圖的總數量為113 670,其中正負樣本集比例為1∶1,漏洞調用鏈子圖和非漏洞調用鏈子圖數目均為56 835。收集到的調用鏈子圖數據,為圖神經網絡模型提供了充足的數據基礎。

表1 調用鏈子圖數據分布
文中圖同構網絡模型訓練的硬件配置為:Ubutun18.04 64位、NVIDIA GeForce RTX 2080 GPU、Intel Core i9-9940 CPU。基于深度學習平臺TensorFlow來搭建GIN漏洞檢測模型,在模型訓練前,將收集到的訓練數據按照8∶1∶1的比例分離,訓練集占80%,驗證集和測試集各占10%。在訓練過程中,保存在驗證集上評估效果最好的模型用于與其他工具進行比較。為了對公共組件庫進行字節碼層面的解析,借助了SOOT這個工具來進行解析,同時使用Neo4j圖數據庫來保存類和方法對應的節點以及邊的關系。在向量化調用鏈子圖的節點時,使用word2vec這個自然語言模型來處理,同時將每個節點的向量設置為100維向量,對圖中的節點數量沒有進行限制。在得到最終的模型之前,選擇樣本集來對模型的超參數進行自動化調優,其中每個batch的最大節點數范圍為(32、64、128),隱藏層的層數范圍為(64、128、256),epoch設置為100,并且在25輪訓練中沒有得到更好效果模型的時候進行自動停止。
將SerialFinder與最近的反序列化漏洞調用鏈檢測方法Gadget Inspector進行比較。該工具是基于靜態分析的方法,它首先將Java環境JDK中所使用到的jar包以及第三方工具類解析成字節碼,確立調用鏈的入口點(Source)和匯聚點(Sink),應用污點分析的技術判斷入口點到匯聚點的連通路徑是否可達,從而檢測出可以利用的反序列化漏洞調用鏈。選擇3個已知的存在反序列化漏洞的公共組件庫Commons-Collections-3.1、Hibernate5.0.7.Final、Commons-Collections4-4.0,因為這些組件庫被反序列化漏洞研究人員廣泛研究和利用。基于這三個公共組件庫對比兩種方法的漏洞檢測能力,最后分析檢測出的調用鏈是否為漏洞調用鏈。
該文選擇十折交叉驗證的方法來評估模型的效果,即將數據分為相同數量的10份,每次訓練選擇其中的9份用于模型訓練,另外1份用于模型的測試階段。使用該標準方法對于模型預測的評估有很強的泛化能力。在進行實驗結果分析中,選擇了廣泛使用的度量指標,分別有:準確率(Accuracy)、查準度(Precision)、召回率(Recall)、F1-score、誤報率(False Positive Rate,FPR)。同時,在交叉驗證中對上述的度量指標計算各自的幾何平均值,幾何平均值與算術平均值相比更加可靠。
(1)不同邊關系選擇對比。
為了評估基于不同關系邊構圖對SerialFinder檢測能力的影響,將SerialFinder與基于兩種關系邊構圖的方法進行對比。其中基于兩種關系邊構圖的方法,只包含ALIAS邊和Call邊,Call邊為方法節點間的通用調用關系。選取的方法包含6種關系邊ALIAS、InvokeStatic、InvokeSpecial、InvokeInterface、Invoke-Virtual、InvokeDynamic。實驗在收集到的三種類型的數據上進行對比。為了方便實驗描述,將基于兩種關系邊構圖的方法稱作Two-relation。表2為兩種處理方法的Accuracy、Precision、Recall、F1-score在三種類型數據上的平均值對比結果。

表2 SerialFinder與Two-Relation在5個指標上的平均值 %
從表2可以得出,SerialFinder在三種類型數據上的平均Accuracy、Precision、Recall、F1-score分別達到97.0%、94.0%、100.0%、96.9%;通過比較發現,在前四個指標上,SerialFinder分別比Two-Relation高出了12.4百分點、14.0百分點、7.7百分點以及11.2百分點,并且在FPR指標上SerialFinder比Two-Relation低了17.2百分點。因此,可以得知依賴6種關系邊構圖的方法能提升SerialFinder的檢測性能。
(2)不同圖神經網絡對比。
為了評估圖同構網絡GIN對SerialFinder檢測能力的影響,選擇圖神經網絡研究領域中使用比較多的圖神經網絡模型進行對比,對比的模型包括門控圖神經網絡GGNN、圖卷積神經網絡GCN、圖注意力網絡GAT,實驗數據選擇該文收集到的三種類型數據。在使用GCN、GAT、GGNN進行網絡訓練之前,首先會提取調用鏈子圖并使用word2vec對圖中的節點和邊進行向量化。在三種類型的數據上進行實驗,結果如表3~表5所示。

表3 不同圖神經網絡在JDK API數據集上的Accuracy、Precision、Recall、F1-score、FPR %

表4 不同圖神經網絡在XStream數據集上的Accuracy、Precision、Recall、F1-score、FPR %

表5 不同圖神經網絡在JDK和XStream混合數據集的Accuracy、Precision、Recall、F1-score、FPR %
從表中的數據可以計算得到,GIN在三種類型數據上的F1-score平均值為96.9%,分別較GGNN(88.8%)、GCN(73.4%)、GAT(91.7%)高出了8.1百分點、23.5百分點、5.2百分點,意味著GIN在保證檢測的準確率高的同時,可以檢測出更多的漏洞樣本。在FPR指標上,GIN在三種類型數據上的平均FPR值為5.9%,相較于GGNN(16.8%)、GCN(11.6%)、GAT(16%)分別低了10.9百分點、5.7百分點、10.1百分點,這意味著GIN網絡檢測出漏洞樣本的誤報率很低。SerialFinder使用的GIN網絡在三種類型數據上均表現出最好的性能。
(3)不同Java反序列化漏洞檢測方法對比。
為了評估SerialFinder對Java反序列化漏洞調用鏈的檢測能力,實驗選擇Java語言常見的三個公共組件庫:Commons-Collections-3.1、Commons-Collections4-4.0、Hibernate5.0.7.Final。在這三個公共組件庫上展開調用鏈的檢測工作,與Gadget Inspector進行對比。對識別為漏洞的調用鏈,還需要對其進行人工分析,才能確定是否為惡意的漏洞調用鏈。本節采用命中率來比較兩種方法檢測反序列化漏洞的能力,命中率即漏洞調用鏈占全部調用鏈的比值,見如下公式。
SerialFinder和Gadget Inspector在三個公共組件庫上的命中率如表6,在Commons-Collections-3.1、Commons-Collections4-4.0、Hibernate5.0.7.Final上,SerialFinder的命中率分別為67.0%、75.0%、50.0%,相比Gadget Inspector 分別高出了17.0百分點、25.0百分點以及50.0百分點,平均高出了近31百分點。可以得知,SerialFinder表現出更好的反序列化漏洞調用鏈檢測能力。

表6 SerialFinder與Gadget Inspector在3個公共組件庫上的命中率 %
(4)檢測性能對比。
為了評估SerialFinder和Gadget Inspector的檢測性能,選擇Commons-Collections-3.1、Commons-Collections4-4.0、Hibernate5.0.7.Final三個公共庫進行檢測,記錄多次測試的平均檢測時間。
SerialFinder的圖網絡模型訓練需要若干個小時,但是訓練開銷是一次的,不需要重新訓練和部署,因而可以忽略不計。表7顯示了SerialFinder和Gadget Inspector在三個公共組件庫上的檢測時間,可以計算得到SerialFinder對三個公共庫的平均檢測時間為21 s,Gadget Inspector對三個公共庫的平均檢測時間為43 s,SerialFinder相比Gadget Inspector的檢測時間低了22 s。因此可以得知文中方法有著更高的檢測效率。

表7 SerialFinder 和Gadget Inspector在三個公共庫上的運行時間 s
在目前的漏洞檢測技術中,靜態分析的方法需要人工專家來制定規則,不但要耗費大量的人力,而且在很大程度上依賴于定義規則的準確性。動態分析的方法需要程序完好的運行,具備程序運行的可行性條件,對于不同的軟件需要準備不同的運行環境,有較高的時間和運行成本。深度學習的方法,可以避免人工專家定義特征和規則,能有效縮小代碼審計的范圍,實現漏洞檢測的自動化。該文提出基于圖神經網絡檢測反序列化漏洞的方法SerialFinder,實現了一種自動化的Java反序列化漏洞調用鏈檢測原型系統。為了評估SerialFinder的檢測能力,選擇3個已知的公共組件庫與Gadget Inspector進行對比,實驗結果表明,SerialFinder檢測出了更多的反序列化漏洞調用鏈,并且有更高的命中率;在時間性能的比較中,SerialFinder的運行時間更短,有更高的檢測效率。