深度学习框架检测软件漏洞——翻译记录
深度学习不需要人类专家定义特征
本文首先提出框架SySeVR——基于语法Syntax-based、基于语义Semantics-based和向量表示Vector Representations,侧重于获得能够容纳与漏洞相关的语法和语义信息的程序表示。
基于源代码的静态分析是检测漏洞的很重要方法包括
基于代码相似性:主要检测代码克隆引起的漏洞
和基于模式的方法:人类专家定义特征
深度学习包括:递归神经网络RNN,卷积神经网络CNN深度置信网络DBN(主要应用于图像和自然语言处理)
深度学习是为了处理自然向量的数据诞生的,软件程序没有这样的向量表示。
已经提出过得基于深度学习的漏洞检测系统VulDeePecker的缺点如下
1,只考虑与库/API函数调用相关的漏洞
2,只利用由数据依赖引起的语义信息
3,他只考虑被称为双向长短期记忆BLSTM的特定RNN
4,它不努力解释假阳性和假阴性的原因。
贡献
我们如何将程序表示为能够容纳适合于漏洞检测的语法和语义信息的向量?
引入并定义了基于语法的漏洞候选 Syntax-based Vulnerability Candidates (SyVCs)和基于语义的漏洞候选 Semantics-based Vulnerability Candidates (SeVCs)的概念,并设计了计算算法,SyVCs反映了漏洞语法特征,SeVCs对SyVCs进行扩展,以容纳数据依赖和控制依赖诱导的语义信息。相应地,该框架被称为基于语法、基于语义和向量表示,简称SySeVR
(1) SySeVR可以使多种深度神经网络检测各种漏洞。SySeVR使双向RNNs,尤其是双向门控递归单元(BGRU)比CNNs更有效,使CNNs比DBNs更有效。此外,SySeVR使深度神经网络(尤其是BGRU)比最先进的漏洞检测方法更有效。
(2)我们发现BGRU的有效性受到训练数据的实质性影响。如果某些语法元素(例如,标记)经常出现在漏洞(相对于没有漏洞)的代码片段中,那么这些语法元素可能会导致高误报(相对于误报)
(3)使用针对特定类型漏洞定制的深度神经网络比使用单个深度神经网络来检测各种类型的漏洞更好
(4)用于学习深层神经网络的语义信息越多,所学习的神经网络的脆弱性检测能力越高。例如,控制依赖诱导的语义信息可以平均降低19.6%的误报率
。(5)通过将支持SySeVR的BGRU应用于4个软件产品(Libav、Seamonkey、Thunderbird和Xen),我们检测到了15个在NVD尚未报告的漏洞。
领域差距
图1a可以通过使用候选区域 region proposal的概念并利用图像的结构表示(例如,纹理、边缘和颜色)来实现,当使用深度学习来检测漏洞时,程序没有自然的结构表示,例如图像的候选区域是什么,这意味着深度学习不能直接用于漏洞检测。
框架:
为了弥补领域差距,使用程序的每个功能作为候选区域,但是粒度太粗,需要确定漏洞位置,将每一行作为漏洞检测的单元,缺点:
(1)程序中的大多数语句不包含任何漏洞,这意味着很少有样本是易受攻击的;
(2)语义上彼此相关的多个语句不被视为一个整体。
受图像处理中候选区域概念的启发,我们建议将程序分成更小的代码段(即,若干语句),这些代码段可能表现出漏洞的语法和语义特征。这解释了,如图1(b)中所强调的,为什么框架寻找程序的SyVC、SeVC和向量表示
SeVC扩展了SyVC,使其包括与SyVC语义相关的语句(即代码行),其中语义信息是由控制依赖和/或数据依赖引起的
1)提取语法:使用漏洞语法特征(函数调用,指针使用)作为起点
定义1:(程序、函数、语句、令牌):程序P是一组(系列)函数f1……fη,用P = {f1……fη}表示,A 函数 fi, 其中1 ≤ i ≤ η,是一组(系列)有序的语句si,1……si,mi,表示为fi= { si,1, . . . , si,mi}。语句 si,j,其中1 ≤ i ≤ η 和1 ≤ j ≤ mi, 是一系列 tokens ti,j,1, . . . , ti,j,wi,j,用si,j= { ti,j,1, . . . , ti,j,wi,j,}表示。
标记可以是标识符、运算符、常量和关键字,并且可以通过词法分析来提取
定义语法:给定一个函数fi,有生成其抽象语法树的标准例程,用Ti表示。在Ti上,根对应函数fi,一个叶节点对应一个标记ti,j,g(1 ≤ g ≤ wi,j),并且内部节点对应于语句si,j,或者多个连续的标记si,j。直观地说,一个SyVC是一个标记(对应于一个叶节点)或者由多个连续的标记(对应于一个内部节点)组成。
定义2:考虑一个程序P= {f1, . . ., fη},其中 fi= {si,1, . . . , si,mi} 且 si,j= {ti,j,1, . . ., ti,j,wi,j}.给定一组漏洞语法特征,用H = {hk}1≤k≤β表示,这里β是语法特征的数量,代码元素 ei,j,z由一个或多个连续的si,j,标记组成,即: ei,j,z= (ti,j,u, . . . , ti,j,v)其中 1 ≤ u ≤ v ≤ wi,j。如果代码元素 ei,j,z与漏洞语法特征hk相匹配,则称为SyVC
请注意,不同类型的漏洞会有不同的语法特征。例如,与库/API函数调用相关的漏洞具有以下语法特征:Ti上的函数是“callee”(表示函数调用)。
SyVCs算法:给定一个程序P = {f1……fη}和一个集合H = {hk}1≤k≤β其具漏洞语法特征,算法1从P中提取SyVCs如下
首先:算法1使用标准抽象语法树生成例程从每个函数fi中提取Ti。
然后,算法1遍历Ti去识别SyVCs,即匹配某些hk的代码元素。
运行示例,在图2的第二列中,我们使用方框来突出显示从程序源代码中使用漏洞语法特征提取的所有潜在漏洞,一个SyVC可能是另一个SyVC的一部分。例如,从第18行中提取了三个潜在漏洞,因为它们是针对不同的漏洞语法特征提取的。
2)将SyVCs转换为SeVCs :为了检测漏洞,我们建议将SyVC转换为SeVC,或者SyVC→SeVC转换,以容纳与所讨论的SyVC语义相关的语句。出于这个目的,我们建议利用程序切片技术来识别在语义上与SyVCs相关的语句。为了使用程序切片技术,我们需要使用程序依赖图(PDG)。这要求我们使用数据依赖和控制依赖,它们是在控制流图(CFG)上定义的。
定义3(CFG):对于程序P = {f1, . . ., fη},函数fi的CFG是一个图Gi= (Vi,Ei),其中Vi= {ni,1, . . . , ni,ci}是一组节点,每个节点代表一个语句或控制谓词,Ei= {?i,1, . . ., ?i,di}是一组直接边,每条边代表一对节点之间可能的控制流
定义4(数据依赖):考虑一个程序P = {f1,…, fη},函数fi的CFG Gi= (Vi, Ei), Gi中的两个节点ni,j 和 ni,e其中1 ≤ j,e ≤ ci并且 j 不等于e。如果在ni,e处计算的值用于ni、j处,则ni、j数据依赖于ni、e
定义5(控制依赖):考虑一个程序P = {f1……fη},函数fi的CFG Gi= (Vi, Ei), Gi中的两个节点ni,j,和ni,e其中 1 ≤ j, ‘e≤ ci并且 j 不等于e,如果从ni,e到程序末尾的所有路径都经过ni,j,则ni,j后支配ni,e。如果存在一条从ni,e开始,到ni,j结束的路径,如(1) ni,j后支配路径上除ni,e和ni,j以外的所有节点。(2) ni,j不后支配ni,e,则ni,j控制依赖于ni,e。
基于数据依赖和控制依赖,我们可以定义PDG
定义6(程序依赖图(PDG) ):对于程序P = {f1,…,fη},函数fi的PDG表示为G0 i= (Vi, E0 i),其中Vi与CFG Gi相同,E0 i={?0
i,1, . . ., ?0i,d0i}是一组直接边,每条边表示一对节点之间的数据或控制依赖关系
给定PDGs,我们可以提取SyVCs的程序切片,这可能会超出单个函数的边界。我们同时考虑向前和向后切片,因为(1)SyVC可能影响一些后续语句,因此可能包含漏洞;(ii)影响SyVC的语句可能会导致SyVC漏洞。
定义7(SyVC的前向、后向和程序切片):考虑一个程序P = {f1……fη},函数fi的程序依赖图PDGs G0 i= (Vi,E0 i),和一个SyVC, ei,j,z, 语句 si,,in G0,i.
由fsi,j,z表示的SyVC ei,j,z在 fi的前向切片被定义为节点{ni,x1,.。。,ni,x i} ? Vi在 G0 i,其中ni,xp,1 ≤ x1≤ xp≤ x i≤ ci,可从ei,j,zin G0 i到达,即fsi,jare中的节点从G0中的所有路径到达ei,j,z
SyVC ei,j,zin程序P的进程间前向切片,用fs0 i,j,z表示,是超越函数边界的前向切片(由函数调用引起)。
由bsi,j,z表示的SyVC ei,j,zin fi的后向切片被定义为节点{ni,y1,.。。,ni,yνi} ? Viin G0 i,其中ni,yp,1 ≤ y1≤ yp≤ yνi≤ ci,由此ei,j,zis在G0 i中可达,即bsi,j,zare中的节点从G0中的所有路径到达ei,j,z
SyVC ei,j,zin程序P的进程间后向切片,用bs0 i,j,z表示,是超越函数边界的后向切片(由函数调用引起)。
给定一个进程间前向切片fs0 i,j,Zan和一个进程间后向切片bs0 i,j,z,SyVC ei,j,z的(进程间)程序切片,用psi,j,z表示,通过合并fs0 i,j,Zan和bs0 i,j,zat到SyVC ei,j,z,定义为一个有序的节点集(属于P中函数的PDGs)。
定义SeVCs:我们可以将SyVCs转换为SeVCs,具体如下:
定义8(SeVC):给定一个程序P = {f1,。。。,fη}和一个SyVC ei,j,z中语句si,j的函数fi,对应于SyVC ei,j,z的SeVC,用δi,j,z表示,定义为P中语句的有序子集,用δi,j,z= {sa1,b1,.。。,saui,j,z,bvi,j,z},其中在语句sap,bq (1 ≤ p ≤ ui,j,zand 1 ≤ q ≤ vi,j,z)和SyVC ei,j,z之间存在数据依赖或控制依赖。换句话说,SeVC,δi,j,z,是对应于(过程间)程序切片psi,j,z的节点的一组有序的语句。
计算SeVCs的算法及运行实例。算法2分三步总结了前面的讨论:生成PDGs;通过算法1生成SyVCs输出的程序片;并将程序片转换为sevc。接下来我们将详细阐述这些步骤,并使用图3来演示一个正在运行的示例。具体来说,图3阐述了SyVC数据(与指针使用相关)在适应数据依赖和控制依赖所导致的语义信息时的SyVC SeVC转换。
步骤1(算法3中的第2-6行):每个SeVC δi,j,zis被转换成一个符号表示。为此,我们建议删除非ASCII字符和注释,然后以一对一的方式将变量名映射到符号名(例如,“V1”、“V2”),最后以一对一的方式将函数名映射到符号名(例如,“F1”、“F2”)。请注意,不同的服务事件可能具有相同的符号表示。
步骤2(算法3中的第8-13行):这一步是将符号表示编码成向量。为此,我们建议将一个SeVC δi,j,z的符号表示分开(例如,“V1 = V2-8;”)通过词汇分析转换成符号序列(例如,“V1”、“V2”、“”、“8”和“;”).我们把一个符号转换成一个固定长度的向量。通过连接向量,我们得到每个SeVC的向量Ri,j,z。
步骤3(算法3中的第14-22行):因为(I)符号的数量(即,表示SeVCs的向量)可以不同,和(ii)神经网络采用相同长度的向量作为输入,我们使用阈值θ作为神经网络输入的向量长度。当向量短于θ时,零被填充到向量的末尾。当向量大于θ时,我们考虑三种情况。(I)如果向量中对应于前向切片fsi,jis的部分比θ/2短,我们删除Ri,j,zto的最左边部分,使|Ri,j,z| = θ。(ii)如果向量对应于后向切片bsi,jis的部分比θ/2短,我们删除Ri,j,zto的最右部分,使|Ri,j,z| = θ。(iii)否则,我们从Ri,j,z0的最左边部分和最右边部分删除几乎相同的长度,使|Ri,j,z| = θ。
4)对SeVCs及其对应的V向量进行标记:为了学习深度神经网络,我们将向量(即其所代表的SeVCs)标记为有漏洞或没有漏洞,如下所示:
一个包含已知漏洞的SeVC(即表示它的向量)被标记为“1”(即易受攻击),否则被标记为“0”(即不易受攻击)。一个学习的深度神经网络编码漏洞模式,并可以检测是否给定sevc是否有漏洞。
C 评估指标
漏洞检测器的有效性可以通过以下5个广泛使用的指标来评估[27]:假阳性率(F P R)、假阴性率(F N R)、准确性(A)、精度(P)和F1-measure (F1)。让TP表示被检测为漏洞的漏洞样本的数量,FP表示没有漏洞但被检测为漏洞的样本的数量,TN表示没有漏洞且被检测为没有漏洞的样本的数量,FN表示被检测为没有漏洞但实际存在漏洞的样本数量。表一总结了它们的定义
三 实验结果
A.研究问题和数据集
研究问题。我们的实验旨在回答以下研究问题:
RQ1:SySevr能否使BLSTM检测多种(相对于单种)漏洞?
RQ2:SySevr能否构建多种深度神经网络来检测多种漏洞?我们能解释它们的有效性吗?
RQ3:适应控制依赖能让SySeVR更有效吗?能提高多少?
RQ4:与最先进的方法相比,基于SySeVR的方法有多有效?
为了回答这些问题,我们使用Anano[28]在Python中实现了以下6个深度神经网络:
CNN [29]、
DBN [30]和
RNNs(包括LSTM、GRU、BLSTM和BGRU [31]、[32]、[33])。
运行实验的计算机有一个NVIDIA GeForce GTX 1080 GPU和一个运行在3.50GHz的英特尔至强E5-1620 CPU。
漏洞数据集,我们从两个来源生成脆弱性数据集:NVD [21]和SARD[22]。NVD包含生产软件中的漏洞,可能还有diff文件描述易受攻击的代码片段与其修补版本之间差异的差异文件。SARD包含生产、合成和学术程序(也称为测试用例),分为“好的”(即没有漏洞)、“坏的”(即有漏洞)和“混合的”(即具有修补版本也可用的漏洞)
对NVD来说,我们关注19种流行的C/C++开源产品(与[11]中的相同)及其伴随着不同文件的漏洞,这些文件是提取易受攻击的代码片段所必需的。结果,我们收集了1592个开源C/C++程序,其中874个是易受攻击的。对于SARD,我们收集了14000个C/C++程序,其中13906个程序易受攻击(即“坏”或“混合”)。我们总共收集了15,592个程序,其中14,780个是易受攻击的;这些易受攻击的程序包含126种类型的漏洞,其中每种类型都由一个共同弱点枚举标识符(CWE标识)[34]唯一标识。126个CWE身份证与我们的数据集一起发布。
B. 实验
1)提取系统漏洞:在接下来的内容中,我们将阐述算法1中针对不同类型漏洞的两个组件:漏洞语法特征的提取以及如何匹配它们
提取漏洞语法特征:为了提取已知漏洞的语法特征,自然要从上述易受攻击的程序中提取易受攻击的代码行,并分析它们的语法特征。然而,这是一项极其耗时的任务,这促使我们利用最先进的商业工具Checkmarx [6]的C/C++漏洞规则来分析漏洞语法特征。正如我们将看到的,这种替代方法是有效的,因为它覆盖了从SARD收集的93.6%的易受攻击程序。值得一提的是,我们选择Checkmarx而不是开源工具(如Flawfinder [4]和RATS [5]),因为后者解析器简单,规则不完善[35]。
我们对Checkmarx规则的手动检查导致以下4个语法特征(每个都包含许多漏洞)
库/API函数调用(简称FC):这个语法特性涵盖了811个库/API函数调用,这些调用是用我们的数据集发布的。这811个函数调用对应于106个CWE标识
数组用法(简称AU):这个语法特性涵盖了87个与数组相关的CWE标识(例如,与数组元素访问、数组地址运算相关的问题)。
指针用法(简称PU):该语法特征涵盖了103个与指针相关的CWE标识(例如,指针算术、引用、作为函数参数的地址传递中的不当使用)。
算术表达式(简称AE):该语法特征涵盖了45个与不当算术表达式(例如整数溢出)相关的CWE标识
图4示出了这4个语法特征在它们所覆盖的CWE标识方面彼此重叠(例如,39个CWE标识展示了所有4个语法特征,但是 |FC∪AU∪PU ∪ AE| = 126)
FC, AU, PU, and AE元素图 in terms of the CWE IDs they cover, where |FC| = 106, |AU| = 87, |PU| = 103, and |AE| = 45
匹配语法特征:为了使用算法1提取SyVCs,我们需要确定程序P中函数fi的抽象语法树Ti上的代码元素ei,j,z是否匹配漏洞语法特征。请注意,Ti可以通过使用Joern[36]生成。通过图2中的示例程序,如下图5所示的方法可以自动判断代码元素ei,j, z是否匹配某个语法特征。
如图5(a)所示,如果Ti上的(i) ei,j,z是被调用者(即函数被调用),且(ii) ei,j,z是上述811个函数调用之一,则代码元素ei,j,z(即memset)匹配FC语法特征。
如图5(b)所示,我们说代码元素ei j z(即“source”),如果(i) ei,j,z是标识符声明语句(即IdentifierDeclStatement)节点声明的标识符,且(ii) IdentifierDeclStatement节点包含字符‘[’ and‘]’.,则匹配AU的语法特征。
如图5(c)所示,如果(i) ei,j,z是IdentifierDeclStatement节点声明的标识符,且(ii) IdentifierDeclStatement节点包含字符‘?’.,则我们说代码元素ei,j,z(即data)匹配PU语法特征。
如图5(d)所示,我们说代码元素ei,j,z (data=dataBuffer-8)匹配AE语法特征,如果(i) ei,j,z是一个表达式语句(表达式-语句)节点,并且(ii) ei,j,z包含一个字符=,并且在=的右侧有一个或多个标识符
提取SyVCs:
现在,我们可以使用算法1从15,592个程序中提取SyVCs。对应于这4个语法特征,我们提取了4种语法特征:
FC-kind SyVCs:我们从NVD中提取了6304个,从SARD中提取了58099个,总共是64,403个。
AU-kind SyVCs:我们从NVD中提取9776个,从SARD中提取32453个,总共42229个。
PU-kind SyVCs:我们从NVD中提取了73,856,从SARD中提取了217,985,总共是291,841。
AE-kind SyVCs:我们从NVD中提取了5264个,从SARD中提取了16890个,总共22154个。
把它们放在一起,我们提取了420,627个SyVCs,涵盖了从SARD收集的13,906个(或93.6%)脆弱项目中的13,016个;这个覆盖范围验证了我们使用Checkmarx规则来获得漏洞语法特征的想法。请注意,我们可以计算覆盖率93.6%,因为SARD给出了每个漏洞的精确位置;相反,我们不能计算关于NVD的覆盖范围,因为它不能给出漏洞的精确位置。提取SyVC的平均时间是270毫秒
2) 将SyVCs转换为SeVCs:在使用算法2将SyVCs转换为SeVCs时,我们使用Joern[36]提取PDGs。对应于算法1中提取的420,627个SyVC,算法2生成420,627个SeVC(在回忆一个SyVC转化为一个SeVC时)。为了观察语义信息的作用,我们实际使用算法2生成了两组语义信息集合:一组容纳由数据依赖引起的语义信息,另一组容纳由数据依赖和控制依赖引起的语义信息。在这两种情况下,表二第二列总结了按照转换后的syvc种类分类的sevc数目。就SyVC的SeVC转换效率而言,生成适应数据依赖的SeVC平均需要331毫秒,生成适应数据依赖和控制依赖的SeVC平均需要362毫秒
3)将SeVCs编码为V向量表示:
我们使用算法3将SeVCs编码为向量表示。为此,我们采用word2vec[37]将每个SeVC的符号编码为定长向量。然后,每个SeVC由表示其符号的向量的连接来表示。我们将每个SeVC设置为500个符号(如算法3中所讨论的填充或截断),每个符号的长度为30,意味着θ= 15,000。
4)生成SeVCs的Ground Truth标签:
对于从NVD提取的SeVCs,我们检查其差异文件涉及行删除的漏洞;我们不考虑只包含行添加的diff文件,因为在这些情况下,NVD没有给出易受攻击的语句。我们分三步生成基本事实标签。
第一步:解析一个diff文件,标记前缀为“-”的行被删除/修改,前缀为“-”的行被移动(即一处删除,另一处添加)。
第二步:如果一个SeVC包含至少一个前缀为“-”的删除/修改语句,则标记为“1”(即易受攻击);如果一个SeVC包含至少一个前缀为“-”的moved语句,并且检测到的文件包含一个已知的漏洞,则它被标记为“1”;否则,SeVC被标记为“0”(即没有漏洞)
步骤3:检查标记为“1”的SeVC,因为步骤2可能会将一些不脆弱的SeVC错误标记为“1”(同时注意,不可能将脆弱的SeVC错误标记为“0”)。在前面的3个步骤中,前两个是自动的,但最后一个是手动的
对于从SARD中提取的SeVC,从“好”程序中提取的SeVC标记为“0”;如果从“坏的”或“混合的”程序中提取的SeVC包含至少一个易受攻击的语句,则该SeVC被标记为“1 ”,否则标记为“0”
总共有56,395个服务事件标记为“1”,364,232个服务事件标记为“0”。表二的第三列和第四列总结了每种SyVCs对应的脆弱和不脆弱的sevc数量。对应于SeVC的向量的基本真值标签与SeVC的基本真值标签相同
C.实验结果
为了学习一个深度神经网络,我们分别使用80%的程序,从NVD和SARD中随机选择用于训练(训练程序),并使用剩余的20%用于测试(测试程序)。
1)回答RQ1的实验:
在这个实验中,我们使用了[11]中的BLSTM和包含由数据和控制依赖关系引起的语义信息的SeVCs。我们随机选取从训练方案中抽取的30,000个sevc作为训练集(其中12.7%是脆弱的,其余87.3%不是),从测试方案中抽取的7,500个sevc作为测试集(其中12.2%是脆弱的,其余87.8%不是)。两个集合都包含了对应于4种SyVCs的sevc,与它们的数量成正比,如表II第二列所示。为了公平与VulDeePecker[11]比较,我们也随机选择30000 SeVCs对应FC-kind SyVCs提取(其中22.8%是脆弱的,其余的77.2%是不)作为训练集,并随机选择7500名SeVCs相应FC -kind SyVCs提取测试项目的测试集(其中22.0%是脆弱的,其余的78.0%是不会)。这些sevc只容纳由数据依赖引起的语义信息(如[11]
学习BLSTM的主要参数有:
dropout为0.2;批大小为16;代数为20;输出维数为256;采用小批量随机梯度下降法结合ADAMAX[38]进行训练,默认学习率为0.002;隐向量维数为500;隐藏层数为2。
表三总结了结果。我们发现,SySeVR使能了FC-kind SyVCs的BLSTM(或SySeVR-BLSTM)的FNR最低(9.6%),但FPR高于PU-和AE-kind SyVCs。其他3种SyVCs的平均FPR为3.3%,FNR为12.6%。总的来说,SySeVR使BLSTM比VulDeePecker在同类漏洞上实现更低的FPR(低0.3%)和更低的FNR(低12.1%)。这将导致
明显1:SySeVR-BLSTM可以检测各种漏洞能力,可以降低FNR 12.1%。
2)回答RQ2的实验:
为了回答RQ2,我们使用与第三节-C1相同的数据集训练了1个CNN、1个DBN和4个RNN(即LSTM、GRU、BLSTM和BGRU)。表四总结了结果。我们观察到,与单向RNNs(即LSTM和GRU)相比,双向RNNs(即BLSTM和BGRU)可以平均降低3.1%的FNR,而FPR的代价是平均增加0.3%。这种现象可能是由以下原因引起的:双向RNNs可以容纳更多关于出现在所讨论语句之前和之后的语句的信息。总之,
sysevr使能的双向rnn(特别是BGRU)比cnn更有效,而cnn又比dbn更有效。不过,他们的FNRs始终远高于FPRs
解释BGRU在漏洞检测中的有效性。解释深层神经网络的有效性很重要,但却是一个悬而未决的问题。现在我们报告我们沿着这个方向的初步努力。在接下来的内容中,我们将重点关注BGRU,因为它比其他产品更有效
为了解释BGRU的有效性,我们在图6中回顾了它的结构。对于每个SeVC和每个时间步长,在激活层有一个输出(属于[0,1])。BGRU的输出是激活层最后一个时间步的输出;该输出越接近1,SeVC越有可能被归类为易受攻击。对于SeVC的分类,我们确定在确定其分类中起关键作用的标记(即代表它们的符号)。这可以通过在时间步长(t0,t0+ 1)查看所有令牌对来实现。我们发现,如果在时间步骤t0+ 1对应于令牌的激活层输出比在时间步骤t0对应于令牌的激活层输出大得多(例如,0.6)(相对较小),那么在时间步骤t0+ 1的令牌在将SeVC分类为易受攻击(相应地,不易受攻击)方面起着关键作用。此外,我们发现许多假阴性是由令牌“如果”或其后的令牌引起的,因为这些令牌通常出现在不容易受到攻击的服务事件中。我们还发现,许多误报是由与库/应用编程接口函数调用及其参数相关的标记引起的,因为这些标记经常出现在易受攻击的服务事件中。总之,我们已经
BGRU的有效性在很大程度上受到训练数据的影响。如果一些语法元素经常现在脆弱的sevc中(vs.不脆弱),那么这些元素可能会导致假阳性(相应地,假阴性)
使用定制的或通用的漏洞检测器?
在实践中,我们经常处理多种类型的漏洞(或SyVCs)。这就提出了一个新问题:我们应该使用多个神经网络(一个针对每种SyVCs),还是使用单个神经网络(容纳4种SyVCs)来检测漏洞?为了回答这个问题,我们做了以下实验。对于FC-、AU-和PU- kind SyVCs,我们随机选取从训练程序中提取的30000个SeVCs作为训练集,从测试程序中提取的7500个SeVCs作为测试集,其中的SeVCs容纳由数据依赖和控制依赖引起的语义信息。AE-kind少得多的漏洞,我们使用的所有20336 SeVCs提取培训项目的培训(其中15.9%是脆弱的,其余的84.1%是没有),和所有的1818 SeVCs提取测试程序测试(其中12.0%是脆弱的,其余的88.0%是不会)。
表五总结了实验结果。我们观察到,除PU外,使用每种SyVCs特有的BGRU检测与4种SyVCs相关的漏洞比使用单一BGRU更有效。这对于PU来说不太可能成立,因为从表II中可以看出,PU类SyVCs中脆弱与非脆弱的SeVCs的比例是1:9,远远小于其他3类SyVCs中平均1:4的比例。因此,所得到的BGRU将偏向于不脆弱的sevc,导致高FNR。总之
洞察4:使用为特定类型的漏洞定制的BGRU比使用单个BGRU来检测多种类型的漏洞要好。
3)回答RQ3的实验:
我们使用实验来比较(I)所学习的6个神经网络的有效性,从适应由数据依赖和控制依赖引起的语义信息的语义模型中学习的6种神经网络。在这两种情况下,我们随机选择30000 SeVCs提取培训项目作为训练集和7500年SeVCs提取测试项目的测试集。所有这些训练集和测试集对应于四种SyVCs,他们的数量成正比,第二列的表二所示。
表六总结了结果。我们观察到,容纳由数据依赖和控制依赖引起的语义信息可以提高几乎每个场景中的漏洞检测能力,并且平均降低19.6%的模糊推理率。这可以用以下事实来解释:控制依赖关系提供了对漏洞检测有用的额外信息
为学习神经网络提供的语义信息越多,所学习的神经网络的脆弱性检测能力就越高。
4)回答RQ4的实验:
我们认为BGRU是从对应于从训练程序中提取的4种语义特征向量的341,536个语义特征向量和从测试程序中提取的79,091个语义特征向量中学习的,同时适应由数据依赖和控制依赖引起的语义信息。我们将我们最有效的BGRU模型与商业静态漏洞检测工具Checkmarx [6]和开源静态分析工具Flawfinder [4]和RATS [5]进行了比较,因为(I)这些工具可以说代表了漏洞检测的最先进的静态分析;(二)它们被广泛用于检测C/C++源代码中的漏洞;(iii)它们直接对源代码进行操作(即不需要编译源代码);以及(iv)我们可以使用它们。我们还考虑了先进的系统VUDDY [2],它特别适用于检测代码克隆引起的漏洞。我们进一步考虑了VulDeePecker [11],我们考虑了所有4种SyEvC和数据以及SySeVR的控制依赖。
表七总结了实验结果。我们观察到,SySeVR支持的BGRU大大优于最先进的漏洞检测方法。开源的Flawfinder和RATS有很高的FPR和fnr
Checkmarx比Flawfinder和RATS好,但仍然有较高的FPRs和FNRs。VUDDY以高FNR换取低FPR而闻名,因为它只能检测到与训练程序中几乎相同的漏洞。启用sysevrbgru比VulDeePecker更有效,因为VulDeePecker不能处理其他类型的SyVCs(除了FC),也不能适应由控制依赖引起的语义信息。此外,从较大训练集(即341,536个SeVCs)学习的BGRU比从较小训练集(30,000个SeVCs;FNR降低6.7%,见表四)。总之
启用sysevr的BGRU比最先进的漏洞检测方法更有效。
应用BGRU检测软件产品漏洞:为了展示SySeVR在检测真实软件产品中的软件漏洞方面的有效性,我们使用启用了SySeVR的BGRU检测了4个产品的漏洞:Libav、Seamonkey、Thunderbird和Xen。每个产品都包含多个目标程序,我们从中提取它们的syvc、sevc和vectors。对于每个产品,我们都在其20个版本中应用了启用sysevr的BGRU,这样我们就可以知道在发布新版本时,供应商是否悄悄地修补了一些漏洞。
如表八所示,我们发现了15个在NVD没有报告的漏洞。其中,7种未知(即它们在这些产品中的存在直到现在才为人所知),并且确实与表八中提到的CVE标识符(CVE标识)相似(根据我们的人工检查)。出于道德考虑,我们没有给出这些漏洞的全部细节,但我们已经向供应商报告了这7个漏洞。其他8个漏洞已经被供应商在发布有问题的产品的新版本时“悄悄地”修补过了。
局限性
目前的研究有几个局限性。首先,我们关注于检测C/ c++程序源代码中的漏洞,这意味着框架可能需要进行调整,以应对其他编程语言和/或可执行文件。第二,我们的实验涵盖了4种SyVCs;未来的研究需要适应更多种类的SyVCs。第三,对生成SyVCs和SeVCs的算法进行改进,以适应更多的语法/语义信息用于漏洞检测。第四,我们在SeVC粒度上检测漏洞(即语义上相互关联的多行代码),这可以得到改进更精确地确定包含漏洞的代码行。第五,截断由SeVCs变换而来的大于阈值的向量;未来的研究需要探讨如何在不丢失截断信息的情况下处理矢量长度变化的问题。第六,我们的实验表明,一些深度神经网络比目前最先进的漏洞检测方法更有效。虽然我们已经在解释为什么这部分上有了一些见解,但需要更多的研究来解释深度学习在这种背景下以及其他方面的成功[39]
与漏洞检测相关的前期研究。基于源代码的静态漏洞检测有两种方法:基于代码相似性的和基于模式的。由于基于代码相似性的检测器只能检测由代码克隆引起的漏洞,并且本研究是一种基于模式的方法,我们回顾了后一种方法的先前研究。表九总结了SySeVR和以前的漏洞检测方法的比较,根据自动化程度分为三类。(一)手工方法:脆弱性模式由人类专家手工生成(如Flawfinder [4]、RATS [5]、Checkmarx [6])。这些工具经常导致高假阳性和/或高假阴性[35],我们的实验也证实了这一点(第三节-C4)。(二)半自动方法:需要人类专家手动定义特征(例如,导入和函数调用[8];复杂性、代码流失和开发人员活动[40];API符号和子树[10];和系统调用[7]),用于传统的机器学习模型,例如支持向量机和k-近邻。不同的漏洞往往用不同的特征来描述(如格式字符串漏洞[41];信息泄露漏洞[42];缺少检查漏洞[9];和污点式漏洞[43],[44])。该方法通常以粗粒度检测漏洞(例如,程序[7];组件[8];文件[40];或函数[10]),这意味着无法确定漏洞的位置。(三)更自动化的方法:人类专家不需要定义特征。林等人[15]提出了一种用于自动学习函数的高级表示的方法(即,粗粒度且不能确定漏洞位置)。VulDeePecker [11]是第一个展示使用深度学习来检测漏洞,同时能够确定漏洞位置的可行性的系统。SySeVR是第一个使用深度学习来检测漏洞的系统框架。
先前的研究与深度学习有关。深度学习已经用于程序分析。CNN已经用于软件缺陷预测[17],恶意URL,文件路径检测,注册表项检测[45];DBN已经用于软件缺陷预测[19],[20];RNN已被用于漏洞检测[11],[15],软件可追溯性[12],代码克隆检测[13],以及识别二进制文件中的函数[14]。本研究为使用深度学习来检测漏洞提供了第一个框架。
总结
我们提出了SySeVR框架,利用深度学习来检测漏洞。基于我们收集的大量漏洞数据,我们得出了许多见解,包括对深度学习在漏洞检测中的有效性的解释。此外,我们还发现了15个未在NVD中报告的漏洞。在这15个漏洞中,有7个是未知的,已经报告给了供应商,另外8个是在发布新版本时被供应商悄悄修补的