论文: A Deep Learning-Based System for Vulnerability Detection
发表于 NDSS 2018,作者是 Zhen Li , Deqing Zou , Shouhuai Xu, Xinyu Ou, Hai Jin, Sujuan Wang, Zhijun Deng 和 Yuyi Zhong。
一、主要内容
作者首次将深度学习技术应用到漏洞检测领域,这里关键的技术难点在于如何将漏洞映射为向量,因为对于深度学习来说,能够处理的输入就是向量,所以需要一些指导性原则,下面会详细说明。基于这作者设计了评估系统 VulDeePecker,作者为深度学习方法提供了最初始的漏洞数据集,实验结果表明:与其他方法相比,系统能够实现更少的误报,将系统用于 Xen,Seamonkey 和 Libav 这3个软件产品检测到了4个未报告的漏洞。
现有漏洞检测缺陷:
- 现有的漏洞检测解决方案依赖于专家知识来定义规则。
- 会出现很高的漏报率,也就是会漏掉很多漏洞。
作者 Contribution:
- 开始利用深度学习进行漏洞检测的研究。
- 介绍了一种基于深度学习的漏洞检测系统的设计与实现。
- 提供了第一个用于评估系统 VulDeePecker 和其他基于深度学习的漏洞检测系统的数据集。
二、指导性原则
作者提出使用深度学习检测漏洞,这些原则旨在回答以下三个问题:
1. 如何表示基于深度学习的漏洞检测程序?
由于深度学习或神经网络以向量作为输入,需要将程序表示为具有语义意义的向量,即需要将程序编码成向量,这些向量是深度学习所需要的输入。
指导原则1:程序可以首先转换成某种中间表示,称为 code gadget。
2. 什么是合适的粒度?
由于不仅需要检测程序是否易受攻击,而且还需要确定漏洞的位置,因此需要更细的粒度来进行基于深度学习的漏洞检测。这意味着漏洞检测不应该在程序或函数级别进行,这是非常粗粒度的。
指导原则2:为了帮助确定漏洞的位置,程序应该以比将程序或功能视为一个单元更精细的方式表示。code gadget 适合原则2。
3. 如何选择神经网络?
指导原则3:由于一行代码是否有漏洞取决于上下文,故能够处理上下文的神经网络比较适用于漏洞检测。作者选择的是 BiLSTM,也就是双向长短时记忆网络。神经网络图如下:
三、VulDeePecker 的设计
作者目标是设计一个漏洞检测系统,可以实现自动判断源代码中给定的程序是否易受攻击,并且还可以自动判断漏洞的位置。
code gadget
定义:code gadget 是由许多程序语句组成的(例如:代码行),它们在数据依赖关系或控制关系方面在语义上彼此相关。
为了生成 code gadget,作者提出了关键点的启发式概念。例如:对于不正确使用 API 引起的漏洞,关键点是 API 调用;对于不正确使用数组引起的漏洞,关键点是数组。还需要注意:一类漏洞可能有多种关键点,多种类型的漏洞也存在相同的关键点。
VulDeePecker 系统
系统有两个部分组成:训练阶段和预测阶段。
1. 训练阶段:4个步骤
Step 1:提取库/API函数调用和相关的的程序片段
1.1 从训练程序中库/API函数的调用,同时注意 VulDeePecker 有关库/API函数调用的关键点。
1.2 为在步骤1.1中提取的库/API函数调用的每个参数(或者变量)提取一个或多个程序片段。
例子如下:
首先将库/API函数分为后向和前后,区分依据是是否接收外部输入。前向代表有命令行,套接字和文件,它们都是外部输入,然后向前找到相应的代码行。后向如上图的 strcpy 函数,它不接受外部输入,所以后向考虑,找到传入到这个函数参数有关的代码行。
图中显示了一个包含库函数调用 strcpy 的示例程序,它有两个参数 buf 和 str。strcpy 是一个后向库函数调用,针对每一个参数,生成一个后向切片。对于参数 buf,切片包含三条语句,即程序的第4,5,9行,它们属于用户自定义的函数test。对于参数 str,切片包含六条语句,即程序的第13,15,18,19,2,9行,前四行属于用户自定义的函数 test,后两行属于用户定义的函数 main。
Step 2:生成训练程序的 code gadget 及其标定好的真实数据
2.1 将步骤2.2中获得的程序片段组装为 code gadget,每一个库/API函数调用对应一个 code gadget。code gadget 不一定对应某些连续的代码行,相反,它是由多行语义相关的代码组成。
例子如上图:
在图中所示的示例中,有三个语句(4,5,9)属于用户定义函数 test 与参数 buf 对应的程序切片,有两条语句(2,9)属于用户定义函数 test 与参数 str 对应的程序切片。因为这两个切片相关于同一个函数 test,所以需要将它们组装成一个单独的块。通过在函数内依次出现的先后顺序,形成2->4->5->9->9的顺序,第9行重复,最终获得关于函数 test 的一块组装语句2->4->5->9。
其次,将属于不同用户定义函数的语句组成一个 code gadget。如果这些用户定义函数的两段语句之间已经存在一个顺序,则保留该顺序;否则,使用随机顺序。
2.2 对 code gadget 标记真实数据。
Step 3:将 code gadget 转换为向量表示
3.1 将 code gadget 转换为特定的符号表示。这个步骤的目的在于保存一些训练程序的语义信息。例子如下:
这部分的工作如上图所示:
1)删除非ASCII字符和注释,因为它们与漏洞无关。
2)以一对一的方式将用户定义的变量映射到符号名,比如“VAR1”,“VAR2”,同时注意到当多个变量映射到同一个符号名称上时,即它们出现在不同的 code 中。
3)以一对一的方式将用户定义的函数映射到符号名,比如“FUN1”,“FUN2”,同时注意到当多个函数映射到同一个符号名称上时,即它们出现在不同的代码小部件中。
3.2 对3.1步骤中的符号表示的 code gadget 进行编码为向量,这向量作为训练BLSTM神经网络的输入。例子如下:
将这些 token 转成向量,使用 word2vec 词向量的方式。由于 LSTM 接收等长输入,所以需要固定长度,有以下方案:
1)向量比 T 短时,如果 code gadget 是从后切片或者多种后切片组合生成的,我们就在向前开始的地方填充多个0;否则,在向量结束的地方填充多个0。
2)向量比 T 长时,如果 code gadget 是从后切片或者多种后切片组合生成的,我们就删除向量开始的多余部分;否则,删除向量结束的多余部分。
确保从后向切片生成的每个代码小部件的最后一条语句是库/API函数调用,二从前向切片生成的每个代码小部件的最开始一条语句是库/API函数调用。
Step 4:训练 BiLSTM 神经网络
不过多诉述,具体可看论文。
四、实验部分
收集数据
漏洞数据库来源主要是:包含生产软件漏洞的NVD[10]和包含生成,合成和学术安全漏洞或漏洞的SARD项目。在本篇文献中,关注两种类型的漏洞:缓冲区错误(CWE-119)和资源管理错误(CWE-399),其中每一个都有许多子类型。NVD:520缓冲区漏洞,320个资源管理错误漏洞。SARD:8112个缓冲区漏洞,1729个资源管理错误漏洞。
神经网络的训练
-
提取函数调用和相应的程序片段
从程序中提取C/C++库/API函数调用,有6045个C/C++库/API函数调用,包括标准库函数调用[1],基本的Windows API和Linux内核API函数调用[9],[13]。总共从程序中提取了56902个库/API函数调用,包括7255个正向函数调用和49647个反向函数调用。 -
生成 code gadgets
代码小部件由程序片段生成,利用训练程序的程序片段生成的48744个代码小部件和目标程序的程序片段生成的12894个代码小部件获得了一个有关61638个代码小部件的的数据库(Code Gadget Database)。基于效率的考虑,使用 CGD (前面提到的代码小部件的数据库)总结出了以下6个数据集:
- BE-ALL:CGD的子集,针对缓冲区错误漏洞(CWE-119)和所有的库/API函数调用。
- RM-ALL:CGD的子集,针对资源管理错误漏洞(CWE-399)和所有的库/API函数调用。
- HY-ALL:和CGD一样,针对前面两种错误漏洞和所有的库/API函数调用。
- BE-SEL:CGD的子集,针对缓冲区错误漏洞(CWE-119)和手动选择的函数调用(而不是所有的函数调用)。
- RM-SEL:CGD的子集,针对资源管理错误漏洞(CWE-399)和手动选择的函数调用(而不是所有的函数调用)。
- HY-SEL:和CGD一样,针对前面两种错误漏洞和手动选择的函数调用(而不是所有的函数调用)。
- 调参过程:
code gadgets 的向量表示的标志数目(tokens)设置为50个,dropout设置为0.5,batch size设置为64,epochs设置为4,minibatch 随机梯度下降法,选择300个隐藏节点,采用默认的学习率1.0来进行训练。
实验结果
- 为了测试 VulDeePecker 是否可以应用于多种类型的漏洞,作者在三个数据集上进行了实验:BE-ALL,RM-ALL,HY-ALL,这分别导致了三种神经网络,其有效性如下表所示:
- 为了比较 VulDeePecker 与其他基于模式和基于代码相似性的漏洞检测系统的有效性:
- 结论
- VulDeePecker 可以同时检测多种类型的漏洞,但是其有效性取决于与漏洞相关的库/API函数调用的数量(即越少越好)。
- 可以利用人工专业知识来选择库/API函数调用来提高 VulDeePecker 的有效性,尤其是 F1-measure 中的整体效率。
- 利用数据流分析的优势基于深度学习的漏洞检测系统会更加有效。
- VulDeePecker 比基于代码相似性的漏洞检测系统更有效,后者无法检测出不是由于代码克隆引起的漏洞,因此,经常导致漏报,然而 VulDeePecker 的高效性体现在对大量的数据很敏感,这是一种深度学习的固有性质。
网友评论