王 劍 匡洪宇 李瑞林 蘇云飛
(國防科技大學(xué)電子科學(xué)學(xué)院 長沙 410073)
在馮諾依曼體系下,軟件漏洞不可避免?,F(xiàn)代軟件的規(guī)模越來越大,功能越來越復(fù)雜,導(dǎo)致軟件漏洞層出不窮。近年來各種開源社區(qū)的興起,使得代碼共享、協(xié)作開發(fā)的編程思想蔚然成風(fēng)。當(dāng)前,很多企業(yè)所使用的軟件都是在開源庫的基礎(chǔ)上進(jìn)行開發(fā)的。因此,對(duì)源代碼進(jìn)行漏洞檢測能盡早發(fā)現(xiàn)軟件漏洞,保證軟件系統(tǒng)的安全性。
傳統(tǒng)的源代碼漏洞檢測方法主要分為兩類。一類是基于靜態(tài)分析的檢測方法,包括基于邏輯推理的抽象解釋[1]和模型檢驗(yàn)[2]方法,基于抽象語法樹[3]、控制流圖[4]、數(shù)據(jù)流圖[4]等中間表示形式的程序分析方法;另一類是動(dòng)態(tài)檢測方法,包括模糊測試[5]、符號(hào)執(zhí)行[6]、污點(diǎn)分析[7]等。基于靜態(tài)分析的檢測方法根據(jù)人工經(jīng)驗(yàn)和專家知識(shí)構(gòu)建相應(yīng)的漏洞模式進(jìn)行檢測,其代碼覆蓋率高,但準(zhǔn)確率低、漏報(bào)高。基于動(dòng)態(tài)分析的檢測方法需要將源碼編譯成二進(jìn)制文件后運(yùn)行程序進(jìn)行檢測,其準(zhǔn)確率高,但效率低、開銷大,通常用于缺乏源碼的二進(jìn)制軟件漏洞檢測。
在大數(shù)據(jù)驅(qū)動(dòng)下,深度學(xué)習(xí)技術(shù)逐漸應(yīng)用于漏洞檢測[8]。Lin等人[9,10]設(shè)計(jì)了一種基于Bi-LSTM神經(jīng)網(wǎng)絡(luò)模型的漏洞檢測方法。該方法利用抽象語法樹表示函數(shù)源碼,可實(shí)現(xiàn)跨項(xiàng)目函數(shù)的遷移表示和漏洞檢測。他們還設(shè)計(jì)了一種LSTM框架,實(shí)現(xiàn)了對(duì)異構(gòu)數(shù)據(jù)源在函數(shù)粒度上的漏洞檢測[11]。同時(shí),Liu等人[12]提出了一種基于深度學(xué)習(xí)和正樣本模糊生成的漏洞檢測系統(tǒng)DeepBalance。該系統(tǒng)通過生成“非真實(shí)”的正樣本以平衡正負(fù)樣本的數(shù)量,然后利用Bi-LSTM框架進(jìn)行漏洞檢測,提高了漏洞檢測的準(zhǔn)確率。Liu等人[13]提出了一種跨域漏洞檢測系統(tǒng)CD-VulD。該系統(tǒng)利用度量遷移學(xué)習(xí)框架,最小化源域與目標(biāo)域之間的分布差異來學(xué)習(xí)跨域表示,并通過Bi-LSTM框架進(jìn)行漏洞檢測,大幅提高了漏洞檢測的準(zhǔn)確率。Li等人[14]提出一種基于Bi-LSTM神經(jīng)網(wǎng)絡(luò)模型的漏洞檢測系統(tǒng)VulDeePecker。該系統(tǒng)將程序源碼表示為語法、語義相關(guān)的代碼小片段,通過Bi-LSTM神經(jīng)網(wǎng)絡(luò)模型實(shí)現(xiàn)了代碼小片段粒度的漏洞檢測。Zou等人[15,16]提出了兩種漏洞檢測系統(tǒng)μVulDeePecker和VulDeeLocator。這兩種系統(tǒng)在VulDeePecker的基礎(chǔ)上,分別實(shí)現(xiàn)了對(duì)多類型漏洞的檢測和對(duì)漏洞位置的細(xì)粒度定位。Russell等人[17]通過卷積神經(jīng)網(wǎng)絡(luò)提取函數(shù)源碼中的特征信息,并將提取的信息輸入給后端分類器-隨機(jī)森林以實(shí)現(xiàn)漏洞檢測。Zhou等人[18]提出了一種基于圖神經(jīng)網(wǎng)絡(luò)的漏洞檢測系統(tǒng)Devign。該系統(tǒng)將程序源碼表示為代碼屬性圖,然后利用圖神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)代碼屬性圖中的語義信息進(jìn)行漏洞檢測。段旭等人[19]提出了一種基于注意力機(jī)制的漏洞檢測工具VulSniper。該工具將程序源碼表示為代碼屬性圖,并用144維向量來表示代碼屬性圖中各節(jié)點(diǎn)之間的關(guān)系,通過注意力機(jī)制來捕捉關(guān)鍵的漏洞特征實(shí)現(xiàn)函數(shù)粒度的漏洞檢測。
雖然上述不同結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò)模型能從大量樣本中學(xué)習(xí)出漏洞特征,但是研究人員難以從神經(jīng)網(wǎng)絡(luò)的黑盒模型中提取出分類特征對(duì)結(jié)果進(jìn)行可解釋性分析。通常用于分類的神經(jīng)網(wǎng)絡(luò)模型的輸出結(jié)果為目標(biāo)所屬類別的概率值,即置信度,但并不清楚得出此結(jié)果的原因。當(dāng)前基于深度學(xué)習(xí)的漏洞檢測方法還難以生成PoC(Proof of Concept)來驗(yàn)證漏洞是否存在,而在后續(xù)深入分析漏洞成因時(shí)則需要具體的漏洞特征。如果能從神經(jīng)網(wǎng)絡(luò)模型中提取出漏洞的分類特征,則有助于研究人員對(duì)漏洞成因進(jìn)行分析。目前,在圖片分類中可運(yùn)用神經(jīng)網(wǎng)絡(luò)可解釋技術(shù)對(duì)分類結(jié)果的原因進(jìn)行分析,如通過類激活映射(Class Activation Mapping, CAM)可以將圖片中與目標(biāo)類別相關(guān)的特征區(qū)域以熱力圖的形式進(jìn)行展示[20]。Russell等人[17]在其論文中提到了可以通過CAM來定位更細(xì)粒度的漏洞位置,但他們并沒有進(jìn)行具體實(shí)現(xiàn)和實(shí)驗(yàn)驗(yàn)證。目前,還沒有見到有其他文獻(xiàn)將神經(jīng)網(wǎng)絡(luò)可解釋性技術(shù)運(yùn)用到漏洞檢測當(dāng)中。
當(dāng)前針對(duì)基于深度學(xué)習(xí)的源代碼漏洞檢測存在以下困難和挑戰(zhàn)。(1)程序源碼信息的提取問題。類似于圖片的像素值可以反映圖片各部分特征,那么程序中的哪些信息可以反映漏洞特征?如何提取程序源碼中與漏洞特征相關(guān)的信息是源碼漏洞檢測需要解決的首要問題。(2)程序源碼信息的向量嵌入問題。神經(jīng)網(wǎng)絡(luò)模型以向量作為輸入,因此從程序中提取的信息都要轉(zhuǎn)換成向量,且經(jīng)過詞嵌入后的程序信息應(yīng)當(dāng)保留其語義相關(guān)性。由于源碼中存在大量的自定義標(biāo)識(shí)符,因此在詞嵌入過程中會(huì)出現(xiàn)很多庫外詞。如何緩解庫外詞過多的問題,同時(shí)保留程序信息的語義相關(guān)性,也是源代碼漏洞檢測要解決的一個(gè)關(guān)鍵問題。(3)神經(jīng)網(wǎng)絡(luò)模型的可解釋性。雖然神經(jīng)網(wǎng)絡(luò)模型能從數(shù)據(jù)集中學(xué)習(xí)到漏洞特征,從而實(shí)現(xiàn)對(duì)漏洞函數(shù)的判定,但是模型為什么做出這樣的判定,判定的依據(jù)是什么?神經(jīng)網(wǎng)絡(luò)模型往往難以給出相應(yīng)的解釋。本文針對(duì)以上問題,提出一種基于卷積神經(jīng)網(wǎng)絡(luò)和全局平均池化的可解釋性源代碼漏洞檢測方法。該方法以token序列作為程序信息的提取方式,對(duì)部分自定義標(biāo)識(shí)符進(jìn)行歸一化;然后采用One-hot編碼方式生成詞向量,構(gòu)建以卷積神經(jīng)網(wǎng)絡(luò)和全局平均池化(Convolution Neural Networks and Global Average Pooling, CNN-GAP)為框架的神經(jīng)網(wǎng)絡(luò)進(jìn)行漏洞檢測;最后通過CAM方式對(duì)檢測結(jié)果進(jìn)行可解釋分析。通過對(duì)比分析,本文提出的CNN-GAP模型的精確率、召回率等性能指標(biāo)優(yōu)于Russell等人提出的模型,模型具有較好的泛化性能,且能夠?qū)崿F(xiàn)漏洞函數(shù)代碼行粒度的可解釋性分析。
本節(jié)詳細(xì)闡述基于CNN-GAP可解釋性模型漏洞檢測方法的設(shè)計(jì)思路,主要包括函數(shù)源碼的預(yù)處理和可解釋性神經(jīng)網(wǎng)絡(luò)模型的構(gòu)建方法。
函數(shù)源碼預(yù)處理是將源代碼中的函數(shù)轉(zhuǎn)化為適合神經(jīng)網(wǎng)絡(luò)模型處理的數(shù)據(jù)。由于源代碼中標(biāo)識(shí)符的形式各異,為了緩解庫外詞過多的問題,需要將源代碼中的自定義標(biāo)識(shí)符進(jìn)行歸一化,用占位符代替原來的標(biāo)識(shí)符。在對(duì)標(biāo)識(shí)符進(jìn)行歸一化時(shí),并不對(duì)所有標(biāo)識(shí)符進(jìn)行歸一化,而是保留一些特殊的標(biāo)識(shí)符,比如memcpy, strcpy, memset等內(nèi)存操作和uint8_t, uint16_t等類型名。通過歸一化,既可以緩解由于標(biāo)識(shí)符命名多樣化而造成語料庫爆炸的問題,還可以保留程序中與內(nèi)存操作和變量類型相關(guān)的語義信息。
歸一化標(biāo)識(shí)符即對(duì)函數(shù)名、變量名、字符串等進(jìn)行歸一化。首先通過正則表達(dá)式匹配出程序源代碼中所有的函數(shù)名、變量名和字符串;然后用FUN+NUM替換函數(shù)名,用VAR+NUM替換變量名,用STRING+NUM替換字符串,最終得到歸一化后的標(biāo)識(shí)符。圖1為對(duì)函數(shù)源碼標(biāo)識(shí)符進(jìn)行歸一化的示例,其中圖1(a)為歸一化前的示例函數(shù)源碼,圖1(b)為對(duì)圖1(a)的源代碼歸一化后的函數(shù)源碼形式。
圖1 函數(shù)源碼標(biāo)識(shí)符歸一化示例
函數(shù)源碼作為特殊的文本序列,其分隔符不同于中英文文本序列。根據(jù)分隔符的不同樣式,可建立3種分隔符的語料庫,其中只含有1個(gè)字符的分隔符22個(gè),只含有兩個(gè)字符的分隔符21個(gè),只含有3個(gè)字符的分隔符2個(gè),具體分隔符分布如圖2所示。
圖2 3種形式的分隔符
函數(shù)源碼由一個(gè)個(gè)token組成。以上述分隔符為界,將每個(gè)函數(shù)切分為token序列,為了得到token的向量表示,用One-hot編碼方式對(duì)token進(jìn)行詞向量嵌入。整個(gè)One-hot語料庫包括了分隔符、歸一化后的標(biāo)識(shí)符、關(guān)鍵字等3種類型token。整個(gè)語料庫共有255個(gè)詞,其中3種類型的分隔符45個(gè);歸一化后的函數(shù)名20個(gè)、變量名20個(gè)、字符串10個(gè),共50個(gè)標(biāo)識(shí)符;C/C++中的關(guān)鍵字、內(nèi)存操作庫函數(shù)名、特殊變量名共160個(gè)。由于語料庫共255個(gè)詞,因此每個(gè)token被編碼成255維的詞向量。為了得到固定形狀大小的神經(jīng)網(wǎng)絡(luò)輸入,將切分成token序列的函數(shù)源碼進(jìn)行截?cái)嗷蜓a(bǔ)齊。當(dāng)token數(shù)量超出300個(gè)時(shí),丟棄超出的部分,只保留前300個(gè)token。當(dāng)token數(shù)量不足300個(gè)時(shí),用255維的零向量補(bǔ)足300個(gè)。整個(gè)函數(shù)源碼轉(zhuǎn)換成形狀為300×255的向量。
神經(jīng)網(wǎng)絡(luò)模型既需要適配前端的輸入形式,又需要滿足后端的輸出需求,即能夠?qū)⑤敵龅慕Y(jié)果進(jìn)行可解釋性分析。為了能對(duì)輸出結(jié)果進(jìn)行可解釋性分析,采用卷積神經(jīng)網(wǎng)絡(luò)和全局平均池化相結(jié)合的模型對(duì)輸入向量進(jìn)行處理,如圖3所示。在對(duì)整個(gè)模型進(jìn)行訓(xùn)練調(diào)參后,采用3層的卷積神經(jīng)網(wǎng)絡(luò)模型,其中卷積核的數(shù)量為128個(gè),卷積核的大小分別為6, 5, 4,移動(dòng)步長均為1。在前3層卷積計(jì)算中,為了使特征圖中的激活值能與輸入原圖對(duì)應(yīng),將輸出特征圖補(bǔ)全到原圖的形狀大小。全局平均池化層將最后一個(gè)卷積層輸出的每個(gè)特征圖的激活值取平均,最后這些均值的加權(quán)和作為Softmax層的輸入。
圖3 CNN-GAP模型結(jié)構(gòu)
式(3)表明了特征圖中空間位置x對(duì)劃分為類別c的重要性Mc(x),可以通過網(wǎng)絡(luò)模型中的參數(shù)fk(x)和Wc,k計(jì)算得出。CAM可解釋表示形式Mc(x)就是不同空間區(qū)域的線性加權(quán)可視化。根據(jù)以上分析,可以通過計(jì)算每個(gè)token對(duì)分類的貢獻(xiàn)度來實(shí)現(xiàn)漏洞的可解釋性。由于token對(duì)分類的貢獻(xiàn)度是根據(jù)神經(jīng)網(wǎng)絡(luò)模型計(jì)算得出的,因此神經(jīng)網(wǎng)絡(luò)模型對(duì)漏洞特征的擬合度決定了token貢獻(xiàn)度表征的準(zhǔn)確性。從理論上分析,基于卷積神經(jīng)網(wǎng)絡(luò)和全局平均池化的可解釋性模型可以適用于不同類型的漏洞,但是漏洞可解釋性的準(zhǔn)確性受限于神經(jīng)網(wǎng)絡(luò)模型對(duì)漏洞檢測的準(zhǔn)確性。只有模型對(duì)漏洞檢測的準(zhǔn)確性高,漏洞可解釋性的準(zhǔn)確性才會(huì)高,而模型的準(zhǔn)確性與數(shù)據(jù)集的大小緊密相關(guān)。當(dāng)前,緩沖區(qū)溢出漏洞的數(shù)據(jù)集較之于其他類型漏洞的數(shù)據(jù)集要豐富很多,因此本文主要針對(duì)緩沖區(qū)溢出類型的漏洞對(duì)模型的性能進(jìn)行實(shí)驗(yàn)測試分析。
實(shí)驗(yàn)測試的硬件環(huán)境為20核Core(TM) i9-7900X 3.30 GHz的CPU、48 GB內(nèi)存、1塊Nvidia RTX 2080Ti GPU。軟件環(huán)境以Ubuntu 18.04 LTS為操作系統(tǒng),keras和tensorflow作為構(gòu)建神經(jīng)網(wǎng)絡(luò)的前端和后端。
實(shí)驗(yàn)測試采用Russell論文中的數(shù)據(jù)集,該數(shù)據(jù)集是從Debian和Github上收集的漏洞函數(shù)集。這些函數(shù)集均來源于真實(shí)軟件,包含了CWE-119,CWE-120, CWE-469和CWE-476等類型的漏洞函數(shù),并由其團(tuán)隊(duì)成員對(duì)每個(gè)函數(shù)進(jìn)行了確認(rèn)和標(biāo)記。由于CWE-119緩沖區(qū)溢出類型漏洞是目前影響最大的漏洞類型,且具有較大的數(shù)據(jù)量,因此本文在實(shí)驗(yàn)測試中采用CWE-119類型的漏洞函數(shù)作為基本數(shù)據(jù)集。將數(shù)據(jù)集中正負(fù)樣本比例劃分為1:3,即正樣本為19286,負(fù)樣本為57858;測試集中正負(fù)樣本比例劃分為1:1,即正樣本為2452,負(fù)樣本為2452。主要進(jìn)行3項(xiàng)實(shí)驗(yàn),包括2項(xiàng)模型對(duì)比實(shí)驗(yàn)以及1項(xiàng)輸出結(jié)果可解釋性分析實(shí)驗(yàn)。為了驗(yàn)證模型的有效性,實(shí)驗(yàn)1將CNN-GAP模型與 Russell模型在CWE-119類型的數(shù)據(jù)集上進(jìn)行對(duì)比;實(shí)驗(yàn)2將已訓(xùn)練好的CNN-GAP模型與VulDeePecker模型,在VulDeePecker測試的CWE-119類型數(shù)據(jù)集上進(jìn)行對(duì)比,以驗(yàn)證模型的泛化性能;實(shí)驗(yàn)3將CNNGAP模型輸出結(jié)果用CAM進(jìn)行可視化輸出,實(shí)現(xiàn)對(duì)漏洞特征的可解釋性分析。
訓(xùn)練時(shí)將batch size設(shè)置為128,用binary_crossentropy作為損失函數(shù),用Adam優(yōu)化器進(jìn)行優(yōu)化。在Russell測試集上的結(jié)果如表1所示。從表1可以看出,模型的F1值達(dá)到了0.8872,Precision值達(dá)到了0.9531,Recall值達(dá)到了0.8299,模型的精確率較高但是檢出率(True Positive Rate, TPR)較低,模型的誤報(bào)率(False Positive Rate, FPR)不高但是存在一定的漏報(bào)率(False Negative Rate, FNR)。由于實(shí)驗(yàn)數(shù)據(jù)集來自Russell論文公開的數(shù)據(jù)集,因此將兩個(gè)模型的實(shí)驗(yàn)結(jié)果進(jìn)行對(duì)比,以說明CNNGAP模型的有效性。
表1 CNN-GAP模型在Russell測試集上的結(jié)果
圖4為CNN-GAP模型和Russell模型在CWE-119類型漏洞函數(shù)進(jìn)行實(shí)驗(yàn)測試的 Precision-Recall對(duì)比圖。對(duì)于Russell模型,當(dāng)Recall值小于0.8時(shí)候,Precision值下降速度較緩慢;當(dāng) Recall值大于0.8時(shí),Precision值迅速下降。對(duì)于CNN-GAP模型,其變化趨勢(shì)與Russell模型相同,隨著Recall值的增加,Precision值逐漸降低。當(dāng)Recall值小于0.8時(shí),Precision值下降十分緩慢,且均在0.9以上;當(dāng)Recall值大于0.8時(shí),Precision值雖然下降速度也很快,但是都在0.5以上,而在Russell模型中,當(dāng)其Precision值超過0.8時(shí),Recall值小于0.5;當(dāng)Recall值大于0.5時(shí),Precision值已經(jīng)低于0.5了。從這些數(shù)據(jù)可以說明,Russell模型在保持較高的檢測精確率時(shí),召回率低即漏報(bào)率高;當(dāng)保持較高召回率時(shí),其檢測的準(zhǔn)確率又低于0.5。CNN-GAP模型不僅能夠保持較高精確率,其召回率也不低。由于Russell模型對(duì)token進(jìn)行歸一化的方式是將token替換成字符串、浮點(diǎn)數(shù)等類型,然而常量、變量、函數(shù)名等有可能是相同的數(shù)據(jù)類型,因此它們有可能被替換成同一種占位符,使得標(biāo)識(shí)符之間容易產(chǎn)生混淆。然而,CNN-GAP模型對(duì)每個(gè)token都采用不同的占位符來表示,不會(huì)造成替換后的標(biāo)識(shí)符出現(xiàn)混淆的情況。因此,CNN-GAP 模型對(duì)CWE-119類型的漏洞檢測效果優(yōu)于Russell模型。
圖4 CNN-GAP和Russell模型的Precision-Recall曲線圖
當(dāng)正樣本和負(fù)樣本的數(shù)量不均衡時(shí),還需要TPR和FPR來對(duì)實(shí)驗(yàn)結(jié)果進(jìn)行評(píng)估。此時(shí),根據(jù)閾值的取值不同,可以得到不同的FPR和TPR值。將所有的值以FPR為橫軸、TPR為縱軸畫圖,得到ROC曲線圖,曲線向下覆蓋的面積即為AUC值。理想情況下AUC值為1.0,此時(shí)該分類器為完美分類器。一般情況下,AUC值在0.5~1.0,優(yōu)于隨機(jī)預(yù)測。圖5為CNN-GAP模型采用Russell測試集得到的ROC曲線,AUC值為0.95,接近1.0,說明模型整體性能較好。
圖5 CNN-GAP模型的ROC曲線圖
VulDeePecker是基于Bi-LSTM的源代碼漏洞檢測模型,它將程序源代碼通過定義的規(guī)則切分成code gadget,然后在code gadget粒度上進(jìn)行檢測。該模型采用的數(shù)據(jù)集包括兩種類型的漏洞,CWE-119和CWE-399。本實(shí)驗(yàn)主要針對(duì)CWE-119類型的數(shù)據(jù)集進(jìn)行測試。VulDeePecker的CWE-119數(shù)據(jù)集是txt文檔,以“–”作為分割符,有10440個(gè)含有漏洞的code gadget,29313個(gè)不含漏洞的code gadget。為了提高測試的效率和真實(shí)性,按照其數(shù)據(jù)集原本的數(shù)據(jù)排列順序,取出前1000個(gè)不含漏洞的code gadget和最后1000個(gè)含漏洞的 code gadget進(jìn)行測試,測試結(jié)果如表2所示。
從表2可以看出,CNN-GAP模型檢測的精確率precision高于VulDeePecker模型,Recall,F(xiàn)1等參數(shù)略低于VulDeePecker模型。然而,CNN-GAP模型并沒有在VulDeePecker模型的數(shù)據(jù)集上進(jìn)行訓(xùn)練,僅僅在其測試集上進(jìn)行實(shí)驗(yàn),而實(shí)驗(yàn)結(jié)果非常接近VulDeePecker模型,由此可以說明CNN-GAP模型的泛化性能較好。在前期對(duì)程序源碼的預(yù)處理中,VulDeePecker模型需要將程序進(jìn)行分析切片提取,其前向切片和后向切片只保留了其關(guān)注的程序中幾種易出現(xiàn)漏洞的元素(如API調(diào)用、數(shù)組變量、指針變量等)及其控制流和數(shù)據(jù)流依賴,丟棄了其他不屬于此范圍的代碼元素。因此,VulDeePecker模型雖然精簡了代碼量,但是也丟失了部分代碼特征。CNN-GAP模型無需對(duì)程序進(jìn)行切片,直接對(duì)整個(gè)函數(shù)源碼進(jìn)行處理,不僅簡化了預(yù)處理過程,而且包含了整個(gè)函數(shù)中所有元素的控制流和數(shù)據(jù)流依賴。從此角度考慮,CNN-GAP模型的實(shí)用性優(yōu)于VulDeePecker模型。
表2 CNN-GAP模型與VulDeePecker模型的實(shí)驗(yàn)結(jié)果對(duì)比
通常情況下,分類模型的輸出是判別待測目標(biāo)為某個(gè)類別的概率值,可以依據(jù)這個(gè)概率值對(duì)待測目標(biāo)進(jìn)行分類。對(duì)于使用softmax作為判決器的二分類任務(wù),當(dāng)某個(gè)類別的輸出值較大時(shí),表明被測目標(biāo)為該類別。由于模型的輸出值是根據(jù)特征圖中各位置的激活值得到的,因此通過對(duì)GAP層輸出信息進(jìn)行可解釋性分析,可以計(jì)算得到源碼中每個(gè)token對(duì)分類結(jié)果的重要性。為便于將每一個(gè)激活值與每一個(gè)token對(duì)應(yīng),在構(gòu)建神經(jīng)網(wǎng)絡(luò)模型時(shí),每層網(wǎng)絡(luò)輸出的特征圖大小保持不變,因此激活值與神經(jīng)網(wǎng)絡(luò)權(quán)重系數(shù)的乘積可以表示token對(duì)某個(gè)類別的貢獻(xiàn)度,且該數(shù)值越大,貢獻(xiàn)度越大。若該數(shù)值為正,表明token對(duì)整個(gè)函數(shù)含有漏洞為正向激勵(lì);若該數(shù)值為負(fù),則為反向激勵(lì)。在源碼預(yù)處理中,函數(shù)源碼被切分為300個(gè)token序列。如果將每個(gè)token對(duì)最后分類結(jié)果的重要性進(jìn)行表示,那么300個(gè)token在分布圖中十分擁擠,不便于展示和理解。為了更好地從視覺上感受到函數(shù)源碼對(duì)目標(biāo)類別的重要性,實(shí)驗(yàn)3將GAP中的特征映射到函數(shù)源碼中的每條語句,而不是每個(gè)token。在上文的輸出結(jié)果可視化計(jì)算中已經(jīng)詳細(xì)說明了token權(quán)重的計(jì)算方法,最后將程序語句中每個(gè)token的重要性(權(quán)重值)進(jìn)行相加作為此程序語句對(duì)分類結(jié)果的重要性。
下面的兩段代碼為VulDeePecker測試集中的函數(shù),分別對(duì)應(yīng)的是堆溢出漏洞和棧溢出漏洞。
圖6的代碼片段是CWE-119類型的堆溢出漏洞,其中memset函數(shù)的功能是復(fù)制字符“C”到source所指區(qū)域的前100-1個(gè)字符,strncat函數(shù)的功能是把source所指向的字符串追加到data所指向的字符串的結(jié)尾,直到100個(gè)字符長度。因?yàn)閐ata是動(dòng)態(tài)分配的堆內(nèi)存,而source所指字符串的內(nèi)存大小可能會(huì)超出data的內(nèi)存大小,則會(huì)造成堆溢出。由于strncat函數(shù)沒有對(duì)source的大小進(jìn)行檢查,因此存在堆溢出漏洞。圖7的代碼片段是CWE-119類型的棧溢出漏洞,其中memset函數(shù)的功能是復(fù)制字符“A”到data所指區(qū)域的前100-1個(gè)字符,memcpy函數(shù)的功能是把data內(nèi)存中的字符串復(fù)制到dest內(nèi)存區(qū)域中。dest是數(shù)組,為棧內(nèi)存區(qū)域。然而,在進(jìn)行復(fù)制操作時(shí)沒有對(duì)dest的內(nèi)存大小和復(fù)制字符串的大小進(jìn)行比較,因此復(fù)制的字符串長度超出了dest的內(nèi)存大小,會(huì)造成棧溢出。
圖6 堆溢出示例代碼
圖7 棧溢出示例代碼
圖8、圖9分別為上述兩段代碼經(jīng)過神經(jīng)網(wǎng)絡(luò)模型判別后,根據(jù)可解釋性分析輸出的可視化結(jié)果,其中數(shù)值大于0表示對(duì)應(yīng)的代碼行與漏洞相關(guān)。可以看出圖8中,行10—行13與漏洞特征相關(guān),這幾行代碼包含了strncat漏洞代碼、data堆內(nèi)存、source[]數(shù)組,直觀上能表示出漏洞特征對(duì)最后分類的重要性。圖9中表明第12,13行與漏洞特征相關(guān),這幾行代碼包含了memcpy漏洞代碼,直觀上能表示出漏洞特征對(duì)最后分類的重要性。因此,從可視化的柱狀圖中可以看出CNN-GAP模型所學(xué)到的“漏洞特征”在程序源碼中的分布情況。換個(gè)角度,此漏洞特征也可以表明漏洞代碼在整個(gè)源碼中的位置,即從柱狀圖中可以得知函數(shù)源碼中漏洞的大概位置,實(shí)現(xiàn)在代碼行粒度的漏洞定位。
圖8 CNN-GAP模型針對(duì)堆溢出示例代碼的可視化結(jié)果
圖9 CNN-GAP模型針對(duì)棧溢出示例代碼的可視化結(jié)果
本文以CNN-GAP可解釋性模型為神經(jīng)網(wǎng)絡(luò)框架對(duì)CWE-119緩沖區(qū)溢出類型的漏洞函數(shù)進(jìn)行檢測,并通過CAM可解釋技術(shù)實(shí)現(xiàn)了結(jié)果的可視化輸出。通過與Russell提出的神經(jīng)網(wǎng)絡(luò)模型及VulDeePecker模型進(jìn)行對(duì)比分析,驗(yàn)證了CNN-GAP模型的有效性和泛化性。當(dāng)然,本文提出的模型還可以在以下3個(gè)方面進(jìn)一步完善。一是在程序建模中,雖然通過對(duì)自定義標(biāo)識(shí)符進(jìn)行歸一化處理來緩解庫外詞過多的問題,但同時(shí)也丟失了其中的部分語義信息。在后續(xù)的工作中可以考慮采用更為完善的處理方式以減少語義信息的損失。二是在神經(jīng)網(wǎng)絡(luò)可解釋性分析中,只是大致將程序源碼中與漏洞相關(guān)的代碼行進(jìn)行了高亮表示,沒有對(duì)其根本原因進(jìn)行分析。在后續(xù)的工作中力爭實(shí)現(xiàn)更為細(xì)粒度的漏洞函數(shù)定位分析,達(dá)到token粒度的可視化輸出。三是當(dāng)前的模型僅能識(shí)別CWE-119緩沖區(qū)溢出類型漏洞,后續(xù)可利用CWE-120,CWE-469等類型的漏洞函數(shù)集對(duì)模型進(jìn)行訓(xùn)練,使模型能實(shí)現(xiàn)多種類型漏洞的檢測。