2. 信息网络安全公安部重点实验室, 上海 201204
2. Key Laboratory of Information Network Security of Ministry of Public Security, Shanghai 201204, China
目前, 计算机与信息技术在各行业中的应用越来越多, 软件作为计算机系统功能实现的重要载体, 为用户提供了丰富的信息化体验。然而, 由软件引发的信息安全事件层出不穷, 引发了人们对信息基础设施的关注。软件的高复杂度特征导致软件漏洞成为信息系统安全的主要威胁[1]。近年来, 一些软件漏洞检测方法相继被提出, 但是软件漏洞仍未被彻底消除, 且随着软件数量的剧增, 漏洞出现得更加频繁。
传统的漏洞挖掘技术存在代码检查速度受限, 无法实现自动化、批量化的检测, 难以满足当前互联网发展需求等问题, 同时, 代码检查耦合度较高, 从漏洞的发现、验证到利用, 整个过程主要依赖安全工程师的经验, 漏洞挖掘无法实现模块化。此外, 已有静态检测方法和一些商业工具在代码检测的准确度和误报率方面也存在一定的局限性。在工程应用中, 目前较成熟的检测工具大多基于固定的模式匹配, 无法深入理解代码语义, 难以做到智能化的漏洞检测。
本文利用人工智能技术[2]并借助深度学习算法[3]来实现智能化、高效率和大批量的代码漏洞检测。研究软件漏洞触发机制并利用路径进行程序切片, 形成分类漏洞样本集, 通过深度学习模型训练提取软件的漏洞特征, 建立基于Bi-LSTM的相似性比对模型, 从而判定待测程序是否存在漏洞。
1 背景知识 1.1 漏洞的定义漏洞是指存在于一个系统内的弱点或缺陷, 这个弱点或缺陷导致系统对某一特定的威胁攻击或危险事件具有敏感性[4]。软件漏洞通常是由软件设计时的逻辑缺陷(如数值赋值错误)或开发人员不严谨的编码(如调用不安全的函数)所造成。攻击者利用漏洞植入恶意代码, 实现绕过安全监测、提升权限、窃取数据等恶意行为。
1.2 静态漏洞检测静态漏洞检测是基于源代码的漏洞挖掘方法[5], 通常适用于开源的软件。与动态检测不同, 静态检测通常不需要对程序源代码进行编译, 而是通过语法分析及语义分析, 结合控制流信息、数据流信息构建代码模型, 从而判别代码是否存在漏洞。因为仅对静态代码进行分析, 基于源代码的静态漏洞挖掘的准确率远低于动态检测, 其优点在于不需要复杂的代码编译环境, 效率高于动态检测, 且基于源代码的静态漏洞挖掘方法能够完整地进行分析代码程序, 这能够解决动态检测无法完全覆盖所有代码的问题。
编程语言种类较多, 针对每种语言都有相应的源代码分析工具。例如, Flawfinder[6]是一款免费、开源的针对C/C++代码的静态检测工具, 其针对每一种漏洞都内嵌了特征库, 通过匹配这些特征库可以发现潜在威胁, 但是该方法的误报率较高。目前, 在工业界主要使用商业软件Coverity[7]、Checkmarx[8]等, 这些工具依据数据流进行分析, 技术成熟且支持多种检测语言, 因此得到了广泛应用。
1.3 基于代码特征的漏洞检测基于代码特征的漏洞检测不属于特定的静态或动态检测, 其在静态或动态分析过程中提取代码特征信息, 然后构建代码特征模型, 在此基础上, 运用机器学习、深度学习等技术进行检测。文献[9]提出了一种将静动态特征与机器学习相结合的漏洞挖掘方法, 开发了一种VDISCOVER工具, 以检测实际环境中的漏洞。文献[10]提出一种基于抽象语法树的函数级漏洞检测方案, 该方案将抽象语法树的文本与随机森林分类算法相结合, 从而提高检测的准确率。文献[11]提出基于神经网络的图嵌入算法, 以判断二进制代码的相似性。文献[12]建立基于深度学习的漏洞检测模型VulDeePecker, 其基于敏感函数进行代码切片后运用递归神经网络模型对文本实现分类。
2 静态漏洞检测系统 2.1 系统模型基于代码相似性的漏洞检测模型如图 1所示。在训练阶段, 首先根据敏感函数对原样本代码进行切片, 得到代码片段; 然后对代码片段进行数据清理, 统一格式并进行变量名替换; 随后对代码块进行分词处理, 得到单词并储存于字典中, 对每个单词进行word2vec训练, 将单词转化为向量; 最后运用Bi-LSTM网络对向量化的代码提取特征向量。以上步骤均为运用深度学习技术训练源代码的常规过程, 本文的改进在于提出了相似性判别方法。相似性模型是将待测代码与已知含有漏洞的代码进行相似性判断, 通过判断待测代码的特征向量是否与漏洞代码的特征向量相似来检测漏洞, 这种网络模型也称为孪生神经网络。在训练阶段, 由于已知代码是否包含漏洞, 记包含漏洞的代码为正样本, 不包含漏洞的代码为负样本, 认为2个正样本或2个负样本为相似, 标记为1, 一正一负为不相似, 标记为0, 依此进行有监督的训练。在测试阶段, 先进行和训练阶段相同的前期处理, 包括代码切片、分词处理和向量化, 然后将待测样本与漏洞模板作为成对输入并进行比对, 通过网络模型输出相似或不相似结果。
![]() |
Download:
|
图 1 漏洞检测模型总体结构 |
进行代码切片的原因主要有以下2点:
1) 本文系统不仅要判定程序是否存在漏洞, 还要找出漏洞的位置。如果学习整个代码或者某个函数, 想要通过自动化检测来指出程序漏洞所在位置将十分困难, 不利于进行进一步检测验证。
2) 对于文本相似性深度学习系统而言, 需要尽可能减少无关代码的相似性比对, 这就需要将深度学习的输入简化为敏感函数相关代码, 以提高匹配的准确度。敏感函数的选取主要依据人工经验, 本文采用商业工具Checkmarx来定位敏感函数。
本文运用经典的基于程序依赖图可达性算法的切片方法[13]。程序依赖图是对控制流图和数据流图的进一步优化, 其能刻画出控制流和数据流间的依赖关系。控制依赖表示2个语句在程序流程上的依赖关系, 被依赖节点能够决定依赖节点是否执行程序。数据依赖表示程序中引用某个变量的语句对定义该变量的语句的依赖。依据以上2种关系可以构建出程序依赖图, 如图 2所示。
![]() |
Download:
|
图 2 代码切片示意图 |
数据清洗主要涉及对代码格式的统一、注释删除以及变量名替换。变量名称不会改变程序的执行逻辑, 对于神经网络而言, 过多的用户定义变量和函数会增加样本的信息量冗余, 且不利于相似性比对。因此, 变量统一化命名能够提高模型的准确度, 本文的实验结果也验证了这一点。此外, 多余的注释以及不规范的代码格式同样会对模型检测的准确度产生影响。
变量名替换的一般规则为:1)将自定义变量替换为VAR1、VAR2等; 2)将自定义的函数(非系统函数)命名为FUN1、FUN2等; 3)将自定义的类变换为CLASS1、CLASS2等。统一化命名会在很大程度上降低由用户定义引起的误判, 且在后续的向量化过程中减少词典的索引数目。
2.4 分词与词向量化程序语言与自然语言存在一定的相似性, 程序语言的上下文之间同样具有一定的关联性, 因此, 本文通过自然语言处理的方法来构建漏洞检测模型, 步骤如下:
1) 将代码进行分词操作形成一个词典, 每个词在词典中都对应一个word_index, 如strcpy(VAR1, VAR2)被拆分为‘strcpy’、‘(’、‘VAR1’、‘, ’、‘VAR2’及‘)’。
2) 在分词结束后, 将代码中的词替换为字典索引编号, 从而使代码转化为编号序列。为保证样本词长度的一致性, 需要进行长度补齐。本文单个代码片段的长度上限为200, 不足的补齐到200, 长度超过200的代码片段则直接舍弃。
3) 神经网络的输入是向量, 因此, 必须将词转化成多维向量, 仅通过编码(一维)将不足以表现特征。本文通过Gensim[14]库中的word2vec方法, 将词典中的每个词对应的向量形成词向量映射矩阵[15]。每个代码切片可以看成词的序列模型, 通过词向量映射矩阵, 每个代码切片即变成一个由词向量组成的序列。
一个代码片段的分词与词向量化过程示意图如图 3所示。
![]() |
Download:
|
图 3 代码替换示例 |
记包含漏洞的代码为正样本, 不包含漏洞的代码为负样本。从正样本与负样本中随机选择代码切片形成代码对。如果2个代码切片同属于正样本或同属于负样本, 则该代码对被视为相似的代码对(正样本代码对), 标记为1;反之, 如果2个代码切片一个属于负样本、另一个属于正样本, 则该代码对被视为不相似的代码对(负样本代码对), 标记为0。
2.6 Bi-LSTM相似性判别模型相似性判别模型结构如图 4所示。模型由1个词嵌入层、2个Bi-LSTM层[16]、1个concate层以及全连接层组成。词嵌入层将输入的代码填充为词向量; 2个Bi-LSTM层用以提取代码特征; concate层将2个Bi-LSTM层的输出连接在一起; 全连接层作为分类器。最后经过激活函数sigmoid将特征向量归约到最终的输出结果(0或1, 1表示是漏洞代码, 0表示不是漏洞代码)。在训练过程中, 设定值为0.1的Dropout[17]来防止过拟合, 并在每层加入Batch Normalization[18]以加速运算。损失函数运用binary_crossentropy, 优化方法采用Adam[19]。模型的输出经过反向传播来不断优化模型参数, 以逼近标签值。
![]() |
Download:
|
图 4 Bi-LSTM相似性判别模型结构 |
在检测过程中, 数据预处理和模型特征提取与训练过程类似, 区别在于检测过程的输出结果不直接与标签做比较。由于特定的2个代码即使属于相同的漏洞类型, 其表现形式也有可能不同, 在相似性判断时会出现偏差。因此, 本文引入漏洞模板的概念。从存在漏洞的代码样本中找出100个典型漏洞作为漏洞模板, 将这些漏洞模板记为A1, A2, …, A100, 需要检测的代码记为B, 相似性检测模型记为函数S, S(X1, X2)=1表示模型判断漏洞样本X1、X2相似, S(X1, X2)=0表示漏洞样本X1、X2不相似。定义待测代码与模板的相似度为Sim, Sim的值即为
本文从公开数据集SARD[20]中采集训练与测试数据, SARD共包含约17万条漏洞数据, 涵盖各个程序语言、漏洞类型。选取约2万条包含CWE-119漏洞的C/C++代码, 因为SARD数据集中每一个样本均包含正、负类, 所以共组成约4万条正、负类的样本数据集进行实验。
3.2 评估指标由于相似性判断是一个二分类问题,根据真实值和预测值间的关系,共有以下4种情况:1)实际为漏洞代码,预测也为漏洞代码,将数量统计为TP。
2) 实际为漏洞代码,但预测为无漏洞代码,将数量统计为FN。
3) 实际为无漏洞代码,但预测为漏洞代码,将数量统计为FP。
4) 实际为无漏洞代码,预测也为无漏洞代码,将数量统计为TN。
基于以上4种情况,本文使用召回率(True Positive Rate, TPR)、假阳性率(False Positive Rate, FPR)以及准确度(Accuracy)作为测试依据, 以评估漏洞检测模型的性能。TPR表示漏洞代码被检测出的概率, FPR表示正常代码被检测成漏洞的概率, Accuracy表示整个模型的准确率。三者的计算公式分别为:
$ {TPR = \frac{{TP}}{{TP + FN}}} $ | (1) |
$ {FPR = \frac{{FP}}{{FP + TN}}} $ | (2) |
$ {\mathit{Accuracy}{\rm{ }} = \frac{{TP + TN}}{{TP + FN + FP + TN}}} $ | (3) |
传统的文本特征提取运用LSTM, 但是代码间存在依赖关系, 这种依赖不但与后文有关, 还与前文有关, 因此, 双向LSTM更适用于学习代码。本文对比单向LSTM与双向LSTM网络模型的准确率, 层数为1~7, 测试结果如图 5所示。从图 5可以看出, 双向LSTM的准确率明显优于单向LSTM。单层LSTM网络模型过于简单, 难以充分学习到代码上下文的特征, 导致易出现局部最优的问题, 模型无法取得最佳分类效果。3层双向LSTM的准确率最高, 因此, 本文选择3层双向LSTM作为神经网络判别模型。
![]() |
Download:
|
图 5 2种网络模型的准确率对比 |
某一类漏洞可能有数种不同的表现形式, 以单一漏洞样本进行相似性比对, 对于其他形式的同类漏洞代码样本可能存在误判, 采用多种漏洞模板可以提高判断的准确率。由于存在模板数量和相似度2个变量, 本文首先假定2份样本的相似度Sim为模板数量的一半, 通过实验确定漏洞模板的数量为100左右会达到最佳效果。在大于100以后, 继续增大模板数量, 准确率虽然会有少量提升, 但是提升效果不明显。综合考虑准确率和系统运行效率, 本次实验确定模板数量为100。检测准确率与模板数量间的关系如图 6所示。
![]() |
Download:
|
图 6 检测准确率与模板数量间的关系 |
在模板数量确定为100后,需要确定一个阈值,当待测代码与漏洞模板相似匹配成功的数目为该值时,判定该待测代码为漏洞代码。阈值选择与TPR、FPR及Accuracy的关系如图 7所示。当阈值较小时, 只要待测代码与漏洞模板有一点相似, 就会被判定为漏洞, 因此, 召回率非常高, 漏洞代码很容易被找到, 产生的后果是会有很多误报。相反, 当阈值较大时, 误报率接近于0, 因为几乎没有漏洞代码会与漏洞模板全部都相似, 判定为正样本的几乎一定都是漏洞, 这样产生的后果是会漏报许多漏洞, 召回率非常低。从图 7可以看出, 阈值选取为40~50比较合适, 本文最终选取阈值为40。
![]() |
Download:
|
图 7 阈值与TPR、FPR及Accuracy间的关系 |
本次实验将相似性判别模型和直接判别模型进行对比。直接判别模型在代码特征的提取上与相似性判别模型一致, 区别在于其不会进行相似性匹配, 即不会进行concate操作, Bi-LSTM的输出直接进入全连接层进行分类, 这种做法与文献[8]相同。在相似性判别实验中, 随机选取100个样本作为漏洞模板, 共循环5次后取平均值, 以消除随机选取漏洞模板造成的误差, 实验结果如图 8所示。从图 8可以看出, 相似性判别模型的准确率达到89.05 %, 相较于直接判别模型提升了约4%, 且误报率大幅下降。
![]() |
Download:
|
图 8 直接判别模型与相似性判别模型性能对比 |
将本文相似性检测模型与商业静态检测模型Checkmarx[8]、Flawfinder[6]以及VulDeePecker[12]进行对比, 结果如表 1所示。
![]() |
下载CSV 表 1 4种模型性能对比结果 |
从表 1可以看出, 相对Checkmarx和Flawfinder, 基于深度学习的检测模型具有明显的性能优势。VulDeePecker和本文模型均基于深度学习技术, 区别是VulDeePecker只是单一的检测模型, 而本文将2个检测模型相结合后运用判别相似性的方式进行检测。相似性模型虽然牺牲了少量召回率, 但是大幅降低了误报率。
4 结束语针对静态漏洞检测误报率较高的问题, 本文建立一种基于文本相似性的漏洞检测模型。该模型结合深度学习的思想, 大幅提升了数据处理的速度, 在准确率上相比基于语义分析和基于语法分析的方法有较大提升。静态漏洞检测在整个漏洞挖掘过程中是一个比较初步的检测步骤, 其主要作用是筛选可疑点, 但不能对该点的可用性做出明确判断, 因此, 下一步将通过模糊测试等方式对可疑点进行可用性验证。
[1] |
LIU Jian, SU Purui, YANG Min, et al. Software and cyber security-a survey[J]. Journal of Software, 2018, 29(1): 42-68. (in Chinese) 刘剑, 苏璞睿, 杨珉, 等. 软件与网络安全研究综述[J]. 软件学报, 2018, 29(1): 42-68. |
[2] |
YU Zhuliang. Review of progress on artificial intelligence[J]. Journal of Nanjing University of Information Science and Technology, 2017, 9(3): 297-304. (in Chinese) 俞祝良. 人工智能技术发展概述[J]. 南京信息工程大学学报(自然科学版), 2017, 9(3): 297-304. |
[3] |
LECUN Y, BENGIO Y, HINTON G. Deep learning[J]. Nature, 2015, 521(7553): 436-444. DOI:10.1038/nature14539 |
[4] |
SONG Chaochen, HUANG Junqiang, Wang Dameng, et al. A survey on detecting techniques of computer security vulnerability[J]. Netinfo Security, 2012(1): 77-79. (in Chinese) 宋超臣, 黄俊强, 王大萌, 等. 计算机安全漏洞检测技术综述[J]. 信息网络安全, 2012(1): 77-79. DOI:10.3969/j.issn.1671-1122.2012.01.021 |
[5] |
ZOU Quanchen, ZHANG Tao, WU Runpu, et al. From automation to intelligence:progress in software vulnerability mining technology[J]. Journal of Tsinghua University (Natural Science Edition), 2018, 58(12): 1079-1094. (in Chinese) 邹权臣, 张涛, 吴润浦, 等. 从自动化到智能化:软件漏洞挖掘技术进展[J]. 清华大学学报(自然科学版), 2018, 58(12): 1079-1094. |
[6] |
Flawfinder[EB/OL].[2018-11-02].https://dwheeler.com/flawfinder/.
|
[7] |
Coverity[EB/OL].[2018-11-02].https://scan.coverity.com/.
|
[8] |
Checkmarx[EB/OL].[2018-11-02].https://www.checkmarx.com/.
|
[9] |
GRIECO G, GRINBLAT G L, UZAL L, et al. Toward large-scale vulnerability discovery using machine learning[C]//Proceedings of ACM Conference on Data and Application Security and Privacy. New York, USA: ACM Press, 2016: 85-96.
|
[10] |
LIN Guanjun, ZHANG Jun, LUO Wei, et al. POSTER: vulnerability discovery with function representation learning from unlabeled projects[C]//Proceedings of ACM SIGSAC Conference. New York, USA: ACM Press, 2017: 2539-2541.
|
[11] |
XU Xiaojun, LIU Chang, FENG Qian, et al. Neural network-based graph embedding for cross-platform binary code similarity detection[C]//Proceedings of 2017 ACM SIGSAC Conference on Computer and Communications Security. New York, USA: ACM Press, 2017: 363-376.
|
[12] |
LI Zhen, ZOU Deqing, XU Shouhuai, et al. VulDeePecker: a deep learning-based system for vulnerability detection[EB/OL].[2018-11-02].https://arxiv.org/pdf/1801.01681.pdf.
|
[13] |
ZHANG Yanmei. Research on testing technology of object-oriented programs based on dependency analysis[D].Xuzhou: China University of Mining and Technology, 2012.(in Chinese) 张艳梅.基于依赖性分析的面向对象程序测试技术研究[D].徐州: 中国矿业大学, 2012. |
[14] |
Gensim[EB/OL].[2018-11-02].https://radimrehurek.com/gensim/.
|
[15] |
MIKOLOV T, CHEN Kai, CORRADO G, et al. Efficient estimation of word representations in vector space[EB/OL].[2018-11-02].https://arxiv.org/abs/1301.3781.
|
[16] |
GRAVES A, JAITLY N, MOHAMED A R. Hybrid speech recognition with deep bidirectional LSTM[C]//Proceedings of 2013 IEEE Workshop on Automatic Speech Recognition and Understanding. Washington D. C., USA: IEEE Press, 2014: 273-278.
|
[17] |
HINTON G E, SRIVASTAVA N, KRIZHEVSKY A, et al. Improving neural networks by preventing co-adaptation of feature detectors[EB/OL].[2018-11-02].https://arxiv.org/pdf/1207.0580.pdf.
|
[18] |
IOFFE S, SZEGEDY C. Batch normalization: accelerating deep network training by reducing internal covariate shift[EB/OL].[2018-11-02].https://arxiv.org/pdf/1502.03167.pdf.
|
[19] |
KINGMA D P, BA J. Adam: a method for stochastic optimization[EB/OL].[2018-11-02].https://arxiv.org/pdf/1412.6980.pdf.
|
[20] |
SARD manual[EB/OL].[2018-11-02].https://samate.nist.gov/index.php/SARD.html.
|