Software Vulnerability Analysis and Discovery Using Machine-Learning and Data-Mining Techniques

题目: Software Vulnerability Analysis and Discovery Using Machine-Learning and Data-Mining Techniques: A Survey
作者: Seyed Mohammad Ghaffarian, hamid Reza Shahriari
单位: Amirkabir University of Technology
出版: ACM Computing Surveys


我们将以往用机器学习或数据挖掘进行软件漏洞分析的工作分为以下四类:
- 基于软件度量元的漏洞预测模型:多是利用机器学习中的监督学习方法,在软件度量元特征的基础上构建预测模型,用来评估软件部件的漏洞现状。
- 异常检测方法:利用无监督学习方法自动地从软件源码中抽取出一个正态模型或挖掘规则,然后将其中检测到的异常行为判别为漏洞。
- 漏洞代码模式识别:利用机器学习(多数为监督学习)方法从大量漏洞代码样本中抽取有漏洞代码的模式,然后利用模式匹配技术从软件源码中检测并定位漏洞。
- 其他方法:不属于以上三种,也难以自成一类的。

以下分别说明。

基于软件度量元的漏洞预测

这种方法的主要思想借用于软件工程领域软件质量和可靠性确定方向,软件质量和可靠性确定主要应用于软件测试和验证资源受限,需要更加高效的测试规划的场景。基于软件度量元的漏洞预测因类似的目的被提出,模型同样由软件度量元构建,而不包含程序分析方法。

近期工作总结

Zimmermann 2010利用缺陷预测领域的度量元构建分类模型,预测一个商业产品(Windows Vista)的二进制模块中的漏洞。它们首先计算了度量元与每个模块中漏洞数量的相关性,结果证明相关性很大。作者用了5种度量元(代码修改,复杂度,覆盖率,依赖,组织[organizational]),利用二分类逻辑回归模型,得到精确度67%,召回率21%。
Meneely 2010研究了开发者活动度量元与漏洞间的联系。开发者活动度量元包括:修改一个源码文件的开发者数量,一个文件的commit数量,贡献网络中路径数。用这些作为特征构建贝叶斯网络,得到的精度度12%-29%,召回率32%-56%。
Doyle 2011利用2006到2008年间最广泛使用的14个开源网络应用来研究度量元与漏洞间的关系,开源应用包括WordPress和Mediawiki等。作者利用静态分析工具得到了很多度量元,如静态分析漏洞密度,源码大小,圈复杂度,嵌套复杂度,还有另一位作者提出的Security Resources Indicator。作者自己检查了预测结果,发现误判率为18%,认为误判率可以接受。
Shin 2013研究基于复杂度和代码修改度量元的传统缺陷预测模型能否用来预测漏洞。作者在Mozilla Firefox上进行了实验,利用18个复杂度度量元,5个代码修改度量元,和缺陷历史度量元,尝试了多种分类模型,得到83%的召回率和11%的精确度。作者的另一个工作中调查了执行复杂度与软件漏洞的联系,得到67%-81%的召回率和8%-12%的精确度。
Shin 2011研究复杂度,代码修改,和开发者行为度量元与漏洞间的关系,选择了28个度量元进行实验,得到至少70%的召回率和至多25%的误判率,并且得出结论表征开发历史的度量元对漏洞的预测具有很强的指导性。
Moshtari 2013提出了以前工作的三个不足,并且提出了新的方法。作者提出了一个半自动的分析框架来检测软件漏洞,并且用它的输出作为漏洞信息替代了传统报告中的漏洞,这样做能够提供更多的有关漏洞的信息。除项目内的漏洞预测,作者还进行了跨项目的漏洞预测。结果显示针对Mozilla Firefox的预测结果召回率为90%,误报率为10%。
Meneely 2013从Apache HTTPD网络服务器的65个漏洞中手动找到了124个漏洞修复的commit进行研究,结果显示1)代码修改度量元与VCC的关联很大,2)影响很多开发者的commit更有可能是VCC,3)一个新的开发者提交的commit更有可能是VCC。
Bosu 2014从10个开源项目中分析了超过260,000个代码修改请求,得到了超过400个包含漏洞的代码修改。作者的目的是识别出有漏洞的代码修改。他们的发现包含1)经验较少的开发者做出的修改更有可能包含漏洞,2)修改的规模与包含漏洞的可能性有关,3)新文件比起修改后的文件包含漏洞的可能性更小。
Perl 2015作者构建了一个数据集,包含66个C/C++github程序中170,860条commit,和其中640条与漏洞有关的commit,并且与相关的CVE ID进行了关联。作者选择了代码修改和开发者行为度量元,以及Github元数据构建模型。在与静态分析工具FlawFinder进行对比时发现相同召回率(24%)情况下,FlawFinder的精确度只有1%,而VCCFinder精确度能达到60%。
Walden 2014将度量元特征构建的模型与文本挖掘技术进行对比。作者首先利用3个大型开源的PHP网络应用(Drupal, Moodle, PhpMyAdmin)构建了一个数据集,包含223个漏洞。利用12个代码复杂度度量元构建了预测模型,另外利用文本挖掘的方法构架了模型进行对比,结果显示文本挖掘方法更好并且差距较大,作者还进行了跨项目的实验,两种方法的实验结果都很差。
Morrison 2015复现了Zimmermann的方法,利用两个新发布的Windows操作系统进行实验,结果显示精确度低于50%,召回率低于20%。
Younis 2016试图识别出更加容易被利用的漏洞。为此作者从Linux内核和Apache HTTPD中收集了183个漏洞,包含了82个可被利用的漏洞,选择了8个度量元来衡量这些漏洞,并利用t检验来检查各个度量元的判别能力。作者利用随机森林和子集选择方法得到的最好F值为84%。

讨论

利用软件度量元预测漏洞的优点在于软件度量元在软件工程中是比较易得的。并且缺陷预测已经在一些软件项目中应用,构建漏洞预测模型不需要太多额外的工作。另外,漏洞预测系统的目的只是引导更好的测试规划和资源的分配。
以上工作的结果显示基于软件度量元的漏洞预测已经臻于成熟,以下是我们总结的一些未来的工作和挑战:
- 漏洞数据的少和稀疏是一个数据上的挑战,在数据挖掘和机器学习中叫做类不平衡问题。已经有一系列的工作用来解决这一问题,任何人在利用软件度量元进行漏洞预测时都不应忽略这一问题。
- Moshtari等人利用半自动框架来检测漏洞,以此收集漏洞信息作为数据集,这是一种有效的,可以进行深入研究的方法。
- 跨项目的漏洞预测问题目前鲜有人问津,因训练数据和测试数据的分布可能会有很大的差别。这一方面可以借鉴缺陷预测中引入的迁移学习思路。
- 多数工作效果很差,一个可能的结论是传统的软件度量元不适合软件漏洞的预测。因此设计专门针对安全的度量元,如Doyle等提出的Security Resources Indicator是一个可研究的点。
- 这一领域还未用到深度学习。

异常检测方法

异常检测指的是寻找不符合常态或有异常行为数据的问题,经常也称作anomalies或outliers。在软件质量保证领域,异常检测是为了通过检测不服从常规模式的API来检测软件中的缺陷,以及检测被忽视的条件和缺失的检查,检查可以分为两种1)API用法的检查,2)程序实现逻辑的检查。
异常检测中的重要环节是自动抽取正常的行为,换言之就是抽取常规,规则和模式,这些接下来被用作检测异常行为的基础。自动抽取正常行为这一环节如果由人手工进行会极大影响方法的效率,因为1)写规则是一件艰难的事,2)人犯的错误会带来不正确的规则,从而导致错误的结果。

以往工作总结

Engler 2001认为寻找程序错误的主要困难在于要知道系统必须遵守的规则有哪些。为此他们提出通过定制规则模板来抽取程序的规则。他们抽取了两种规则:must-beliefs和may-beliefs,must-beliefs是众所周知的编程规则。may-beliefs是一些代码特征认为是规则,但存在例外。评估阶段作者在Linux和OpenBSD中对规则模板进行了检查,在不同场景中误报率从4%到57%不等。
Livshits 2005实现了一个工具DynaMine,从版本历史中检查源码check-in,抽取制定应用的代码模式,基于关联度很高的方法调用。方法一开始对新增的方法调用的软件revision历史进行预处理,然后将这些信息存入数据库准备被挖掘。挖掘利用经典的Apriori算法,即利用一个item集合作为输入,然后输出出现频繁的item集合和item之间的强关联规则。作者还提出了一系列排名方法,来对挖掘出的模式进行排名。挖掘出的模式随即交给用户去确认。评估阶段在两个大型的Java项目上进行,挖掘出了56个之前没有被发现的漏洞模式。
Li 2005作者提出了一个叫做PR-Miner的方法来从大型源码中挖掘隐式编程规则。PR-Miner从解析和预处理源码开始,移除不需要的元素例如关键字,数值常量等,根据数据类型来重命名函数中的局部变量和结构体中的数据字段。 预处理后所有程序元素都转换为一个哈希值,函数由内部的一系列哈希值表示存入数据库。作者通过对数据库进行挖掘找出常出现在一起的程序元素,这些就叫做程序模式。作者利用一个高效的算法从程序模式中生成规则,规则用来检测对规则的违背。评估在三个大型工程上进行,结果显示PR-Miner检测出的60个对规则的违背中,误判率为73%-90%
Wasylkowski 2007提出挖掘程序源码中的方法调用序列。首先,对象使用模型被从Java字节码抽取出来,对每个方法使用过程间分析。随后方法调用的临时属性被从模型中挖掘出来。这些常见模式表示了常见的对象用法,作者利用它们来训练分类模型,来识别不常见的模式。评估阶段在5个项目中排名前77的不常见模式中检查出5个缺陷,5个code smell,27个后门。
Acharya 2007认为现有方法无法从API使用模式中抓住一些有用的顺序信息,因此他提出了一个自动抽取API“频率偏序”的方法。方法采取4个步骤:利用一个push-down模型检查方法来抽取与API有关的过程间的控制流敏感的静态trace,然后用一个算法来将trace分到不同的应用场景。第三步中用一种方法从各场景结合中挖掘出“频繁的闭合偏序(FCPO)”,FCPO不是一般模式,而只能应用于特定代码。为解决这一问题,一个叫Mine-Verify的算法被引入,利用两个随机切分的不相交的代码集合来对模式进行确认。评估阶段此框架用于72个UNIX windowing系统的客户端程序。对每个实验,36个客户端用来挖掘,而另外36个用作确认。作者没有给出全部结果而只是拿一个程序作例子。
Chang 2008强调被忽视的条件是一类重要的难以发现的缺陷。为此作者提出了一种将静态程序分析和数据挖掘结合的方法来挖掘代码基中的隐含条件规则,并从对规则的违背中检测neglected condition。首先,程序被表示为修改后的“过程依赖图(procedure dependence graph, PDG)”的集合,叫做“系统依赖图(system dependence graph, SDG)”,PDG中增加了“共享数据依赖边(shared data dependence edge, SDDE)”,用来连接在控制流路径中使用了同一变量定义的程序元素。潜在规则可以看成EPDG的子图。一个叫做“分层最大频率子图挖掘(HMFSM)”的算法被用来寻找recurring graph minor,在对有效规则进行抽取和确认之后,“近过渡闭包(NTC)”数据库被用来挖掘对规则的违背。评估阶段作者将此方法应用到了4个项目中,检测到的规则中只有少于25%的无效规则,在寻找规则实例时得到了100%的精确度,而违反规则的检测结果中有79%的误报。作者表示约有一半的误报是由语义上一致的语句被赋予不同标签造成的,并且为未来工作提出了几点建议。
Thummalapenta 2009提出了一个新颖的方法来减少程序规则自动挖掘中的误报。他们提出了“替代模式”的概念,替代模式中一个API调用的很多频繁模式都放在一起考虑。他们提出一种叫“Alattin”的方法,利用迭代挖掘的策略来挖掘平衡和不平衡的模式,同时能够检测neglected condition。首先Alattin从源码中抽取重用的API,将它们喂给一个搜索引擎来收集抽取频繁模式的数据库。然后对每个频繁模式,输入数据库被分为消极和积极两个数据库,消极数据库中存储所有不符合该模式的候选模式,积极的数据库存储所有服从的。再对消极数据库进行频繁样集挖掘,用来构建不平衡的替代模式。这些被挖掘出的模式随后就用来在调用点处检查对规则的违背。对检测被忽视的条件,Alattin抽取了所有API调用点附近的条件检查,由于每个模式可能会有多种替代,Alattin只有在一个调用点违反了所有模式时才会报告。评估阶段作者在6个Java库上进行实验,1小时内挖掘了144个模式,其中75个(83%)是规则,7个是有部分是规则,8个是误报。对规则违背的检测与同类方法相比在误报率上有28%的减小。
Gruska 2010提出了一种跨项目的异常检测,利用一个轻量的,语言独立的解析器来分析不同预言的程序(包括C, C++, Java, PHP),这种方法是基于程序结构和函数调用的,因此源码上的很多细节可以被忽略,解析器只需解析所选部分。得到的抽象表示用来建立函数的有限自动机模型,模型中的状态代表代码中的位置,转换代表函数调用。模型用来抽取制定函数中所有可能的函数调用序列及其相关信息,然后每个函数模型被转换为代表函数之间值流向的属性序列。在评估阶段,作者挖掘了超过6000个开源Linux项目,抽取了16000000个与正常API有关的序列属性。作者随机选取了20个项目,在其上应用了异常检测,从总共检测出的138个异常中选择前25%来进行人工检查,其中有4个是缺陷,7个代码异味,39个(78%)误报。
Yamaguchi 2013提出了一个叫Chucky的系统,用来检查源码中的检查丢失。Chucky将机器学习和静态代码分析结合起来。作者将安全检查分为两种:检查安全逻辑的实现(例如访问控制)和检查API的安全使用(例如检查缓冲区大小)。Chucky利用一个五步的过程,对每对事先选好的source和sink进行执行。首先对源码进行解析,然后基于函数中的相似API symbol执行邻居发现方法。第三,加入轻量的污点分析来得到那些与目标源和槽相关的检查。第四,所有函数和它们的邻居都被映射到向量空间。最后,计算映射后的向量的中心,然后进行异常检测。Chucky认出了评估集中很多的检查丢失,前10名的异常几乎要么存在缺陷要么是漏洞。作者还利用Chucky检测出了12个位置漏洞(例如zero-day)。

讨论

根据前面列举的工作,异常检测可以用来找到因API的不恰当使用造成的软件漏洞,也可以用来寻找因条件被忽视和检查丢失造成的逻辑漏洞。重要的是这一过程可以通过工具自动完成,而不需要人工制定安全规则或安全专家的参与。然后自动对软件缺陷和漏洞进行异常检测存在以下问题:
- 异常检测方法只适合于成熟的软件系统。它基于的假设是API的不恰当使用和检查丢失是较少发生的事件。
- 代码基中须有大量的条件检查和频繁的API使用。
- 异常检测方法通常无法确定缺陷或漏洞的类型。因为以上方法只能找到不符合任何常规规则或模式的代码。
- 以往工作的高误报率证明异常检测系统并不可靠,它的输出需要进行仔细的人工审查,这限制了系统的可用性。

上述问题不仅约束了缺陷和漏洞检测,也约束了其他领域的工作,例如网络入侵检测。可以很清楚地看到利用异常检测方法来进行漏洞检测还有很大的研究空间,以下是我们认为可行的一些未来工作:
- 一个一直流行的工作就是降低异常检测的误报率
- 在安全相关的方法中的问题就是无法分辨一个异常是否与安全相关(是否是漏洞)
- 图是一种能够对代码进行较丰富表示的结构,利用图挖掘和图匹配来进行异常检测是一个很值得研究的方向,同样需要降低误报率

漏洞代码模式识别

与异常检测相似,这一部分方法同样是从程序源码(或二进制机器码)中分析并抽取特征。两者的区别在于异常检测的目的是抽取常规的模式或规则,而这一部分工作目的是抽取漏洞代码的模式或规则。
此类工作的一般套路是收集一个很大的软件漏洞样本集,处理每个样本并抽取特征,然后利用机器学习(主要是监督学习)来自动学习一个识别漏洞模式的模型。不同的方法从程序源码中抽取了不同的特征,如传统的代码解析,静态数据流和控制流分析,动态分析,程序源码的文本挖掘等。

近期工作总结

Yamaguchi 2011, 2012提出一种辅助发现漏洞的方法,叫做vulnerability extrapolation,这项工作的动机是基于对一个重复场景的观察:安全专家的日常工作就是在同一个代码基的其他部分寻找与最近发现的漏洞相似的实例。为此作者提出了四个步骤:为每个函数抽取抽象语法树,利用词袋技术将语法树映射到向量空间,将每个函数表示成一个包含子树的向量,子树是用指示特定API symbol是否存在的向量来表示的。随后,潜在语义分析被用在了这个向量表示中,来识别频繁出现在代码基AST中的结构化模式。这一步骤是通过将所有函数的向量表示聚合成一个大的稀疏矩阵,然后应用矩阵奇异值分解(singular value decomposition, SVD)来进行的。评估阶段作者选择了四个开源项目:LibTIFF, Pidgin, FFmpeg和Asterisk。作者利用一些最新报告的漏洞作为种子,发现了几个zero-day漏洞。
Shar 2012, 2013基于PHP网络应用的数据流分析,提出了一系列的静态代码属性,用来预测SQL注入和跨站脚本攻击。一共20个静态代码属性,例如从不同来源输入数据的语句个数,数据数据类型,

待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值