本论文相关内容
- 论文下载地址——Web Of Science
- 论文中文翻译——SySeVR A Framework for Using Deep Learning to Detect Software Vulnerabilities
- 论文阅读笔记——SySeVR A Framework for Using Deep Learning to Detect Software Vulnerabilities
文章目录
- 本论文相关内容
- 前言
- SySeVR:一种使用深度学习检测软件漏洞的框架
-
- 摘要
- 1 引言
- SySeVR框架
-
- 2.1 基本思想和框架概述
-
- 2.2 提取SyVCs
-
- 2.2.1 提取漏洞语法特征
- 2.2.2 定义和提取SyVCs
- 2.3 将SyVCs转换为SeVCs
-
- 2.3.1 基本定义
- 2.3.2 定义程序切片
- 2.3.3 定义SeVCs
- 2.3.4 计算SeVCs
- 2.4 将SeVCs编码为向量
- 2.5 标记SeVCs和对应的向量
- 3 实验与结果
-
- 3.1 研究问题
- 3.2 数据集
- 3.3 评价指标
- 3.3 实验
-
- 3.3.1 提取SyVCs
- 3.3.2 将SyVCs转换为SeVCs
- 3.3.3 将SeVCs编码为向量表示
- 3.3.4 生成SeVCs的基本真实标签
- 3.4 实验结果
-
- 3.5.1 回答RQ1的实验
- 3.5.2 回答RQ2的实验
- 3.5.3 回答RQ3的实验
- 3.5.4 回答RQ4的实验
- 3.5.5 BGRU在软件产品漏洞检测中的应用
- 4 局限性
- 5 相关工作
-
- 5.1 与漏洞检测相关的研究
- 5.2 与深度学习相关的研究
- 6 结论
- 总结
前言
这应该是到目前为止我读过的最难的一篇文章了,断断续续读了半个多月,里面提出的想法真的很新颖,后面争取复现一下代码,下面是我读这篇文章做的笔记!
SySeVR:一种使用深度学习检测软件漏洞的框架
摘要
之前我们学习的关于使用深度学习应用到漏洞检测的论文描述的都是一种方法或者工具,虽然减轻了手动定义漏洞特征的繁重工作,但是并没有对漏洞检测的有效性进行系统的解释,针对这一问题,本文提出了第一个使用深度学习来检测带有源代码的C/C++程序漏洞的系统,该框架被称为:基于语法、基于语义和矢量表示(SySeVR)。本文做出的主要贡献如下:
- 能获得容纳与漏洞相关的语法和语义信息的程序表示
- 通过检测到国家漏洞数据库中未报告的15个漏洞来证明该框架的有效性
- 将其中7个未知的漏洞报告给软件供应商
- 另外8个漏洞已经在软件更新后由供应商“悄悄地”修补
- 对深度学习在漏洞检测中有效性的解释
1 引言
作者首先指出,软件漏洞是不可避免地,所以尽早发现它们十分重要。目前对于源码漏洞检测主要有两种方法:
- 基于代码相似性的方法:可以检测由代码克隆引起的漏洞,但是当漏洞不是由代码克隆造成时,这种方法具有很高的假阴性
- 基于模式的方法:需要人类专家定义漏洞特征,所以这种方法容易出错且费力
所以作者认为,一个好的漏洞检测系统,应该能做到:
- 有效检测各种原因引起的漏洞
- 尽可能少地依赖人类专家
如何有效地解决以上问题呢?作者提出了使用深度学习应用到源码漏洞检测的想法。但是深度学习适用于处理矢量输入数据的情况,而软件程序没有这种矢量表示。针对这个问题,作者提出了第一个基于深度学习的漏洞检测系统,称为VulDeePecker(之前分析过的论文),可以在切片级别(语义上相互关联的多行代码)进行漏洞检测。但是VulDeePecker存在一些局限性:
- 它只考虑与库/API函数调用相关的漏洞
- 它仅利用由数据依赖性引起的语义信息
- 它只考虑被称为双向长短期记忆(BLSTM)的特定RNN
- 不擅长解释假阳性和假阴性的原因
为了克服VulDeePecker的上述缺点,在本文作者提出了第一个使用深度学习检测带有源代码的C/C++程序漏洞的系统框架,此框架主要解决了以下问题:如何将程序表示为向量,以适应适合漏洞检测的语法和语义信息?说白了就是如何在VulDeePecker的基础上,达到更高效的漏洞检测效果。为了实现这一目的,作者引入两个概念:
- 基于语法的候选漏洞(SyVCs):反映漏洞的语法特征
- 基于语义的候选漏洞(SeVCs):反映数据依赖性和控制依赖性引起的语义信息
这也是为什么本框架被称为基于语法、基于语义和矢量表示(简称SySeVR),此外本文的贡献还包括:
- 设计了自动提取SyVCs和SeVCs的算法
- SySeVR克服了VulDeePecker的上述缺点
用于测试的数据集可从https://github.com/SySeVR/SySeVR公开获取,其中是包含126种类型的漏洞数据集,使用此数据集通过实验证明了SySeVR可以实现以下目标:
- SySeVR使多种神经网络能够检测各种漏洞
- 因为BGRU的有效性在很大程度上受到训练数据的影响,所以可以在一定程度上解释假阳性和假阴性的原因
- 容纳更多语义信息(即控制依赖性和数据依赖性)可以提高启用SySeVR的漏洞检测器的有效性。
- 使用支持SySeVR的BGRU检测到现实中四种软件存在的漏洞,且将软件漏洞的信息报告给各位的供应商
- 成功证明了SySeVR的有效性
本文后续内容的文章结构如下:
- 第二节:介绍SySeVR框架
- 第三节:描述实验和结果
- 第四节:讨论了本研究的局限性
- 第五节:回顾了相关的前期工作
- 第六节:全文总结
SySeVR框架
2.1 基本思想和框架概述
2.1.1 基本思想
通过深度学习在图像处理中的region proposal(候选框)的概念启发,我们想是否可以将深度学习方法应用到漏洞检测环境中呢?我们可以通过一个例子来看深度学习在图像中检测人类的例子。
图1 (a)图像处理中region proposal的概念。
- 原理是将相似纹理、相似颜色、相邻边缘的区域划分为一个region proposal,将输入图像提取多个区域region proposal
- 将每个region proposal视为一个“单元”,使用向量表示
- 通过训练神经网络检测对象,判断哪个区域region proposal是我们的检测目标
通过以上例子的启示,若应用深度学习到漏洞检测,我们需要以一种能够充分容纳漏洞相关的语法和语义信息的方式表示程序。那么应该如何划分region proposal还保留语法和语义信息呢?有两个思路:
- 将程序中的每个函数视为图像处理中的一个region proposal,但是这种方法有一个缺点:
- 将每一行代码或语句作为漏洞检测的一个单元,这种方法也存在两个缺点
- 程序中的大多数语句不包含任何漏洞,这意味着很少有样本是受攻击的
- 语义上相互关联的多个语句不被视为一个整体
既然粒度不能太高,也不能太低,那就取一个折中值,将一个程序划分为更小的代码段(即许多语句),这些代码段对应于region proposal,不仅保证了较低的粒度,还可以保证漏洞的语法和语义特征
2.1.2 框架概述
图1(b)显示了受region proposal概念启发的SySeVR框架。从本质上说,该框架寻找适合于漏洞检测程序的SyVC、SeVC和向量表示。
图1 (b) SySeVR框架的灵感来自于region proposal的概念,并以获取程序的SyVC、SeVC和矢量表示为中心。
整个过程其实与图1 (a)类似,最终都是通过将数据转换为向量进行训练判断,但是对于源代码来说,如何将程序转换为向量是我们需要考虑的问题。我们可以通过图2中描述的示例来强调SySeVR提取SyVC、SeVC和程序的向量表示的过程。这个过程也只是一个抽象表示,具体的实现细节可以参考图3。
图2 说明程序的SyVC、SeVC和向量表示的示例,其中SyVCs用方框突出显示,一个SyVC可能是另一个SyVC的一部分。SyVC→SeVC的转换在图3中详细说明。
- 用方框表示SyVC(一个与某些漏洞的语法特征匹配的代码元素)
- 在SyVC的基础上拓展SeVC,得到包含由控制依赖或数据依赖引起的语义信息的代码行
- 将每个SeVC作为编码向量输入到深度神经网络
2.2 提取SyVCs
2.2.1 提取漏洞语法特征
不管什么方法,都需要提取到漏洞的语法特征,只有提取到漏洞语法特征,才能进行针对性的判断。比如与指针使用相关的漏洞的标识符生命中都包含符`*`,例如图2中的第18行。但是由于漏洞的种类太多,分别为每一个漏洞定义和提取它们的语法特征是非常耗时的。针对如何提取漏洞语法特征,本文也提出了一个具体方法,具体可参考3.3.1节。
提取到漏洞语法特征后,用 H = { h k } 1 ≤ k ≤ β H=\left\{h_{k}\right\}_{1 \leq k \leq \beta} H={hk}1≤k≤β表示一组漏洞语法特征,其中:
- h k h_k hk代表一个漏洞语法特征
- β β β为漏洞语法特征的个数
给定 H H H,我们需要确定一段代码是否匹配语法特征 h k h_k hk。
2.2.2 定义和提取SyVCs
- 定义1(程序、函数、语句、标记):
- P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη}:表示程序 P P P是由一组函数 f 1 , … , f η f_1,…, f_η f1,…,fη组成
- f i = { s i , 1 , … , s i , m i } f_i = \left\{s_{i, 1}, \ldots, s_{i, m_{i}}\right\} fi={si,1,…,si,mi}:表示函数 f i f_i fi是语句 s i , 1 , … , s i , m i s_{i, 1}, \ldots, s_{i, m_{i}} si,1,…,si,mi的有序集合,其中 1 ≤ i ≤ η 1≤i≤η 1≤i≤η
- s i , j = { t i , j , 1 , … , t i , j , w i , j } s_{i, j}=\left\{t_{i, j, 1}, \ldots, t_{i, j, w_{i, j}}\right\} si,j={ti,j,1,…,ti,j,wi,j}:表示语句 s i , j s_{i,j} si,j是标记 t i , j , 1 , … , t i , j , w i , j t_{i, j, 1}, \ldots, t_{i, j, w_{i, j}} ti,j,1,…,ti,j,wi,j的有序集合,其中 1 ≤ i ≤ η 1≤i≤η 1≤i≤η并且 1 ≤ j ≤ m i 1≤j≤m_i 1≤j≤mi
可以发现其中最小单位就是标记,标记可以是标识符、操作符、常量和关键字。可以通过词法分析提取。
具体的漏洞语法特征提取过程可以参考3.3.1节,这里给出一个简单的介绍。给定一个函数 f i f_i fi:AST的根对应函数 f i f_i fi;AST的叶对应标记 t i , j , g ( 1 ≤ g ≤ w i , j ) t_{i,j,g}(1≤g≤w_{i,j}) ti,j,g(1≤g≤wi,j);AST的内部节点对应语句 s i , j s_{i,j} si,j或 s i , j s_{i,j} si,j的多个连续标记。
- 定义2 (SyVC):
- e i , j , z e_{i,j,z} ei,j,z:由 s i , j s_{i,j} si,j的一个或多个连续标记组成的代码元素,即 e i , j , z = ( t i , j , u , … , t i , j , v ) e_{i,j,z}=\left(t_{i, j, u}, \ldots, t_{i, j, v}\right) ei,j,z=(ti,j,u,…,ti,j,v)其中 1 ≤ u ≤ v ≤ w i , j 1≤u≤v≤w_{i,j} 1≤u≤v≤wi,j
- SyVC:匹配漏洞语法特征 h k h_k hk的代码元素 e i , j , z e_{i,j,z} ei,j,z,即给定一组漏洞语法特征 H = { h k } 1 ≤ k ≤ β H = \{h_k\}_{1≤k≤β} H={hk}1≤k≤β,其中 h k h_k hk表示漏洞语法特征
通过这个定义,我们可以明白:SyVC对应于AST的叶节点(这意味着它是一个标记),或者形式上对应于AST的内部节点(这意味着它是一条语句或由多个连续标记组成)。算法1也给出了提取SyVCs的具体描述,主要分为以下两步(具体步骤可参考3.3.1节):
- 每个函数 f i f_i fi生成一个AST T i T_i Ti
- 遍历 T i T_i Ti来识别SyVCs,即“匹配”某些 h k h_k hk的代码元素
2.3 将SyVCs转换为SeVCs
2.3.1 基本定义
但是为了准确的检测漏洞,仅仅依靠SyVCs是不够的,还要利用SeVCs,也就是说在提取到SyVCs的基础将SyVC→SeVC是目前需要研究的问题。本文提出使用程序切片技术来识别与SyVCs语义相关的语句,那么如何利用程序切片呢?别急,我们首先要清楚几个定义:
-
定义3(CFG):
- V i V_i Vi:是由 { n i , 1 , … , n i , c i } \{n_{i,1},…, n_{i,c_{i}}\} {ni,1,…,ni,ci}构成的一组节点,每个节点代表一个语句或控制谓词
- E i E_{i} Ei:是由 { ϵ i , 1 , … , ϵ i , d i } \left\{\epsilon_{i, 1}, \ldots, \epsilon_{i, d_{i}}\right\} {ϵi,1,…,ϵi,di}构成的一组直接边,每条边代表一对节点之间可能的控制流
- CFG:表示给定程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη}中函数 f i f_i fi的一个图 G i = ( V i , E i ) G_i = (V_i, E_i) Gi=(Vi,Ei)
-
定义4(数据依赖):考虑一个程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη},函数 f i f_{i} fi和在 G i G_{i} Gi中的两个节点 n i , j n_{i,j} ni,j和 n i , ℓ n_{i,\ell} ni,ℓ的CFG为 G i = ( V i , E i ) G_{i} = (V_{i}, E_{i}) Gi=(Vi,Ei),其中 1 ≤ j , ℓ ≤ c i 1 \leq j, \ell \leq c_{i} 1≤j,ℓ≤ci,并且 j ≠ ℓ j \neq \ell j=ℓ。如果 G i G_{i} Gi中有从 n i , ℓ n_{i,\ell} ni,ℓ到 n i , j n_{i,j} ni,j的路径,并且在节点 n i , j n_{i,j} ni,j处使用在节点 n i , ℓ n_{i,\ell} ni,ℓ处计算的值,那么 n i , j n_{i,j} ni,j的数据依赖于 n i , ℓ n_{i,\ell} ni,ℓ。
-
定义5(控制依赖):考虑一个程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη},函数 f i f_{i} fi和在 G i G_{i} Gi中的两个节点 n i , j n_{i,j} ni,j和 n i , ℓ n_{i,\ell} ni,ℓ的CFG为 G i = ( V i , E i ) G_{i} = (V_{i}, E_{i}) Gi=(Vi,Ei),其中 1 ≤ j , ℓ ≤ c i 1 \leq j, \ell \leq c_{i} 1≤j,ℓ≤ci,并且 j ≠ ℓ j \neq \ell j=ℓ。其中 n i , j n_{i,j} ni,j后置支配 n i , ℓ n_{i,\ell} ni,ℓ,如果从 n i , ℓ n_{i,\ell} ni,ℓ到程序末尾的所有路径都穿过 n i , j n_{i,j} ni,j。如果存在从 n i , ℓ n_{i,\ell} ni,ℓ开始到 n i , j n_{i,j} ni,j结束的路径,使得
- n i , j n_{i,j} ni,j后置支配在路径上除 n i , ℓ n_{i,\ell} ni,ℓ和 n i , j n_{i,j} ni,j的所有节点
- n i , j n_{i,j} ni,j并不后置支配 n i , ℓ n_{i,\ell} ni,ℓ
那么 n i , j n_{i,j} ni,j控制依赖于 n i , ℓ n_{i,\ell} ni,ℓ。
-
定义6(PDG):
- V i V_i Vi:是由 { n i , 1 , … , n i , c i } \{n_{i,1},…, n_{i,c_{i}}\} {ni,1,…,ni,ci}构成的一组节点,每个节点代表一个语句或控制谓词
- E i ′ E_{i}^{\prime} Ei′:是由 { ϵ i , 1 ′ , … , ϵ i , d i ′ ′ } \left\{\epsilon_{i, 1}^{\prime}, \ldots, \epsilon_{i, d_{i}^{\prime}}^{\prime}\right\} {ϵi,1′,…,ϵi,di′′}构成的一组直接边,每条边代表一对节点之间的数据或控制依赖关系
- PDG:表示给定程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη}中函数 f i f_i fi的一个图 G i ′ = ( V i , E i ′ ) G_{i}^{\prime}=\left(V_{i}, E_{i}^{\prime}\right) Gi′=(Vi,Ei′)
2.3.2 定义程序切片
当我们从SyVCs中提取到程序片段后,还要考虑前向和后向切片,因为:
- SyVC可能会影响一些后续语句
- 影响SyVC的语句可能使SyVC易受攻击
所以我们要考虑程序片段中的前向和后向切片,定义如下:
- 定义7(SyVC中的前向和后向程序切片):考虑一个程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη},各函数 f i ( 1 ≤ i ≤ η ) f_{i}(1 \leq i \leq \eta) fi(1≤i≤η)的PDG G i ′ = ( V i , E i ′ ) G_{i}^{\prime}=\left(V_{i}, E_{i}^{\prime}\right) Gi′=(Vi,Ei′), 并且在 G i ′ G_{i}^{\prime} Gi′中语句 s i , j s_{i,j} si,j的SyVC e i , j , z e_{i,j,z} ei,j,z。
- f s i , j , z fs_{i,j,z} fsi,j,z:表示SyVC e i , j , z e_{i,j,z} ei,j,z在 f i f_i fi中的正向切片。定义为一个有序的节点集 { n i , x 1 , … n i , x μ i } ⊆ V i \left\{n_{i, x_{1}}, \ldots\right.\left.n_{i, x_{\mu_{i}}}\right\} \subseteq V_{i} {ni,x1,…ni,xμi}⊆Vi,其中:
- n i , x p , 1 ≤ x 1 ≤ x p ≤ x μ i ≤ c i n_{i, x_{p}}, 1 \leq x_{1} \leq x_{p} \leq x_{\mu_{i}} \leq c_{i} ni,xp,1≤x1≤xp≤xμi≤ci
- 可从 G i ′ G_{i}^{\prime} Gi′中的 e i , j , z e_{i,j,z} ei,j,z到达。即 f s i , j fs_{i,j} fsi,j中的节点来自 G i ′ G_{i}^{\prime} Gi′中从 e i , j , z e_{i,j,z} ei,j,z开始的所有路径
- f s i , j , z ′ \mathrm{fs}_{i, j, z}^{\prime} fsi,j,z′:表示程序 P P P中SyVC e i , j , z e_{i,j,z} ei,j,z的程序间正向切片。定义为一个有序的节点集,其中:
- 一个节点属于一个或多个PDGs
- 每个节点从 e i , j , z e_{i,j,z} ei,j,z开始通过一系列函数调用可达。也就是说, f s i , j , z ′ \mathrm{fs}_{i, j, z}^{\prime} fsi,j,z′是一个有或没有跨越函数边界(通过函数调用)的正向切片
- b s i , j , z \mathrm{bs}_{i, j, z} bsi,j,z:表示 f i f_i fi中SyVC e i , j , z e_{i,j,z} ei,j,z的后向切片。定义为一个有序的节点集 { n i , y 1 , … , n i , y ν i } ⊆ V i \left\{n_{i, y_{1}}, \ldots, n_{i, y_{\nu_{i}}}\right\} \subseteq V_{i} {ni,y1,…,ni,yνi}⊆Vi,其中:
- n i , y p , 1 ≤ y 1 ≤ y p ≤ y ν i ≤ c i n_{i, y_{p}}, 1 \leq y_{1} \leq y_{p} \leq y_{\nu_{i}} \leq c_{i} ni,yp,1≤y1≤yp≤yνi≤ci
- 在 G i ′ G_{i}^{\prime} Gi′中可达 e i , j , z e_{i,j,z} ei,j,z。即 b s i , j , z \mathrm{bs}_{i, j, z} bsi,j,z中的节点来自 G i ′ G_{i}^{\prime} Gi′中以 e i , j , z e_{i,j,z} ei,j,z结束的所有路径
- b s i , j , z ′ \mathrm{bs}_{i, j, z}^{\prime} bsi,j,z′:表示程序 P P P中SyVC e i , j , z e_{i,j,z} ei,j,z的程序间后向切片。定义为节点的有序集合,其中:
- 一个节点属于一个或多个PDGs
- 每个节点可以通过一系列函数调用到达 e i , j , z e_{i,j,z} ei,j,z。也就是说, b s i , j , z ′ \mathrm{bs}_{i, j, z}^{\prime} bsi,j,z′是一个反向切片,有或没有跨越函数边界(通过函数调用)
- p s i , j , z \mathrm{ps}_{i, j, z} psi,j,z:通过连接前向切片 f s i , j , z ′ \mathrm{fs}_{i, j, z}^{\prime} fsi,j,z′与后向切片 b s i , j , z ′ \mathrm{bs}_{i, j, z}^{\prime} bsi,j,z′的保序方式,同时忽略相邻重复节点(即用一个节点替换同一节点的多个相邻出现)得到的有序集。
对于以上定义可以通过图3中的第三列加深理解,考虑SyVC“data”。
图3 在算法2中为SyVC“数据”详细说明SyVC→SeVC转换过程,其中实箭头(即有向边)表示数据依赖,虚线箭头表示控制依赖。注意每个实箭头(即数据依赖)都用在问题中引起相关数据依赖的变量名进行了注释。
- SyVC“data”的程序间前向切片:跨越了函数 f u n c func func和 p r i n t l n println println
- SyVC“data”的程序间后向切片:与函数 f u n c func func中的SyVC“data”的后向切片相同,因为没有其他函数调用函数 f u n c func func
- SyVC“data”的程序切片:通过连接程序间前向切片和程序间后向切片而获得,同时省略与SyVC“data”对应的节点的一个(两个中的一个)相邻出现(程序源代码第25行)
2.3.3 定义SeVCs
- 定义8 (SeVC):给定一个程序 P = { f 1 , … , f η } P = \{f_1,…,f_η\} P={f1,…,fη}和在函数 f i f_{i} fi的语句 s i , j s_{i,j} si,j中有一个SyVC e i , j , z e_{i,j,z} ei,j,z,则SyVC e i , j , z e_{i,j,z} ei,j,z对应的SeVC,记为 δ i , j , z \delta_{i, j, z} δi,j,z,定义为 P P P中语句的有序子集,记为 δ i , j , z = { s a 1 , b 1 , … , s a v i , j , z , b v i , j , z } \delta_{i, j, z}=\left\{s_{a_{1}, b_{1}}, \ldots, s_{a_{v_{i, j, z}}}, b_{v_{i, j, z}}\right\} δi,j,z={sa1,b1,…,savi,j,z,bvi,j,z},其中语句 s a p , b q ( 1 ≤ p , q ≤ v i , j , z ) s_{a_{p}, b_{q}}\left(1 \leq p, q \leq v_{i, j, z}\right) sap,bq(1≤p,q≤vi,j,z)与SyVC e i , j , z e_{i,j,z} ei,j,z之间存在数据依赖或控制依赖。
2.3.4 计算SeVCs
当我们定义好一些基础内容后,就可以计算源码中的SeVCs了,整个步骤可以参照算法2,并使用图3来说明一个运行示例。具体包括三个步骤,如下所示:
-
生成PDGs(算法2中的第2-4行):
该步骤为每个函数生成一个PDG。图3的第二列显示了分别对应于函数 f u n c func func和 p r i n t l n println println的PDGs,其中每个数字表示语句的行号。
-
用算法1生成SyVCs输出的程序片(算法2中的第6-9行):
该步骤为每个SyVC e i , j , z e_{i,j,z} ei,j,z生成程序片 p s i , j , z \mathrm{ps}_{i, j, z} psi,j,z。将 f s i , j , z \mathrm{fs}_{i, j, z} fsi,j,z与 f i f_{i} fi调用的函数的前向切片合并,得到程序间前向切片 f s i , j , z ′ \mathrm{fs}_{i, j, z}^{\prime} fsi,j,z′。通过合并 b s i , j , z \mathrm{bs}_{i, j, z} bsi,j,z和来自 f i f_{i} fi调用的函数和 f i f_{i} fi调用函数的后向切片来获得程序间后向切片 b s i , j , z ′ \mathrm{bs}_{i, j, z}^{\prime} bsi,j,z′。最后将 f s i , j , z ′ \mathrm{fs}_{i, j, z}^{\prime} fsi,j,z′和 b s i , j , z ′ \mathrm{bs}_{i, j, z}^{\prime} bsi,j,z′合并为程序片 p s i , j , z \mathrm{ps}_{i, j, z} psi,j,z。其中:
- SyVC的前向切片:只利用了数据依赖关系,原因如下:
- 通过控制依赖关系受SyVC影响的语句在大多数情况下不会受到攻击
- 利用对SyVC有控制依赖关系的语句将涉及许多与漏洞几乎没有关系的语句
- SyVC的后向切片:同时利用数据依赖性和控制依赖性
-
将程序切片转换为SeVCs(算法2中的第10-19行):
- 在相同函数中:该算法将属于函数 f i f_{i} fi且出现在 p s i , j , z \mathrm{ps}_{i, j, z} psi,j,z中的语句作为节点转换为SeVC,同时保持这些语句在 f i f_{i} fi中的顺序。如图3所示的运行示例:
- 根据其中13条语句在函数 f u n c func func中的顺序,得到有序的语句集(SeVC):第{7、9、10、11、12、14、16、18、22、23、24、25、26}行
- 根据其中3条语句在函数 p r i n t l n println println中的顺序,得到有序的数据集(SeVC):第{1、3、4}行
- 在不同函数中:该算法将属于不同函数的语句转换为SeVC。对于在 p s i , j , z \mathrm{ps}_{i, j, z} psi,j,z中作为节点出现的语句 s i , j ∈ f i s_{i, j} \in f_{i} si,j∈fi和 s a p , b q ∈ f a p ( i ≠ a p ) s_{a_{p}, b_{q}} \in f_{a_{p}}\left(i \neq a_{p}\right) sap,bq∈fap(i=ap),如果 f i f_{i} fi调用 f a p f_{a_{p}} fap,则 s i , j s_{i,j} si,j和 s a p , b q s_{a_{p}, b_{q}} sap,bq的函数调用顺序相同,即 s i , j < s a p , b q s_{i, j}si,j<sap,bq;否则, s i , j > s a p , b q s_{i, j}>s_{a_{p}, b_{q}} si,j>sap,bq。如图3所示的运行示例:
- SeVC是第{7,9,10,11,13,14,16,18,22,23,24,25,26,1,3,4}行,其中函数 f u n c func func中的语句出现在函数 p r i n t l n println println的语句之前,因为 f u n c func func调用了 p r i n t l n println println。
2.4 将SeVCs编码为向量
当我们从SyVCs中提取到程序切片后,就要进行最后一步,也就是将此程序切片转换为SeVCs,此过程通过算法3实现:
-
算法3中的第2-6行:
①:删除非ASCII字符和注释
②:以一对一的方式将用户定义的变量名映射到符号名(例如“V1”,“V2”)
③:以一对一的方式将用户定义的函数名映射到符号名(例如“F1”,“F2”)
此步骤的作用如下:
- 使SeVCs独立于用户定义的变量和函数名
- 捕获程序语义信息,每个SeVC δ i , j , z \delta_{i, j, z} δi,j,z被转换为符号表示
-
算法3中的第8-13行:这一步将符号表示编码为向量。作者建议通过词法分析(例如,“V1”,“=”,“V2”,“-”,“8”,和“;”)将SeVC δ i , j , z \delta_{i, j, z} δi,j,z的符号表示(例如,“V1=V2-8;”)划分为符号序列。我们把一个符号转换成一个固定长度的向量。通过连接这些向量,我们得到了每个SeVC的一个向量 R i , j , z R_{i,j,z} Ri,j,z。
-
算法3第14-22行:此步骤也是整个算法中最重要的一步,因为符号的数量(即表示SeVCs的向量)可能不同,但是神经网络要求输入向量都是相同长度,所以如何调整SeVCs的向量长度以适应神经网络的输入向量长度是目前需要解决的问题。作者定义阈值 θ θ θ作为神经网络输入向量的长度,那么就有两种情况:
-
SeVCs的向量长度小于 θ θ θ:
零被加到该向量的末尾。
-
SeVCs的向量长度大于 θ θ θ:
-
当SyVC的子向量小于 θ / 2 θ/2 θ/2:删除 R i , j , z R_{i,j,z} Ri,j,z的最右边部分,使得到的向量的长度为 θ θ θ
-
当SyVC的子向量大于 θ / 2 θ/2 θ/2:删除 R i , j , z R_{i,j,z} Ri,j,z的最左边部分,使得到的向量的长度为 θ θ θ
-
当SyVC的子向量等于 θ / 2 θ/2 θ/2:保持长度为 ⌊ ( θ − 1 ) / 2 ⌋ \lfloor(\theta-1) / 2\rfloor ⌊(θ−1)/2⌋的子向量紧靠SyVC左侧,并保持长度为 ⌈ ( θ − 1 ) / 2 ⌉ \lceil(\theta-1) / 2\rceil ⌈(θ−1)/2⌉的子向量紧靠SyVC右侧
可以看到,不管是哪种情况,基本思想是使SyVC出现在结果向量的中间。最终结合SyVC得到长度为 θ θ θ的向量。可以通过一个例子强化对于此步骤的理解(SeVCs的向量长度大于 θ θ θ,并且SyVC的子向量等于 θ / 2 θ/2 θ/2):假设 θ = 15000 θ = 15000 θ=15000,每个符号的长度是30,这意味着每个SeVC有500个符号。假设一个SeVC中的符号数是510(因此需要减少到500),而SyVC位于第255个符号的位置(在510个符号中),那么保留紧靠SyVC左侧的249个连续符号和紧靠SyVC右侧的250个连续符号。结合SyVC,我们得到了一个500=249+1+250个符号的向量。
2.5 标记SeVCs和对应的向量
为了训练深度神经网络,还要将SeVCs向量标记为易受攻击的或不易受攻击的训练数据(当然,测试的时候并不会有标记):
- 易受攻击的SeVC向量:标记为“1”
- 不易受攻击的SeVC向量:标记为“0”
训练好的神经网络模型就可以检测给定的SeVCs是否易受攻击。
3 实验与结果
3.1 研究问题
本文所进行的实验旨在回答以下问题(RQs):
- RQ1:SySeVR能让BLSTM检测到多种(或单一)漏洞吗?
- RQ2:SySeVR能否构建多种神经网络来检测多种漏洞?我们能解释一下它们的有效性吗?
- RQ3:适应控制依赖能使SySeVR更有效吗?提高多少?
- RQ4:与最先进的方法相比,基于SySeVR的方法如何更有效?
另外还需要注意本文所使用的实验环境,这对我们复现实验有着很大的帮助:
- 编程语言:Python
- 神经网络框架:Tensorflow
- GPU:NVIDIA GeForce GTX 1080
- CPU:Intel Xeon E5-1620 3.50GHz
3.2 数据集
本实验的数据集主要来自两个来源(如下所示),其中每种漏洞类型都由一个通用漏洞枚举标识(CWE ID)唯一标识。
- NVD数据集:包含软件产品中的漏洞,可能还包含diff文件,描述漏洞代码段与其补丁版本之间的差异
- SARD数据集:包含生产、合成和测试用例,它们被分为有漏洞、没有漏洞和有其补丁版本可用的漏洞
3.3 评价指标
对于一些度量变量的定义我们要清楚:
- T P TP TP:表示被检测为易受攻击的易受攻击样本的数量
- F P FP FP:表示不易受攻击但被检测为容易受攻击的样本的数量
- T N TN TN:表示不易受到攻击且被检测为不易受攻击的样本的数量
- F N FN FN:表示被检测到不易受威胁的易受攻击样本的数量
本实验结果采用以下度量指标进行评估:
- F P R FPR FPR:度量假阳性样本在不易受攻击样本中的比例
F P R = F P F P + T N F P R=\frac{\mathrm{FP}}{\mathrm{FP}+\mathrm{TN}} FPR=FP+TNFP
- F N R FNR FNR:度量易受攻击样本中假阴性样本的比例
F N R = F N T P + F N F N R=\frac{\mathrm{FN}}{\mathrm{TP}+\mathrm{FN}} FNR=TP+FNFN
A = T P + T N T P + F P + T N + F N A=\frac{\mathrm{TP}+\mathrm{TN}}{\mathrm{TP}+\mathrm{FP}+\mathrm{TN}+\mathrm{FN}} A=TP+FP+TN+FNTP+TN
- P P P:度量真正易受攻击样本在检测到易受攻击样本中的比例
P = T P T P + F P P=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FP}} P=TP+FPTP
- F 1 F 1 F1:通过考虑精度和假阴性率来度量整体有效性
F 1 = 2 ⋅ P ⋅ ( 1 − F N R ) P + ( 1 − F N R ) F 1=\frac{2 \cdot P \cdot(1-F N R)}{P+(1-F N R)} F1=P+(1−FNR)2⋅P⋅(1−FNR)
- M C C MCC MCC:度量模型预测与基本真实标签匹配的程度,适合处理不平衡的数据集
M C C = T P × T N − F P × F N ( T P + F P ) ( T P + F N ) ( T N + F P ) ( T N + F N ) M C C=\frac{\mathrm{TP} \times \mathrm{TN}-\mathrm{FP} \times \mathrm{FN}}{\sqrt{(\mathrm{TP}+\mathrm{FP})(\mathrm{TP}+\mathrm{FN})(\mathrm{TN}+\mathrm{FP})(\mathrm{TN}+\mathrm{FN})}} MCC=(TP+FP)(TP+FN)(TN+FP)(TN+FN) TP×TN−FP×FN
3.3 实验
3.3.1 提取SyVCs
-
提取漏洞语法特征:当我们获取到源代码后,首先就要提取漏洞语法特征,此步骤使用商业工具Checkmarx的C/C++漏洞规则来分析漏洞语法特征,通过分析最终得到了四种漏洞语法特征(每一种都容纳了许多漏洞)
- 库/API函数调用(简称FC):这种语法特性涵盖了811个库/API函数调用,这811个函数调用对应106个CWE IDs
- 数组用法(简称AU):这种语法特征涵盖了87个与数组相关的CWE IDs(例如,与数组元素访问、数组地址算术相关的问题)
- 指针使用(简称PU):这种语法特征涵盖103个与指针相关的CWE IDs(例如,在指针算术、引用、地址传输作为函数参数时的不当使用)
- 算术表达式(简称AE):这种语法特征涵盖了与不正确的算术表达式(如整数溢出)相关的45个CWE IDs
图4显示了这四种语法特征在它们覆盖的CWE IDs方面的相互重叠:
- 一种语法特征可能涵盖多个CWE IDs
- 一个CWE IDs可能涵盖一种或多种类型的语法特征
图4 FC、AU、PU和AE在它们覆盖的CWE IDs方面的维恩图,其中|FC| = 106, |AU| = 87, |PU| = 103, |AE| = 45, |FC∪AU∪PU∪AE| = 126。
从图4中可以看到:10个CWE IDs对应的漏洞被PU类语法特征覆盖,而不被其他语法特征覆盖,39个CWE IDs对应的漏洞被FC、AU、PU、AE这4种语法特征全部覆盖。
- 匹配语法特征:将程序 P P P中的函数 f i f_{i} fi表示为抽象语法树 T i T_{i} Ti, T i T_{i} Ti可以通过使用Joern生成,可用于判断其中的代码元素 e i , j , z e_{i,j,z} ei,j,z是否匹配语法特征,从而提取SyVCs。图2中的示例程序可以抽象为如图5所示的抽象语法树 T i T_{i} Ti:
图5 说明语法特征匹配的示例,其中高亮显示的节点匹配某些漏洞语法特征,因此是SyVC。
-
如图5(a)所示,当满足:
- e i , j , z e_{i,j,z} ei,j,z在 T i T_{i} Ti上是一个“被调用者”(即,函数被调用)
- e i , j , z e_{i,j,z} ei,j,z是上面提到的811个函数调用之一
可以认为代码元素 e i , j , z e_{i,j,z} ei,j,z(即“memset”)匹配FC语法特征
-
如图5(b)所示,当满足:
- e i , j , z e_{i,j,z} ei,j,z是在标识符声明语句(即IdentifierDeclStatement)节点中声明的标识符
- IdentifierDeclStatement节点包含字符’[‘and’]’
可以认为代码元素 e i , j , z e_{i,j,z} ei,j,z(即" source ")匹配AU语法特征
-
如图5(c)所示,当满足:
- e i , j , z e_{i,j,z} ei,j,z是在IdentifierDeclStatement节点中声明的标识符
- IdentifierDeclStatement节点包含字符“*”
可以认为认为代码元素 e i , j , z e_{i,j,z} ei,j,z(即“data”)匹配PU语法特征
-
如图5(d)所示,当满足:
- e i , j , z e_{i,j,z} ei,j,z 是一个表达式语句(ExpressionStatement)节点
- e i , j , z e_{i,j,z} ei,j,z 包含一个字符’=‘并在’='的右侧有一个或多个标识符
可以认为代码元素 e i , j , z e_{i,j,z} ei,j,z ("data=dataBuffer-8 ")匹配AE语法特征
-
提取SyVCs:有了以上定义后,作者使用算法1从15591个程序中提取到对应于4种语法特征的4种SyVCs:
- FC类SyVCs:从NVD中提取6356个,从SARD中提取58047个,总共64403个
- AU类SyVCs:从NVD中提取9812个,从SARD中提取32417个,总共42229个
- PU类SyVCs:从NVD中提取73890个,从SARD中提取217951个,总共291841个
- AE类SyVCs:从NVD中提取5295个,从SARD中提取16859个,总共22154个
其中需要注意的是:
- SARD给出了每个漏洞的精确位置
- NVD没有给出漏洞的精确位置
3.3.2 将SyVCs转换为SeVCs
提取到SyVCs后,使用算法2将SyVCs转换为两组SeVCs,转换结果如表1所示:
- 容纳仅由数据依赖引起的语义信息,转换的平均时间为331毫秒
- 容纳同时由数据依赖和控制依赖引起的语义信息,转换的平均时间为362毫秒
表1 15591个项目中SeVCs、易受攻击的SeVCs和非易受攻击的SeVCs的数量
3.3.3 将SeVCs编码为向量表示
为了进行神经网络的训练,需要将SeVCs编码为向量表示:
- 使用 w o r d 2 v e c word2vec word2vec将提取的SeVCs符号编码为定长向量。主要超参数包括:
- 词向量的维数为30
- 窗口大小为5
- 训练算法为skip-gram
- 配置高频词随机下采样的阈值为0.001
- 将每个SeVC由表示其符号的向量的拼接表示
- 将每个SeVC设置为500个符号(必要时填充或截断),其中:
- 每个符号的长度为30
- θ = 15000 θ = 15000 θ=15000
3.3.4 生成SeVCs的基本真实标签
为了训练模型,我们需要生成SeVCs的基本真实标签,主要分两个步骤:
-
自动生成初步标签
对于从NVD提取的SeVCs,检查其diff文件包含行删除的漏洞(不考虑仅包含行添加的diff文件),并解析它来标记和区分:
- 以“-”为前缀并被删除/修改的行(语句)
- 以“-”为前缀并被移动的行(例如在一处删除并在另一处添加)
以下情况SeVCs被标记为“1”(易受攻击的):
- SeVC包含至少一个以“-”为前缀的删除/修改语句
- SeVC包含至少一个以“-”为前缀的移动语句,并且检测到的文件包含已知的漏洞
- 从“坏”或“混合”程序中提取的SeVC包含至少一条易受攻击的语句
反之其他情况被标记为“0”(不易受攻击的):
-
提高上述初步标签的质量
使用分层 k k k-fold ( k k k=5)交叉验证来识别在上一步中可能被错误标记的易受攻击的SeVCs(同时注意到真正的易受攻击的样本永远不会被错误标记为“0”),主要包括以下几个步骤:
① 将数据集分为5个子集
② 一个子集作为验证集,其他4个子集放在一起作为训练集
③ 利用训练过的神经网络对验证集中的样本进行分类。假阴性被认为是可能被错误标记的样本
④ 手动检查这些样本,并纠正错误的样本
⑤ 重复执行步骤②~④,以便每个子集作为验证集使用一次
最终,对于所有数据,总共有56395个SeVCs被标记为“1”,364232个SeVCs被标记为“0”。详细信息可见表1
3.4 实验结果
实验数据集来自NVD和SARD,随机选择其中80%的程序作为训练集,其余20%的程序作为测试集。
3.5.1 回答RQ1的实验
本实验进行启用SySeVR的BLSTM与VulDeePecker的对比实验,其中用来学习BLSTM的主要超参数如下所示:
- dropout为0.2
- 批数为16个
- epochs为20
- 输出维度为256
- 使用小批随机梯度下降算法结合ADAMAX进行训练,默认学习率为0.002
- 隐向量维数为500
- 隐层数是2
实验结果如表2所示:
表2 VulDeePecker与启用SySeVR的BLSTM(或SySeVR-BLSTM)在检测与各种SyVCs相关的漏洞方面有效性的对比(度量单位:%)
结论1:SySeVR-BLSTM可以检测到与函数调用、数组使用、指针使用和算术表达式相关的漏洞,在检测库/API函数调用相关的漏洞时,SySeVR-BLSTM的 F P R FPR FPR和 F N R FNR FNR分别比VulDeePecker低 3.4 % 3.4\% 3.4%和 5.0 % 5.0\% 5.0%。
3.5.2 回答RQ2的实验
为了选出最适合启用SySeVR的模型,实验2使用分层的5倍交叉验证来训练8个标准模型:
- 线性逻辑回归(LR)分类器
- 具有一个隐藏层多层感知(MLP)的神经网络
- DBN
- CNN
- 4个RNNs
- 长短期记忆(LSTM)
- 门控循环单元(GRU)
- BLSTM
- BGRU
使用包含4种SyVCs的数据集,选择导致最高 F 1 F1 F1-度量的超参数值( F P R FPR FPR设置为 2.0 % 2.0\% 2.0%)。实验结果如表3所示:
表3 启用SySeVR的不同类型模型在检测4种漏洞时的有效性(度量单位:%)
结论2:支持SySeVR的双向RNN(特别是BGRU)比支持SySeVR的单向RNN和CNN更有效,后者比支持SySeVR的DBN和浅层学习模型(即LR和MLP)更有效。尽管如此,所有这些模型的 F N R FNR FNR始终远高于其 F P R FPR FPR。
上述启用SySeVR的模型采用 w o r d 2 v e c word2vec word2vec来生成向量。为了看看 w o r d 2 v e c word2vec word2vec是否可以用更简单的向量表示代替,比如标记频率,作者使用单词袋将SeVCs编码为固定长度的向量。有了这种向量表示后,使用两个浅层模型(即LR和MLP)和两个深层神经网络(即CNN和BGRU)进行了实验。实验结果如表4所示,为了将单词袋和 w o r d 2 v e c word2vec word2vec进行对比,可以将表3(使用 w o r d 2 v e c word2vec word2vec)和表4(使用单词袋)的实验结果数据进行对比。
表4 启用SySeVR的模型且使用从单词袋导出的向量的有效性(度量单位:%)
结论3:使用分布式表示(如 w o r d 2 v e c word2vec word2vec)来捕获上下文信息对SySeVR很重要。特别是,以标记频率为中心的表示是不够的。所以本文使用 w o r d 2 v e c word2vec word2vec来生成实验向量。
为了解释BGRU的有效性,可以看图6的结构。对于每个SeVC和每个时间步,在激活层有一个输出(属于[0,1])。BGRU的输出是激活层最后一个时间步的输出,这个输出越接近1,SeVC越有可能被归类为易受攻击。对于SeVC的分类,需要识别在确定其分类中起关键作用的标记(即表示它们的符号),这也是解释BGRU有效性的关键一步。这可以通过观察双标记时的步骤 ( t ′ , t ′ + 1 ) \left(t^{\prime}, t^{\prime}+1\right) (t′,t′+1)。如果激活层输出对应的标记时间步 t ′ + 1 t^{\prime}+1 t′+1明显(如0.6,对比小的)大于相对应的激活层输出时间步 t ′ t^{\prime} t′的标记,标记在时间步 t ′ + 1 t^{\prime}+1 t′+1中扮演着一个关键的角色在分类SeVC是易受攻击的(相应地,不是易受攻击的)。
图6 BGRU的结构
结论4:如果一个语法元素(例如,token)出现在易受攻击的(相对应,非易受攻击的)的SeVCs比出现在非易受攻击的SeVCs(相对应,易受攻击的)的出现频率更高。那么该语法元素可能会导致假阳性(相对应,假阴性);这意味着语法元素的出现频率很重要。
3.5.3 回答RQ3的实验
为了对比由数据依赖引起的语义信息与由数据依赖和控制依赖引起的语义信息的有效性,分别在上面提到的8个模型中进行实验,实验结果如表5所示:
表5 由数据依赖(简称DD)引起的语义信息有效性与由数据依赖和控制依赖(简称DDCD)引起的语义信息有效性的对比(度量单位:%)
结论5:能够容纳更多语义信息(即控制依赖和数据依赖)的模型能够获得更高的漏洞检测能力。
3.5.4 回答RQ4的实验
为了验证SySeVR框架对比其他产品和漏洞检测系统的有效性,作者从训练程序中提取了4种SyVCs,同时考虑由数据依赖和控制依赖引起的语义信息。将本文研究中最有效的模型(BGRU)与以下几种产品和漏洞检测系统进行比较:
- 商业静态漏洞检测工具Checkmarx
- 开源静态分析工具Flawfinder
- 开源静态分析工具RATS
- 最先进的系统VUDDY
- VulDeePecker
选取这些产品和漏洞检测系统的原因如下:
- 这些工具可以证明代表了最先进的漏洞检测静态分析
- 它们被广泛用于检测C/C++源代码中的漏洞
- 直接对源代码进行操作(即不需要编译源代码)
- 可以使用它们
实验结果如表6所示:
表6 比较SySeVR框架中的BGRU和最先进的漏洞检测器(度量单位:%)
结论6:启用SySeVR的BGRU比最先进的漏洞检测方法更有效。
3.5.5 BGRU在软件产品漏洞检测中的应用
为了展示SySeVR在检测真实软件产品中的软件漏洞方面的有用性,作者应用SySeVR-BGRU来检测4种软件产品中的漏洞:
- Libav
- Seamonkey
- Thunderbird
- Xen
其中需要注意的是,对于每个产品,作者将启用SySeVR的BGRU应用到它的20个版本中,这样就可以知道在发布新版本时,供应商是否已经“悄悄地”修补了一些漏洞。检测结果如表7所示,共检测到15个没有在NVD中报告的漏洞。其中,7个是未知的(即它们在这些产品中的存在直到现在还不知道),并且确实与表7中提到的CVE标识符(CVE IDs)相似。其他8个漏洞在发布相关产品的新版本时已被供应商“悄悄地”修补。
表7 这15个被BGRU检测到但NVD没有报告的漏洞,包括7个未知的漏洞和8个已经被“悄悄地”修补的漏洞。
4 局限性
作者指出了本文所研究内容的一些局限性:
- 目前本框架只专注于检测C/C++程序源代码中的漏洞,未来应调整框架以适应其他编程语言或可执行程序
- 目前的研究只聚焦了4种漏洞语法特征,未来的研究应该识别更完整的漏洞语法特征
- 可以改进生成SyVCs和SeVCs的算法,以容纳更多用于漏洞检测的语法/语义信息
- 目前的实验使用单一模型来检测多种类型的漏洞,未来应该研究单一模型与分别定制的模型在检测多种类型的漏洞方面谁更有效
- 目前在切片级别(语义上相关的多行代码)检测漏洞,未来的研究应该聚焦于如何定义为包含漏洞的代码行
- 目前通过手动检测生成基本真实标签,存在错误标记的可能,未来应该研究更有效的自动标记方法(联合训练的思想)
- 目前虽然已经对神经网络检测漏洞有了一定的可解释性,但是应该需要更有力的可解释性
5 相关工作
5.1 与漏洞检测相关的研究
基于源代码的静态漏洞检测有两种方法:
5.2 与深度学习相关的研究
深度学习早已被应用在程序分析领域,总结如下:
- CNN已用于软件缺陷预测和定位源代码中的bug
- DBN用于软件缺陷预测
- RNN已用于漏洞检测软件溯源、代码克隆检测和二进制文件中的识别功能
本文所研究的内容(SySeVR)是第一个使用深度学习检测漏洞的系统框架。
6 结论
本文所研究内容做出的主要贡献包括:
- 提出了使用深度学习检测漏洞的SySeVR框架
- 基于收集的大量漏洞数据集,证明了此框架的有效性
- 对深度学习在漏洞检测中有效性的解释
- 检测到15个没有在NVD中报告的漏洞
未来的工作应该聚焦于:
- 解决第4节中讨论的局限性
- 研究代码复制对启用SySeVR的模型的影响
总结
本文所提出的方法主要聚焦于如何利用基于语法、基于语义和矢量表示(SySeVR)的技术来提高深度学习在源码漏洞检测方面的有效性和可解释性问题。基本思路是首先提取SyVCs,然后再将包含语法信息的SyVCs转换为包含语义信息的SeVCs。当然,其中有许多定义,这些定义保证了在信息转换过程中的有效性。之后再将SeVCs编码为神经网络的输入向量,还需要注意要标记SeVCs和对应的向量,也就是“打标签”,训练好神经网络模型后,就可以使用此模型进行源码漏洞检测。
本文所提出的方法优点包括:
- 对深度学习在漏洞检测中有效性的解释
- 对比其他漏洞检测框架/系统的有效性有着明显的提高
- SySeVR-BLSTM可以检测多种类型的漏洞
- 启用SySeVR的漏洞检测框架/系统的有效性都有一定程度的提高
- 能够容纳更多语义信息(即控制依赖和数据依赖)
本文所提出的方法缺点包括:
- 目前本框架只专注于检测C/C++程序源代码中的漏洞
- 目前的研究只聚焦了4种漏洞语法特征
- 目前容纳的用于漏洞检测的语法/语义信息不够多
- 目前的实验仅仅使用单一模型来检测多种类型的漏洞
- 目前在仅仅切片级别(语义上相关的多行代码)检测漏洞
- 目前通过手动检测生成基本真实标签,存在错误标记的可能
- 目前对神经网络检测漏洞的可解释性不强
- 目前并没有考虑代码复制对启用SySeVR的模型的影响