【论文翻译】Software Vulnerability_Detection Using Deep Neural Networks_ A Survey

文章信息:
Software Vulnerability Detection Using Deep Neural Networks: A Survey(2020)
基于深度神经网络的软件漏洞检测综述

摘要

不断增加的安全漏洞披露已成为软件行业和网络安全领域的重要关注点,表明当前的漏洞检测方法有待进一步改进。开源软件社区的蓬勃发展使得大量的软件代码成为可能,这使得机器学习和数据挖掘技术能够利用软件代码中丰富的模式。特别是,最近深度学习在语音识别和机器翻译方面的突破性应用,展示了神经模型理解自然语言能力的巨大潜力。这促使软件工程和网络安全社区的研究人员将深度学习应用于学习和理解易受攻击的代码模式和表明易受攻击代码特征的语义。在本调查中,我们回顾了采用基于深度学习/神经网络的方法来检测软件漏洞的当前文献,旨在调查最先进的研究如何利用神经技术来学习和理解代码语义,以促进漏洞发现。我们还确定了这一新领域的挑战,并分享了我们对潜在研究方向的看法。

关键词:网络安全;深度神经网络(DNN);机器学习(ML);表示学习;软件漏洞。

1 简介

计算机系统构成了我们数字社会的基础,赋予了全世界的人们和企业权力。然而,软件中可利用的漏洞可能对计算机系统的安全运行构成潜在威胁,并每天影响数百万用户。五年前披露的“心脏出血”[1]和“Shellshock”[3]漏洞已经证明了这一点,2017年,Apache Struts漏洞导致1.43亿消费者的金融数据被泄露[5],[15],[125],[126]。
有效的攻击缓解解决方案之一是在部署前应用软件漏洞检测。作为漏洞检测基础的代码分析技术可以分为静态、动态和混合方法。静态技术,如基于规则/模板的分析[16],[29],[113],代码相似性检测[42],[45],以及符号执行[13],[83],[106],主要依赖于对源代码的分析,但经常会出现高误报[56]。动态分析包括模糊测试[81]、[103]和污迹分析[74]、[82],往往存在代码覆盖率低的问题。混合方法结合了静态和动态分析技术,旨在克服上述弱点。然而,它们也继承了它们的缺点,并且在实践中操作效率低下[119]。迄今为止,软件产品发布后披露的漏洞数量的迅速增加表明,当前的代码检查和安全技术软件质量检查在效率和有效性方面需要进一步改进[108]。
使用模式识别和机器学习(ML)的数据驱动漏洞发现为自动化和可能更有效的漏洞发现[21],[33],[63],[101]提供了替代解决方案。ML算法可以学习潜在的和抽象的易受攻击的代码模式,具有显著提高泛化水平的潜力。现有的基于ml的方法主要对源代码进行操作,从而提供更好的人类可读性。研究人员已经应用了基于源代码的特性,如导入(例如,头文件)、函数调用[73]、软件复杂性度量和代码更改[94]-[96]作为识别潜在易受攻击的文件或代码片段的指标。此外,从版本控制系统(如开发人员活动[66]和代码提交[79])中获得的特征和信息也被用于预测漏洞。
传统的机器学习技术在漏洞检测中的应用仍然需要专家来定义特征,这主要取决于人的经验、专业水平和领域知识的深度——[43],[56],[117]。特征工程过程可能很耗时,而且可能容易出错,而由此产生的手工制作的特征也可能是客观的和特定于任务的。新兴的深度学习技术为基于机器学习的漏洞检测领域提供了新的潜力。一方面,基于神经网络/深度学习的模型的分层结构有助于促进抽象和高度非线性模式的学习,能够捕获复杂数据的内在结构。另一方面,神经网络的使用允许自动提取特征,并具有多层抽象[53],并且可能具有改进的泛化水平[61],从而将专家从劳动密集型和可能容易出错的特征工程任务中解脱出来。此外,深度学习方法能够发现人类专家可能从未考虑过的潜在特征[89],这极大地扩展了特征搜索空间。因此,研究人员一直被激励着应用神经模型来学习易受攻击的代码模式,这些模式表明了应用程序中的潜在漏洞。
尽管在开发自动化漏洞检测解决方案方面已经投入了大量的研究工作,但人类智能在指导和/或补充开发/使用不同类型的工具和方法以辅助漏洞搜索过程方面仍然发挥着重要作用[108]。许多静态工具和基于机器学习的检测系统是基于知识渊博的安全专家/测试人员的经验开发的,以近似专家/测试人员如何搜索漏洞。例如,早期基于规则的静态代码分析工具是根据最佳编程实践提取规则模板的。对预定义规则的违反将会发出警报。基于机器学习的检测方法也严重依赖于从代码分析中提取的精心设计的特征集,例如,抽象语法树(ast)和控制流图(cfg)。从某种意义上说,特征工程过程反映了专家/测试人员认为最重要的特征,这些特征揭示了软件中的漏洞。然而,在可预见的未来,检测系统无法像专家/测试人员那样搜索漏洞,因为专家/测试人员很难将他们对漏洞的知识和理解转化为检测系统可以学习的特征向量。系统从特征集中学习到的东西也可能受到各种因素的影响(例如,模型的表达性、数据过拟合、数据中的噪声等)。
本研究的目标是使漏洞检测系统能够像经验丰富的专家或测试人员一样,以自动化和高效的方式更准确、更有效地执行。因此,要使基于机器学习的检测系统最终能够像人类一样学习和理解易受攻击的代码语义,还需要弥合差距。在本文中,我们将这种差距定义为语义差距,这将在第II-A2节中进行深入讨论。到目前为止,机器学习、软件工程和网络安全社区的研究人员一直在努力弥合这一差距。特别是,随着深度学习技术被应用于漏洞检测,神经模型[例如,循环神经网络(RNNs)]能够推理和理解代码语义[7]。与完全依赖手工特征的传统基于机器学习方法相比,深度学习方法有可能通过学习揭示代码语义的复杂模式和软件代码的高级表示来进一步缩小语义差距。
在本文中,我们回顾了最近的一项工作,该工作应用了基于深度学习/神经网络的方法进行漏洞发现,并评估了神经网络学习的不同类型的特征表示如何帮助捕获易受攻击的代码片段的特征,从而有助于弥合语义差距。我们还确定了所审查研究的弱点和该研究领域未解决的问题,旨在提出未来可能的研究方向。

A 结构

本文组织如下。在第二节中,我们首先从前人的研究中总结了软件漏洞的定义。然后,我们讨论了双方之间的语义差距:人类代码检查员和现有的检测系统。最后,我们简要回顾了传统的基于机器学习的研究是如何弥合语义差距的。在第三节中,我们提供了所审查研究应用的不同类型神经网络的一些背景知识,并根据神经网络学习的不同类型的特征表示将其分为四类。我们回顾了对每个类别的研究,以揭示每个工作如何处理代码并利用神经网络来学习脆弱性代码模式和语义。在每个小节的最后,我们讨论每个作品使用的数据集,其可能的可重复性,以及类别中共享的每个研究的特征。我们还确定了每个类别中研究的局限性。在第四节中,我们列出了该领域的挑战,并分享了对未来可能的研究方向的见解。我们在第五节对本文进行总结。

相关综述

在软件工程领域,已经提出并研究了各种用于缺陷/漏洞发现的技术。已经有几篇调查文章从不同的角度对许多软件缺陷/漏洞检测方法进行了系统的回顾。Shahriari和Zulkernine[90]回顾了使用不同代码分析技术的漏洞检测研究。Malhotra[64]回顾了应用ML技术的软件缺陷预测研究。Liu等人[62]进行了一项简短的调查,一般回顾了使用代码分析和基于机器学习技术的漏洞检测研究。Ghaffarian和Shahriari[33]对仅关注用于漏洞检测的传统机器学习技术的研究进行了广泛的回顾。所审查的研究主要基于从软件度量中提取的特征、手动定义的漏洞模式和异常模式。另一个类似的调查[44]也建立在这些研究的总结之上。[7]从比较编程语言与自然语言的角度提供了系统的研究,并根据代码和语言的异同讨论了模型设计的动机。在本文中,我们重点回顾了应用基于深度学习/神经网络的技术进行漏洞检测的工作,强调了神经网络为学习易受攻击的代码片段的特征而获得的不同特征表示,以便更好地理解代码语义。

2 漏洞语义差距

A. 软件漏洞:一个不同的视角

  1. 定义:软件安全漏洞(简称漏洞),又称安全缺陷[89]、安全bug[108]、软件弱点[54],简单定义为“具有安全含义的软件漏洞”[87]。Votipka等人[108]将漏洞分为三类:1)与性能相关的;2)与功能相关的;以及3)安全相关,并且也表明软件漏洞可以被看作是软件缺陷或bug的一个子集[83]。一旦这些对安全至关重要的漏洞被攻击者利用,就可能导致违反安全策略,导致安全失效[20]。在总结了前人对漏洞的不同定义后,Ghaffarian和Shahriari[33]对漏洞的定义如下:

漏洞的一个实例,由软件的设计、开发或配置中的错误引起,从而可以被利用来违反一些显式或隐式的安全策略。

  1. 人类检查员和检测系统,语义差距:尽管上述定义提供了对漏洞的一般理解,识别软件中的漏洞是一项具有挑战性的任务。它需要代码检查员或安全专家(统称从业者)具备足够的程序经验和知识,以及对编程语言的深度理解[108],这些共同形成了对代码语义的高级理解。在本文中,我们认为这种高层次的理解有助于在手动代码审计任务中搜索可能存在漏洞的代码片段,如图1所示。然而,基于机器学习的检测系统只能通过学习手动提取(即基于传统机器学习算法的研究)或自动提取(即,基于深度学习的研究)从代码(例如,源代码和汇编)中提取。检测系统无法像从业者那样完全理解易受攻击的代码模式的潜在语义。因此,在知识渊博和经验丰富的从业者和基于机器学习检测系统之间存在语义差距,我们将其定义如下。

语义差距是从业者可以理解的漏洞的抽象语义与ML算法可以学习的获得语义之间缺乏一致性。

在这里插入图片描述

和语法上(例如,代码结构的正确形式)理解代码。查看代码,执行者可能会检查是否缺少对变量的边界检查(即缓冲区错误的原因)。他/她在代码检查和安全知识方面的经验有助于他/她从软件测试人员或攻击者的角度进行思考,这可能会提供一种感觉或直觉,即更多地关注一段代码而不是另一段代码。例如,一个源变量(例如,一个输入值)是否可以被攻击者控制。他/她对程序的知识和熟悉程度也有助于他/她对代码依赖性的理解。例如,从业者知道目标函数的调用者和/或调用者,这使他/她能够轻松地执行过程间分析。")
因此,该领域研究的目标是开发基于机器学习的检测系统,该系统可以执行与经验丰富和知识渊博的从业者一致的漏洞检测,但以更可扩展,更高效和自动化的方式。从从业者的角度来看,在手工代码检查过程中成功检测漏洞不仅需要对代码语义和语法的理解,还需要对代码库的深刻了解,安全编码的实践,以及漏洞检测的经验[109],[121],如图2所示。以“心脏出血”漏洞(CVE-2014-0160)[1]为例,漏洞代码片段如下:
image.pngimage.png

此漏洞是由于缺少对可变负载的边界检查而导致的,并且与几行间歇代码有关。首先,负载在第7行声明,并在第11行由应用程序编程接口(API)函数调用n2s定义。在第19行中,假设负载在边界内,因此函数OPENSSL_malloc分配一个内存块,其缓冲区大小为负载长度,加上填充长度,再加上3。在第23行,将可变负载传递给API函数调用s2n,然后在第24行调用库函数memcpy,它将负载大小的源缓冲区pl复制到缓冲区bp。最终,存储在可变有效载荷中的内容通过28行的函数调用dtlsl_write_bytes发送到网络。检查此代码并发现漏洞的从业者应该能够正确识别可变有效载荷的流以及它在数据流中的操作方式。特别是,这需要从业者了解API调用n2s和s2n的实现,以确定可变负载如何变化。基于这种理解和经验,从业者可能会觉得有必要在调用memcpy之前验证可变有效载荷的边界,并可能进一步调查(例如,执行污点分析)。
从设计基于机器学习的漏洞检测系统的角度来看,将知识(即对程序代码的熟悉程度)和对代码库的理解传递给基于机器学习的漏洞检测系统。从业者必须将他们的知识和理解转化为针对漏洞发现进行优化的特征,以便基于机器学习的检测系统可以从这些特征中学习。然而,从业者可以描述上述漏洞的原因以及他们如何发现它,将他们的描述和理解转换为ML算法可学习的数值特征集,这迄今为止一直是一项具有挑战性的任务,许多研究人员仍在探索。一方面,将人类对漏洞的理解转化为数字特征是一个抽象和量化的过程,这将导致信息丢失并引入偏见。另一方面,当我们基于提取的特征应用ML算法来训练模型时,由于各种原因(例如,欠拟合/过拟合,数据的噪声等),模型可能会偏离我们的预期。

B. 从常规ML到深度学习

  1. 传统的基于ml的解决方案:许多基于ml的解决方案已经被引入,通过提出各种特征集供检测系统学习,试图近似从业者如何搜索漏洞的过程来弥合差距。[33]进行了一项广泛的调查,回顾了应用传统ML技术(非基于神经网络)进行漏洞分析和发现的不同方法。作者将这些方法分为三大类:1)基于软件度量的;2)基于易受攻击代码模式;3)基于异常的。在本次调查中,从不同的角度,我们想讨论这三组分类的研究是如何填补语义空白的。像McCabe[65]和代码流失[70]这样的软件度量是从不同角度衡量软件产品质量的数值指标。McCabe度量是软件复杂性度量。使用这些度量的漏洞检测模型建立在一个假设之上,即复杂的代码对于实践者来说很难理解,因此很难维护和测试。作为漏洞检测指示器的代码流失度量意味着频繁修改的代码往往是错误的,因此更有可能是有缺陷的,并且可能是易受攻击的,考虑到漏洞是软件缺陷的一个子集。尽管这些度量标准在度量软件质量方面有着悠久的历史,并且被用于缺陷预测,但它们并不是漏洞的直接指标。例如,这些度量标准并没有为代码安全性分析提供度量[69],并且经验表明,并非所有易受攻击的代码块(例如,文件或函数)都包含许多行代码并且逻辑复杂。因此,许多完全依赖软件度量作为特征来构建ML模型的研究报告了漏洞检测[33]的糟糕结果。从从业者如何执行代码审计的角度来看,可以考虑代码的复杂性等因素进行进一步检查,但这些因素不会是从业者确定一段代码是否易受攻击的决定性因素。因此,需要其他能够更好地描述易受攻击代码片段特征的特征集来训练更有效的ML分类器,以促进漏洞检测。

有一些研究应用文本挖掘技术从源代码上下文中提取代码模式,通过源代码中不同文本标记的频率来联合描述代码的模式。例如,词袋技术被应用于将源代码中的标记转换为向量表示,然后将其用作分类的特征集[88]。为了考虑可能相互关联的标记序列,挖掘程序的源代码采用了N -gram技术[76]。然而,一些研究人员认为,基于频率的文本挖掘技术未能捕获软件代码的丰富语义,因为它们“简单地平滑了术语共现的计数”,并且无法保留代码的
长期上下文依赖性[114]。其他研究人员[110]也指出,两个Java文件,其中包含完全相同的令牌和每个令牌的相同频率,可以有不同的代码语义。
与从源代码表面文本中挖掘的“扁平化”特征集相比,许多研究应用静态代码分析工具提取“结构化”特征集作为ML算法学习的代码模式。这些特征集是从静态分析生成的不同形式的程序表示中提取出来的,包括ast、cfg、数据流图(DFGs)、程序依赖图(PDGs)等。与软件度量和基于频率的代码特征相比,从代码分析工具和解析器的结果中提取的特征集揭示了更多关于代码的信息,因为每种形式的程序表示都从不同方面提供了对源代码的视图。例如,ast表示树状视图中的代码结构。CFG、DFG和PDG有助于分析变量如何从源流向汇,并可用于构建变量依赖关系和理解程序结构。特别是,Yamaguchi等人[119]提供的一种方法将AST、CFG和PDG组合成一个称为代码属性图(CPG)的联合表示,以提供更全面的图结构来描述代码的属性。除了从结构化程序表示中衍生出的特征集外,从动态分析中获得的程序执行轨迹也被用作特征[91]。结合从CFG和DFG中提取的静态特征集,他们的模型比他们之前的研究获得了更好的性能[92]。因此,基于高级源代码结构提取这些特征集可以在很大程度上反映从业者如何发现漏洞。
有一系列的研究将易受攻击的代码模式视为偏离正确和正常代码模式的异常模式。对于这些研究,作者没有考虑如何发现漏洞,而是强调了可能导致漏洞的因素。早期的研究如[29]、[57]、[124]和[111]应用了从知识渊博的个人经验中衍生出来的规则作为“模板”,用于检测不符合编程指南或最佳实践的潜在bug /脆弱代码。后来的研究采用了从异常API使用模式[6]、imports、function calls中提取的特征[73],以及API符号缺失检查[122]进行漏洞检测。然而,这些特征集通常与一小部分漏洞或特定类型的漏洞相关联。例如,从导入和函数调用中提取的特性只能训练一个分类器,该分类器检测由一些易受攻击的头文件或库引入的漏洞,而与缺失检查相关的API符号只能用于发现由于缺乏验证或边界检查而导致的漏洞。这些由异常代码模式生成的规则或特征集既可以是通用的,例如“调用锁函数表明之后应该调用解锁函数”,也可以是特定于任务/项目的,例如,导入或函数调用生成的特征可能并不适用于每个软件项目,缺失检查检测的解决方案是为成熟的软件项目设计的。因此,这些研究提出的解决方案可能会导致许多误报,或者只适用于特定任务的应用程序。

  1. 新兴的深度学习技术:传统ML模型在漏洞检测任务中的应用,通常依赖于从静态和/或动态代码分析中提取的手工特征来指导模型学习脆弱的代码模式。深度神经网络(deep neural networks, dnn)在语音识别b[25]、图像识别[49]、机器翻译b[9][102]等许多领域的突破性应用,使dnn成为许多最先进的人工智能(AI)应用的基础[104]。迄今为止,dnn已被应用于漏洞自动发现,检测性能良好。与传统的ML技术相比,在漏洞检测的应用中,深度学习技术:
    1. 与传统ML算法相比,能够学习更复杂、更抽象的高级特征或表示[104];
    2. 能够自动学习更具泛化性的潜在特征或表示,从而将从业者从劳动密集型、主观性和容易出错的特征工程任务中解脱出来[56],[61];
    3. 提供灵活性,允许针对不同的应用场景定制网络结构。例如,将长短期记忆(LSTM)网络与用于学习功能级表示的密集层结合起来作为高级特征[56],[61],实现用于学习特征重要性[8]的注意层,并添加用于捕获远程代码依赖[18]的外部存储器“插槽”,[89]。

深度学习技术的上述特征使研究人员能够构建能够捕获代码语义、理解代码上下文依赖关系并自动学习更具泛化性的高级特征集的检测系统。有了这些能力,构建的系统可以更好地“理解”代码的语义和上下文,因此,将进一步减少语义差距。

3 特征表示弥合语义差距

深度学习技术在各个领域的应用迅速增长,证明了其在学习复杂、潜在和抽象模式方面的有效性。最近在自然语言处理(NLP)领域的突破,如机器翻译[9],[102]和语言理解[26],也证明了神经网络模型在理解文本/语言数据的潜在丰富“语义”方面的能力。此外,早期的研究人员发现,自然语言模型对于处理软件源代码[39],[40]也是有效的,这促使许多研究人员将深度学习技术应用于代码分析任务。

A. 促进表征学习的神经网络

在本文中,我们特别侧重于回顾应用dnn进行软件漏洞检测的文献。在回顾的研究中,不同类型的网络结构用于从各种类型的输入中提取抽象特征,我们称之为特征表示,用于识别易受攻击的代码片段的语义特征。

全连接网络

全连接网络(fully connected network, FCN): FCN也被称为多层感知器(multilayer perceptron,MLP),被许多先行者选择作为主要基于手工制作的漏洞检测模型数字特征。这类作品将网络视为一个高度非线性的分类器,用于学习隐藏的和可能复杂的脆弱模式。与随机森林、支持向量机(SVM)、C4.5等传统机器学习算法相比,FCN可以拟合高度非线性和抽象的模式。这得到了通用逼近定理[23]的支持,即具有有限神经元数量的单个隐藏层的FCN可以近似任何连续函数[22]。因此,在给定大数据集的情况下,FCN具有比传统ML算法学习更丰富模型的潜力。这种潜力促使研究人员使用它来对潜在和复杂的易受攻击的代码模式进行建模。FCN的另一个优点是它是“输入结构无关的”,这意味着网络可以接受多种形式的输入数据(例如,图像或序列)[84]。这也为研究人员提供了手工制作各种类型的特征以供网络学习的灵活性。

卷积神经网络

卷积神经网络(Convolutional neural network,CNN): CNN被设计用来学习结构化的空间数据[84]。在图像处理中,CNN第一层的过滤操作能够从语义相似的附近像素学习特征。然后,后续过滤器(卷积核)将学习更高级别的特征,这些特征将被后续层(即密集层)用于分类。CNN能够从附近像素学习特征的能力也可以促进NLP任务。
例如,在文本分类任务中,应用于上下文窗口(即包含几个词嵌入)的CNN过滤器可以将上下文窗口内的词投影到语义相似词的向量非常接近的上下文特征空间中的局部上下文特征向量上[123]。因此,CNN可以捕获单词的上下文含义,这促使研究人员将CNN用于学习具有上下文感知的脆弱代码语义。

递归神经网络

递归神经网络:相比前馈网络(如FCN或CNN)相比,RNN天生就是为处理序列数据(如文本)而设计的。因此,大量的研究应用RNN的变体来学习漏洞的语义。特别是,rnn的双向形式能够捕获序列的长期依赖关系。出于这个原因,许多研究利用双向LSTM (Bi-LSTM)[41]和门通循环单元(GRU)[17]结构来学习代码上下文依赖性,这对于理解许多类型漏洞(例如缓冲区溢出漏洞)的语义至关重要。这些漏洞与包含多个连续或间歇代码行的代码上下文相关联,这些代码行构成了一个易受攻击的上下文。

其他类型

其他类型:有一些漏洞检测研究应用于其他不适合上述类型的网络结构,如深度信念网络(DBN)[110]和变分自编码器(VAEs)[52]。深度学习技术的另一个有前途的特点是,网络结构可以定制,以满足不同的应用场景。例如,研究人员[18],[89]应用了存储器网络[100],[112],该网络配备了外部存储器“插槽”,用于存储先前引入的信息,以备将来访问[18]。与LSTM结构相比,这种类型的网络能够捕获更远距离的序列依赖性;因此,它具有捕获更大范围代码序列的增强能力,这些代码序列是识别缓冲区溢出漏洞依赖于上下文的关键。

B. 先前工作分类

我们将回顾的研究分为四类特征表示,总结如下。

  1. 基于图的特征表示:大量的研究应用深度神经网络来学习来自不同类型的基于图的程序表示的特征表示,包括AST、2CFG、PDG以及它们的组合。
  2. 基于序列的特征表示:这类研究利用深度神经网络从序列代码实体中提取特征表示,如执行轨迹、函数调用序列和变量流/序列。
  3. 基于文本的特征表示:对于这类作品,特征表示是直接从代码的表面文本中学习的。
  4. 混合特征表示:这一类别包括最近将上述三种类型的特征表示结合在一起的研究。

提出的分类背后的基本原理是双重的。一方面,这些研究的贡献在于如何处理软件代码以生成特征表示,以促进深度神经网络对代码语义的理解,并捕获模式作为潜在易受攻击的代码片段的指标。另一方面,深度神经网络模型作为具有内置表示学习能力的分类器。现有的基于不同类型特征输入的研究允许深度神经网络获得揭示不同语义信息的高级表示。例如,使用ast作为神经模型输入的研究使深度神经网络成为可能通过程序的层次结构捕获代码模式和语义。应用函数调用序列的研究允许深度神经网络学习与函数调用模式相关的抽象特征。
在第III-C-III-F节中,我们将回顾应用不同特征表示以促进漏洞检测的每一类工作。我们还将讨论每个工作使用的数据集、它们可能的可重复性、每个类别共有的特征和/或局限性。

C. 基于图的特征表示

在本节中,我们回顾了使用各种类型的基于图的程序表示的研究,包括AST、CFG、PDGs和数据
依赖图(ddg)作为深度神经网络的输入来学习深度特征表示。

近期工作总结

[93]开发了一种检测基于php的web应用的SQL注入(SQLI)和跨站点脚本(XSS)漏洞的方法。这是一种针对语句级检测的细粒度解决方案。该方法的动机是观察到输入清理代码的实现对于防止SQLI和XSS漏洞至关重要。基于观察,他们提出了一组静态代码属性来表征cfg和ddg的净化代码模式。具体来说,作者使用cfg来识别输入及其相应的汇来生成输入属性,并使用ddg来定位执行输入净化的功能。基于识别的卫生处理功能,作者对一些卫生处理属性进行了分类。这些静态代码属性形成了20-D特征向量来描绘卫生处理模式。然后,作者应用C4.5、朴素贝叶斯(NB)和FCN作为分类器进行训练和分类。他们的实证研究表明,SQLI漏洞检测的平均召回率为93%,虚警率为11%,略好于XSS漏洞的预测结果,召回率为78%,误报率为6%。作者还报告说,FCN在他们的数据集上优于其他两个传统的ML分类器。
(“Automaticallylearning semantic features for defect prediction,”ICSE2016)[110]是第一项使用AST来学习神经表示,以检测Java源代码中的缺陷和漏洞。假设ast表示包含编程模式的代码语法,通过分析ast可以揭示隐藏在源代码中的代码语义。在从源代码中提取ast时,作者保留了三种类型的节点:1)函数调用和类实例创建节点;2)声明节点;3)控制流节点。然后,将节点转换为令牌序列。在跨项目检测的场景中,特定于项目的令牌被替换为方法声明/调用等通用名称。特别地,作者应用了距离相似度计算算法[72]来从他们的数据中去除噪声。该算法能够根据token和token之间的顺序计算token序列之间的距离。在此之后,对计算出的距离使用k近邻算法。如果某个实例与其邻居具有相反的标签,则该实例将被标记为噪声并被删除。最后,使用一对一映射表对剩余的标记序列进行标记化,将每个标记映射到一个整数,以便这些序列可以用作DBN的输入。与[38]、[61]和[86]等现有研究类似,作者将样本输入训练好的DBN,自动生成高级特征表示,然后用于训练传统的机器学习算法,如ADTree、NB和逻辑回归(LR)。
对于项目内检测的评估,作者从PROMISE3缺陷存储库中选择了Java项目,并将他们提出的方法与两个不同的特性集进行了比较:1)软件度量和2)ast。结果表明,DBN生成的基于ast的特征在所有选择的项目上都取得了最好的性能。对于跨项目场景,作者选择了TCA+[71]作为基线系统。绩效评估显示,在22个跨项目场景中,有17个基于dbn的方法在F1得分方面优于TCA+。
(“POSTER: Vulnerability discovery with functionrepresentation learning from unlabeled projects)[60]中提出的另一种基于ast的方法应用Bi-LSTM网络来学习跨项目漏洞发现的特征表示。考虑到在实践中获取易受攻击功能的手动标签可能是昂贵的,作者利用可以自动生成的软件复杂性度量作为代理来替代实际标签,以在功能级生成高级表示。他们的方法建立在许多研究共享的假设之上,即使用软件代码度量(例如,代码复杂性度量)作为漏洞检测的特征,因为复杂的代码难以测试和维护;因此,它更有可能是有缺陷和易受攻击的。具体来说,作者从源代码函数的ast中提取原始特征。他们使用“codessensor”[120],这使他们能够在没有AST提取的工作构建环境的情况下获得ast。然后,使用深度优先遍历(deep -first traversal, DFT)对得到的ast进行遍历,将其转换为序列。为了执行跨项目检测,作者模糊了特定于项目的AST令牌,以便左边的令牌与项目无关。随后,将AST序列中的每个标记转换为整数,并映射到64维嵌入向量上,该嵌入向量被输入到所提出的Bi-LSTM网络中,并在网络训练期间进行微调。该网络由两个Bi-LSTM层组成,用于从嵌入的AST序列中学习上下文信息。Bi-LSTM层之后有两个全连接层形成一个完整的网络在训练阶段,作者选择“本质复杂性”作为实际标签的替代品来训练网络。当训练完成后,作者将AST序列输入网络,并获得最后一层的输出作为学习到的高级表示,然后将其用作训练随机森林分类器的特征。作者使用从两个开源项目:FFmpeg和LibTIFF中收集的函数作为训练集,开源项目LibPNG作为实验的测试集。与之前的研究不同的是,作者使用了基于每个函数易受攻击的预测概率的排序结果,他们发现在检索200个最可能易受攻击的函数时,其中47%的函数实际上是易受攻击的。考虑到表征是在没有提供标签信息的情况下获得的,本文提出了一种可能的漏洞特征提取新方法,使用代码复杂性度量作为实际标签的替代品。
(Cross-project transfer representationlearning for vulnerable function discovery)后来,有人提出了一种方法,通过从历史软件项目的漏洞数据中学习可转移的表征来检测目标项目上的漏洞,该项目没有足够的标记数据来训练鲁棒ML模型[61]。同样,作者使用函数的ast作为原始特征,并将ast转换为基于DFT的令牌序列,以部分保留结构信息。然后,他们将Word2vec[67]与连续词袋(CBOW)模型一起应用,将序列的每个元素转移到100维的嵌入中,以恢复代码语义信息。然后,作者应用Bi-LSTM网络来促进从ast中保存的结构和语义信息中学习指示漏洞检测的项目无关表示。与[60]中使用的网络相比,他们提出的网络只有一个用于学习AST序列上下文信息的Bi-LSTM层,然后是一个全局最大池化层和两个完全连接层。全局最大池化层的功能类似于CNN结构中的最大池化层,用于捕获与潜在漏洞相关的最重要信号。作者基于国家漏洞数据库(NVD)4和常见漏洞与暴露(CVE)提供的漏洞数据库,手动标记了来自6个开源项目的457个易受攻击的函数,并从实验数据集中收集了14 648个非易受攻击的函数。为了模拟场景,使用历史数据进行迁移学习,作者将他们的数据集划分为使用其中五个项目作为源项目,一个作为目标项目。然后,他们进一步以1:3的比例将目标项目划分为训练集和测试集,以模拟通常没有足够的标记数据用于新开源项目的漏洞发现的场景。在训练阶段,使用源项目的数据来训练提议的网络。当训练完成后,作者将目标项目的训练集和测试集馈送到训练好的网络中,得到最后一层的输出作为学习到的深度AST迁移表示。最后,将获得的表征用于训练随机森林分类器。实证研究表明,与使用23个软件代码度量作为特征相比,从所提出的网络中学习到的表征更有效。
(“Automatic feature learning forvulnerability prediction,2017)[24]提出了一种基于ast的研究,利用序列到序列(seq2seq) LSTM网络对Java源代码进行文件级漏洞检测。作者声称,该网络能够自动从ast中学习语义和句法特征。从源文件中提取ast并将其转换为标记序列,以便每个序列对应于一个函数。为了将标记转移到LSTM网络可接受的嵌入中,作者构建了一个查找表,将每个标记映射到固定长度的向量。然后,将代码序列表示为向量表示,并馈送到seq2seq LSTM网络。seq2seq网络一次获取一个序列,每个令牌被输入到一个LSTM单元中。给定输入序列[x1, x2,…]中的一个输入令牌xt。, xn], LSTM单元计算输出状态向量st,并使用状态向量预测下一个令牌。给定代码令牌wt的输出状态向量,训练网络从之前的代码令牌wt的上下文中生成下一个代码令牌wt+1。因此,在训练过程中,网络能够学习标记序列之间的关系。为了生成表示源代码序列结构的语法特征,作者将代码标记序列的嵌入馈送到训练好的网络中,并将均值池化应用于网络的输出。通过这样做,同一序列中的所有令牌状态被聚合并存储在均值池化层生成的向量表示中,然后将每个功能级向量组装成一个文件的单个向量,该向量可以用作项目内漏洞检测的特征。由于所得到的特征向量是特定于项目的,因此作者构建了一个代码本,该代码本总结了所有令牌状态(即语义空间),用于执行跨项目检测。该码本包含了所有项目的令牌。使用k-means对训练集中的所有状态向量进行聚类,获得令牌的状态。给定一个新文件,作者计算文件内所有状态向量与每个簇的最近质心之间的距离,为该文件生成一个特征向量,该特征向量可以用作跨项目预测的特征。作者收集了18个开源的Android项目进行评估他们的方法的有效性。为了进行比较,作者选择了不同的特征提取方法,包括软件度量和词袋技术,以及一种实现DBN进行漏洞检测的最先进方法[110]。在项目内检测场景中,基于句法特征的方法获得了最佳的检测性能,F-measure达到93%。在跨项目场景中,使用语义特征和结合使用句法和语义特征的方法实现了最佳性能(F-measure为87%)。
SySeVR[55]中提供的系统框架利用不同类型的rnn (Bi-LSTM和Bi-GRU)来针对多种类型的漏洞进行检测。该框架旨在探索能够更好地将程序表示为向量的方法,以便保留反映漏洞特征的代码语法和语义信息,以促进漏洞检测。作者观察到,大多数漏洞都表现出一些语法特征,可以从程序的ast中检索到。对于基于语法的候选漏洞(SyVCs),作者需要将它们转换为基于语义的候选漏洞(SeVCs),以容纳与SyVCs在语义上相关的语句。从SyVCs到SeVCs的转变需要对项目的CFGs进行分析。然后,利用程序切片技术推导出DFGs。在CFGs和DFGs的基础上,可以构建PDGs。接下来,作者开发了一种算法,将描述SyVC语义关系的语句编码为向量表示,并使用Word2vec将这些表示进一步转换为定长嵌入[67],[68]。
为了研究提出的框架的性能,作者基于从NVD和软件保证参考数据集(SARD)项目收集的数据集进行了一系列实验。在420627个syvc上进行的实验,对应于四种类型的语法特征,使用Bi-LSTM网络平均产生86%的f1测量,比他们以前的工作[56]高出5%。作者还在CNN、DBN、LSTM、GRU和Bi-GRU五种其他类型的神经网络上进行了系统性能比较实验。Bi-GRU的性能最好,为f1测量的85.9%,DBN的性能最差,为17.8%。基于Bi-GRU网络,作者将所提出的框架与其他最先进的漏洞检测系统(包括Flawfinder[113]、RATS[4]、Checkmarx、VUDDY[45]、VulDeePecker[56])进行了比较,其框架的检测性能最好。

讨论

上一节回顾了六项现有的研究,这些研究将基于图的特征表示应用于漏洞检测。表1列出了所审查研究的摘要,其中我们突出了每个工作的关键差异。只有一半的研究公开了他们的数据集(参见表5)。不幸的是,由于昂贵的数据标记过程,在没有访问数据的情况下,不可能复制和评估所提出的方法。在提供数据集访问的文献中,有两项研究[60],[61]将其代码发布在Github上,这使得他们的作品易于复制。然而,[60],[61]提供的数据集在易受攻击的样本数量方面相对较少(少于500个源代码函数)。在前面回顾的六项研究中,有五项采用ast作为dnn的输入,用于学习漏洞检测的特征表示。根据[119],ast保留了语句和表达式组织方式的层次结构,包含相对更多代码语义和语法与CFGs不同[61]。因此,ast可以成为不同类型的神经模型学习与潜在脆弱模式相关的特征表示的有用来源。然而,据我们所知,还没有研究将ast与其他形式的基于图形的程序表示(如CFGs、pdg或DDGs)进行比较。此外,没有研究提供评估哪种程序表示可以使神经模型学习更有效的代码语义,从而产生最佳的漏洞检测性能。
image.png
此外,ast、CFGs、pdg和DDGs都是基于图的程序表示。尽管如此,上述研究并没有使用它们原始的树/图形式进行处理,而是在将它们馈送到深度网络之前将它们“扁平化”。图嵌入技术和基于图的神经网络可以作为处理上述用于漏洞检测的基于图的程序表示的替代方案,也许是更有效的解决方案。我们将在第IV-C节中深入讨论这一点。

D. 基于序列的特征表示

在本节中,我们回顾了采用dnn的顺序代码实体来学习特征表示的研究,包括系统执行跟踪、函数调用序列、形成数据流的语句序列等。

近期工作总结

[35]中提出的一种方法利用从静态和动态分析中提取的轻量级特征,在二进制级别预测操作系统(OS)规模程序中的内存损坏漏洞。假设来自静态和动态分析的调用序列/跟踪可以揭示C库函数的使用模式,这些函数表现出内存损坏漏洞。作者从一组与标准C库函数相关的调用序列中提取静态特征,这需要作者反汇编二进制文件。获得动态特征需要在有限的时间内执行程序。在执行过程中,作者对程序的事件进行监控,并收集调用序列。然而,获得的动态调用序列包含了大量的函数调用参数,这些参数都是低级的计算值。作者需要将它们分类为子类型,以减少参数类型的多样性。随后,作者应用N -gram语言模型和Word2vec[67],[68]将文本序列转换为有意义的向量表示,然后将其馈给三个分类器:LR、FCN和随机森林进行训练、验证和测试。作者报告说,他们的方法可以正确检测55%的易受攻击的程序,并且在检测精度和效率方面优于简单的模糊器。
文献[116]对C程序漏洞检测进行了评估研究,比较了不同类型的dnn对动态函数调用序列提取的特征集的性能。选择四种网络结构进行评价:[46]中提出的CNN网络、仅包含一个LSTM层的LSTM网络、分别包含一个卷积层和一个LSTM层的CNN-LSTM网络以及具有两个隐藏层的FCN。作者收集了9872个二进制格式的32位Linux程序,并应用[35]中介绍的方法,通过允许程序在有限的时间内执行来获得C标准库函数调用序列。然后,作者遵循[35]中采用的相同方法,通过使用提取函数的参数的子类型来减少参数类型的多样性。接下来,作者使用Keras[19]提供的标记化工具,这是一个深度学习框架,通过将每个标记替换为唯一的整数,将函数调用序列转换为数字序列。还应用了填充和截断,将各种长度的序列转换为固定长度的25个令牌。最后,作者以8:1:1的比例将9872程序数据集划分为训练集、验证集和测试集。为了将输入序列馈送到网络,在三个网络的第一层添加了一个嵌入层,将输入数字调用序列中的每个令牌转换为固定长度的向量。评价结果显示,LSTM网络的假阳性率最低(19%),CNN-LSTM网络的F-Score得分为83.3%,优于其他网络。
[56]中提出的一种方法利用一种称为“代码小工具”的程序表示来检测缓冲区错误和资源管理错误漏洞。代码小部件是一些连续的或间歇的代码行,它们在语义上彼此相关,形成一系列描述变量流和数据依赖性的语句。具体来说,根据这篇文章,代码的语义关系被定义为数据依赖或控制依赖。因此,代码小工具定义了多行代码,这些代码暗示了漏洞的存在,可以通过数据流或控制流依赖来捕获。为了提取与数据流或控制流相关的库/API调用和相应的程序片段,作者使用了一个名为Check-marx的商业工具。然后,将提取的程序片段组装成一个代码小部件,该代码小部件表示完整的数据流和/或API调用序列。随后,作者将代码小部件中的程序片转换为令牌序列,并应用Word2vec[67],[68]将它们转换为固定长度的向量表示。将Bi-LSTM网络作为基于代码小部件特征的漏洞检测分类器。
为了评估所提出的方法,作者从NVD和SARD项目[11]的代码样本中收集了61 638个代码小工具(17725个标记为易受攻击,43 913个标记为非易受攻击)。在这些易受攻击的样本中,有10440个缓冲区错误漏洞和7285个资源管理错误漏洞。他们的实证研究表明,在包含资源管理错误漏洞和非漏洞的数据集上,提出的方法可以达到95.0%的f1度量。对于只包含缓冲区错误漏洞的数据集,他们的f1度量结果为86.6%。对于包含这两种类型漏洞的数据集,他们的方法达到了85.4%的f1度量。值得注意的是,他们的研究是第一个声称他们在审查的研究中发现了一些0天漏洞。
最近的一项研究[127]进一步扩展了[56],纳入了“代码小工具”,不仅包含描述数据依赖关系的代码序列,还包含揭示控制依赖关系的代码序列。因此,代码序列形成了捕获与可能的漏洞相关的“全局”语义的上下文。为了检测特定的漏洞类型,他们还提出了所谓的“代码关注”,以关注语句中的“本地化”信息,例如“特定库或API调用中的参数”。为了促进基于“全局”语义特征和基于“局部”语义特征的学习,他们提出了两个设置相同但尺度不同的深度Bi-LSTM网络。最终,他们使用了一个合并层来融合全局特征和局部特征。然后,将融合的特征表示传递给另一个Bi-LSTM层,然后再传递给softmax层进行分类。
为了评估,作者还扩展了Li等人发表的数据集。在漏洞类型方面,他们从323个用C/ c++编写的程序和来自SARD项目的33086个测试用例中收集了116种不同类型的漏洞。他们的实证研究表明,该方法在检测各种类型的漏洞方面明显优于前人的工作,达到了94.22%的F1-measure。他们的方法还在Xen项目中发现了两个现实世界的漏洞,这证明了所提出方法的有效性。

讨论

上一节回顾了四项现有的研究,这些研究应用了dnn的顺序代码实体来学习漏洞检测的特征表示。表2中列出了所审查研究的摘要,其中我们强调了每个工作的关键差异。

在这里插入图片描述


在这一类别中,两项研究[56],[127]在Github上发布了他们的数据集(见表5),他们发布的数据可以形成一个大数据集,其中包含来自SARD项目的超过33000个人工测试用例和来自真实软件项目的超过138000个处理过的“代码小工具”。然而,该数据集未能成为性能比较的理想基线,因为它不能被不基于“代码小工具”的方法使用。如果作者能够在处理“代码小工具”之前发布原始数据集,那将会更有帮助。
值得注意的是,[56]中提出的方法是一个重要的里程碑。他们定义的程序表示,被称为“代码小工具”,准确捕获了缓冲区错误(CWE-119)和资源管理错误(CWE-399)漏洞的语义模式和特征,对其数据集的检测性能达到95%的F1-measure,是所综述研究中性能最好的。在他们工作的启发下,研究人员进一步改进了他们的想法,将“代码小工具”扩展为包括控制依赖关系[127],或容纳更多基于语法和语义的信息[55],以检测其他类型的漏洞。然而,他们的工作在一定程度上难以复制和遵循,因为“代码小工具”只能使用商业工具进行提取。
与基于图的输入相比,基于序列的输入(如调用序列和由“代码小工具”描述的数据流)完全是“扁平的”,但它们允许神经模型捕捉基于流的模式和高级特征。由于不同的研究基于自收集/自收集的数据集,并且关注不同的检测粒度,因此很难直接比较哪种形式的输入(即ast或“代码小工具”)可以更好地促进dnn学习更有效的特征表示。从而获得更好的漏洞检测性能。需要一个基准测试数据集,提供大量的标签和代码对来评估所提出的解决方案。

E. 基于文本的特征表示

在本节中,我们回顾了使用dnn的软件代码文本来学习特征表示的研究。代码文本是指源代码的表面文本、汇编指令和代码词法分析器处理的源代码。

近期工作总结

[78]中提出的一种近期方法将Java源文件转换为文本标记列表,并应用N -gram模型将标记转换为向量。他们假设可以通过挖掘源代码令牌的频率来识别易受攻击的模式。为了在使用N > 2的N -gram模型时处理所得到的特征向量的高维,他们通过应用Wilcoxon rank-sum[115]来过滤不相关的特征以降低特征向量的维数来进行特征选择。作者将特征向量输入到深度FCN中,获得的最佳性能是平均93%的检测准确率,97.6%的精度和89.26%的召回率在他们的数据集中。
[54]引入的另一种基于cnn的汇编级C程序漏洞检测方法,旨在直接从汇编指令中捕获易受攻击的代码模式。为了将汇编指令转换为向量表示,作者开发了基于Word2vec[67],[68]实现的Instruction2vec。Instruction2vec通过将四种类型的汇编代码(操作码、寄存器、指针值和库函数)映射到相应的固定长度的密集向量,生成汇编代码的查找表。由于每条指令的长度固定为9个值(一个操作码有两个操作数,每个操作数包含4个值),因此作者可以将每条指令表示为9 ×m-dimensional向量(其中m是由Word2vec模型确定的嵌入维数)。对于一段由n条指令组成的汇编代码,instructiontion2vec会将代码转换为9 ×m ×n大小的矩阵,该矩阵可以直接馈给CNN进行处理。为了评估所提出方法的有效性,作者在Juliet测试套件[12]提供的数据集上设置了四组实验。他们收集了3474个基于堆栈的缓冲区溢出测试用例(训练和测试为4比1),并将其编译为32位二进制文件。然后,对二进制文件进行反汇编,生成汇编代码文件,分别用于训练Word2vec和instruction -tion2vec。他们还选择了两种类型的CNN:一种是[46]中提出的CNN结构,它包含一个卷积层,包含9个不同类型的滤波器;另一种是由两个卷积层组成,包含32个×3滤波器和64个×3滤波器。实证研究表明,使用Instruction2ve和[46]中提出的CNN结构进行的实验取得了最好的结果,检测准确率为96.1%。
[86]也提出了类似的方法,将CNN应用于功能级漏洞检测。作者从Juliet Test Suite[12]、Debian Linux发行版和GitHub中收集了1200万个源代码函数样例。作者实现了一个自定义的C/ c++词法分析器,用于解析源代码,将函数源代码转换为令牌序列。为了捕捉关键令牌的含义并最小化令牌词汇表的大小,词法分析器只使用了156个令牌来表示源代码。这意味着,除了所有的C/ c++关键字、运算符和分隔符外,不影响编译的代码都被剥离掉了。然后,作者应用可训练嵌入,将函数序列中的每个标记转换为固定的k维表示,以便在网络训练阶段通过反向传播对每个标记的嵌入进行微调。作者采用了两种网络进行自动特征提取:1)[46]中提出的CNN结构具有一个卷积层后最大池化层和一个两层GRU网络后最大池化层。在网络训练阶段,对整个网络进行训练。当训练过程完成后,作者将训练和测试数据馈送训练后的网络,并获得两个网络的最大池化层的输出作为学习特征,称为神经表征。然后,这些神经表征被用作随机森林分类器的输入,以进行进一步的训练和测试。实验表明,与直接使用这两种网络作为分类器相比,使用网络作为特征生成器加上随机森林分类器产生了更好的检测性能。
最近的一项研究提出了一种基于VAE[47]的最大散度序列自编码器(MDSAE),用于从机器指令序列中自动学习表征,以检测二进制级别[52]的漏洞。作者对每个类(脆弱类和非脆弱类)应用了两个可学习的(非固定的)高斯先验,并且来自潜在空间的代码在分布之前被拟合到数据中。然后,最大化这两个先验之间的散度[例如,Wasserstein (WS)距离或Kullback-Leibler (KL)散度],以分离易受攻击和非易受攻击类的表示。特别是,所提出的MDSAE网络可以作为特征提取器来生成表示为用于分类任务的另一个独立分类器(例如,SVM或随机森林)的特征。或者,该网络可以与浅FCN结合,并同时作为分类器进行训练。
用于实证研究的数据集包含32281个二进制函数,这些函数是通过编译[56]中提供的数据集得到的。结果数据集包括用于Windows的17 977个二进制文件和用于Linux的14 304个二进制文件。Capstone二进制反汇编框架9用于将二进制文件转换为语义上更有意义的汇编代码。然后,对机器指令进行进一步处理以去除冗余前缀,并保留操作码和指令信息(例如,内存位置,寄存器)。作者分别构建了两个词汇表来嵌入操作码和指令信息。为了将操作码转换为向量表示,作者将它们转换为一热向量,并将操作码的一热向量与相应的嵌入矩阵相乘。为了将指令信息转换为向量,作者将指令信息视为十六进制字节序列,并在此基础上构造频率向量。指令信息的向量表示可以通过频率向量与相应的嵌入矩阵相乘得到。最后,通过对操作码和指令信息的向量进行浓缩,可以生成指令的向量表示。
为了评估所提出方法的有效性,作者建立了五个基线系统:用于学习表征的RNN和用于对脆弱和非脆弱函数进行分类的线性分类器。在最后一个隐藏单元的顶部放置一个线性分类器的RNN;段落到向量的分布相似度模型[51];连续的VAE;和[56]中开发的方法。实证研究表明,所提出的方法在所有选定的性能指标(准确率、召回率、精密度、f1分数和接收者工作特征曲线(AUC)下的面积)上都优于基线。
综述的研究表明,DBN和FCN的分层结构能够学习高级表示。他们还证明了CNN和RNN的变体(如LSTM网络)能够从文本语料库(如源代码或AST序列)中捕获上下文模式或结构。然而,直到Choi et al.[18]填补了这一空白,才有全面的研究证明DNN的传统结构能够理解给定代码上下文中值变化的转换。他们应用记忆网络来跟踪对多个语句中不同变量的值所做的变化,他们的实证研究表明,记忆网络能够根据不同变量的值被多个赋值语句改变的上下文来判断是否会触发缓冲区溢出。
根据[18]的说法,监控对多个变量的值变化不仅需要网络理解代码的结构,而且网络还应该具有记住变量及其对应值以及对它们所做的更改的能力。传统的RNN结构(即LSTM和GRU)通过隐藏状态或使用注意机制具有“记忆”,无法准确记忆长序列表达的所有内容(如段落或函数体)。因此,配备了额外构建的记忆块的网络(例如,神经图灵机[34]和记忆网络[100],[112])被开发出来,以保留NLP任务(如问答)的超长范围序列。
在[18]中实现了一个内存网络,用于对合成数据集执行缓冲区溢出(也称为缓冲区溢出)漏洞的端到端检测。提出的网络[18]直接将程序的源代码作为输入,并输出该程序是否包含漏洞。程序代码是逐行获取的。一行中的每个码令牌都由一个V维的一热向量编码,其中V是数据集中所有程序中唯一令牌的词汇表大小。少于N行的程序用零填充,其中N是一个内存插槽可以存储的最大行数,对于每一行,也使用零填充来填充每行的其余部分。然后,作者使用每行的单词计算每行的向量表示。具体来说,使用一个d维向量来表示每个标记,并使用嵌入矩阵(E−val)对每行进行编码。为了使模型能够区分出现在单行不同位置的相同标记的角色,作者应用了[99]中提供的位置编码来编码每行内标记的位置。接下来,将编码的行分配到内存槽中。特别地,存储器网络具有两种类型的存储器槽:用于存储代码行的内容的存储器值块和存储访问代码行的位置信息的存储器地址块。因此,每行都需要使用不同的嵌入矩阵进行编码:Eval用于每行的内容,Eaddr用于位置信息。
为了检查一行是否包含缓冲区溢出漏洞,然后将该行视为使用Eaddr(与地址相关的编码)编码为矢量表示的查询。注意机制通过计算查询嵌入和内存地址块的每个槽之间的内积来应用。随后,对结果向量使用softmax函数来产生一个注意力向量,该向量表明每行与查询的相关性。然后将获得的注意力向量与记忆值块的每个槽相乘,以生成响应向量。这些操作的基本思想是,如果搜索范围内的其中一行将包含相关信息(例如,变量名出现在查询),得到的关注会更高,从而对响应向量的贡献更显著。最后,要么将响应向量应用于权重矩阵以生成输出,要么将响应向量添加到之前的查询嵌入中,这些查询嵌入将用于计算注意力向量并最终计算响应向量。该模型通过多次跳跃迭代地生成响应向量,并产生从0(不安全)到1(安全)的输出。作者设计了四个级别的代码示例,更高的级别表示更复杂的条件(例如,第一级示例指的是直接缓冲区访问,它只考虑一个变量操作,而第四级示例与多个函数调用和类型重新分配相关)。作者在10000个样本程序上训练了他们的网络,并在四个测试集(每个测试集的每个级别)上进行了测试,每个测试集有1000个样本。与b[46]中提出的CNN和LSTM网络相比,提出的记忆网络在所有四个级别的测试中都取得了最好的结果。值得注意的是,CNN在所有级别的样本上都表现不佳。LSTM网络在一级样本上取得了相当的性能,但在更高级别样本上性能急剧下降,而内存网络的性能相对稳定。
然而,[18]中提出的方法有几个弱点:他们使用的合成代码在语法上是无效的,因此代码无法编译,并且合成代码没有任何控制流,不能反映现实世界的场景。因此,最近的一项研究[89]进行了以下改进以解决这些弱点:首先,他们产生了一个更真实的代码数据集(名为s-bAbI),其中包含语法准确的C程序,具有重要的控制流结构。代码样本包含六种不同类型的标签,这些标签是在行级提供的。其次,作者在每行代码中添加行号,以便在处理代码时明确告知存储网络行序列的顺序。第三,作者对每行代码令牌应用Dropout[31][98],其值为0.3,以防止过拟合。对于网络结构和嵌入方法,作者继承了[18]中应用的配置和设置。为了解决类不平衡问题,作者应用了随机抽样技术,以确保在生成的批次中每个标签的查询行数相等。为了进行评估,作者使用了包含76 549个样本(67%为声音)的s-bAbI数据集和[18]发表的数据集。为了进行比较,作者选择了3个开源和1个商业静态代码分析工具。作者重新实现了b[18]中提出的记忆网络,在他们的数据集上进行了测试,他们的网络在f1分数方面达到了71.3%。然而,由于[18]中提供的数据集在语法上不正确,静态分析工具无法执行。在s-bAbI数据集上,内存网络在s-bAbI和soundone上的f1分数分别达到91.7%和90.6%,优于开源工具,而商业工具在相同数据集上的f1分数分别达到93%和91.9%。对于声音数据集,一个名为Frama-c的代码分析工具在f1分数方面达到了98.6%。作者得出结论,由于生成的代码结构简单(例如,没有复杂的函数调用,只包含三个控制流节点),静态分析工具可以实现高性能。然而,他们也强调,记忆网络可以完成90%以上的f1分数,因为训练数据集和测试数据集具有相似的分布。在Juliet test Suite数据集的缓冲溢出测试用例上,网络未能收敛。

讨论

前一节回顾了六项现有研究,这些研究应用dnn的软件代码文本来学习漏洞检测的特征表示。表3列出了所审查研究的摘要,其中我们强调了每个工作的关键差异。

在这里插入图片描述


在上述综述的文献中,[18]、[52]、[89]等6项研究中有3项的数据是公开的(见表5)。[52]中发表的数据集是基于[56]中提出的数据集,但采用汇编/二进制格式。[18]和[89]中提供的数据集是人为构建的,不可编译,无法真实地反映生产软件中真实的脆弱模式。
与其他类别的研究不同,这一类的作品没有使用任何代码分析方法。他们直接使用代码文本作为学习特征表示的输入,并期望神经模型具有表达能力,能够学习隐藏在代码表面文本中的潜在脆弱代码语义。该研究[78]应用了FCN,这是一种用于学习基于频率的源代码特征的通用网络结构。后来的研究将CNN用于语境学习。由于易受攻击的代码语义通常包含多行构成上下文的代码,因此CNN结构可以作为检测与易受攻击代码上下文相关的漏洞的合适选择。最新的研究[18]和[89]提出了记忆网络,这是一种复杂的结构,包含额外的存储槽,用于存储远程代码上下文,允许网络直接接受源代码作为输入。随着网络结构变得更加复杂和富有表现力,代码处理所需的工作量减少,这可能是一个新的趋势。第IV-B节在这方面进行了深入的讨论。
比较和评价这一类的拟议研究具有挑战性。例如,在发表其数据集的研究中,Nguyen et al.[52]侧重于组装级检测。[18]和[89]两项研究要求在语句级提供标签。对这些方法进行比较研究需要一个满足要求的基线数据集,这将带来巨大的工作量。

F. 混合表示

在本节中,我们回顾了基于输入类型的研究,这些输入类型结合了上述任何类别。

近期工作总结

[27]提出了一种检测Android二进制可执行文件漏洞的方法。具体来说,作者反编译了Android APK文件,获得了包含dalvik指令包的小文件。从小文件中提取了两种类型的特征:1)由dalvik指令的频率表示的令牌特征,表示令牌属性;2)通过遍历小文件的ast生成的语义特征。为了提取标记特征,作者将小文件的dalvik指令分为8类,并构建了映射表。通过记录映射表中指令出现的频率,获得令牌特征。语义特征是从使用antlr从小文件中解析的ast中提取出来的[77]。作者采用深度优先搜索(DFS)遍历将ast转换为序列。然后,根据之前构建的dalvik指令映射表,将得到的AST序列转换为整数序列。最后,结合标记特征和语义特征向量构造特征向量,并将其送入深度FCN进行训练和测试。作者还将深度FCN与其他传统的机器学习算法(包括SVM、NB、C4.5和LR)进行了比较。他们的实证结果表明,深度FCN优于其他算法,AUC达到85.98%。
[38]中提出的另一种方法是基于两组特征进行漏洞检测。第一组是直接从源代码中提取的基于源代码的特征,第二组是从Clang和低级虚拟机(LLVM)[50]生成的cfg中派生的基于构建的特征。具体来说,对于基于源代码的特征,作者实现了一个自定义的C/ c++词法分析器,将源代码函数转换为token序列,然后执行[36]的proccedure。特别是,变量名被映射到相同的通用标识符,但单个函数中的每个唯一变量名都被分配了一个单独的索引,以跟踪变量的重新出现。然后,Mikolov等人[67]、[68]使用词袋模型和Word2vec模型将得到的令牌序列转换为两种类型的向量表示。对于基于构建的特征,作者编译了程序,并从函数级cfg和指令级的基本块中提取了特征。特征集由每个基本块中发生的操作以及变量的定义和使用组成。例如,作者构建了一个use-def矩阵来记录变量的定义和使用。如果一个变量在指令i处定义并在指令j中使用,那么use-def矩阵的(j, i)项都被设置为1。得到的特征集包含邻接矩阵和op-vec/use-def向量。然后,作者定义了一个手工制作的固定大小的向量,通过执行形成平均操作来容纳CFG和op-vec/use-def向量的邻接矩阵。
为了进行性能评价,作者将[46]中提出的CNN与传统的随机森林和极度随机树[32]模型进行了比较。实证研究表明,基于源特征的模型取得了更好的性能。与使用CNN作为分类模型相比,由CNN学习(不含密集层)并由基于树的模型分类的组合特征产生了最好的性能。
[59]中提出的一个框架利用两个Bi-LSTM网络从两种不同类型的数据源中获取特征表示,以弥补标记数据的不足。该框架允许每个网络独立训练,并用作特征提取器,用于从两个漏洞相关数据源(包含合成漏洞测试用例的SARD项目[11]和真实世界的漏洞数据)的组合中学习漏洞模式的潜在表示来源。为了弥合SARD项目中真实样本和合成样本之间的差异,作者应用了两种不同类型的特征表示:从真实样本中提取的ast和合成样本的源代码。然后,在训练阶段,一个网络被输入ast,另一个网络将源代码作为输入。他们假设,与使用单个数据源训练的一个孤立网络相比,两个训练过的网络能够从两个漏洞相关的数据源中捕获更多的“漏洞知识”。在训练阶段之后,他们使用来自目标软件项目的可用标记数据,并将它们输入到两个训练好的Bi-LSTM网络中,分别获得两组高级表示。随后,将获得的表示连接起来,形成一个聚合的特征集,该特征集可用于训练传统的ML分类器,如随机森林。他们的实证研究证明,利用两个漏洞相关数据源的框架比只使用一个数据源的框架更有效。该框架在FFmpeg、LibTIFF和LibPNG项目上的表现优于他们之前的工作[61]。

讨论

上一节回顾了三个现有的研究,这些研究应用了不同输入的组合来学习漏洞检测的特征表示。表4列出了所审查研究的摘要,其中我们强调了每个工作的关键差异。在这一类的研究中,只有一个工作[59]公开了数据集和代码(见表5)。他们的方法也是第一个利用两个网络从两组输入(ast和源代码)中学习两种类型的特征表示的方法。该类别中的另外两项研究提出了一种数据标记的自动化解决方案,即使用静态代码分析工具来提供标签。然而,静态工具往往会产生许多误报,需要人工进行进一步检查。
值得注意的是,所有三项研究都报告说,与使用单一类型相比,组合不同类型的特征表示可以提高检测性能。这可能提出了一个新的方向,即使用神经网络来学习不同类型的特征表示可能会获得更多与漏洞相关的知识,这有助于更有效地学习漏洞代码语义,从而获得更好的检测结果。神经网络的表征学习能力可以通过学习包含通用漏洞相关信息的高级和抽象表征来弥合不同类型数据集(例如,无论是合成的还是真实的)之间的差异。换句话说,提供给神经网络的数据集可能在数据格式和处理方法上有所不同,但网络学习到的特征表示是通用的。这可能为比较和评估基于不同数据集的拟议解决方案提供见解。
image.png

4 挑战与未来路线指南

尽管综述的研究已经提出了各种类型的特征集,并应用了不同的网络结构来减少语义差距,但还有很长的路要走。在本节中,我们将讨论面临的挑战和未来的工作,并分享一些见解。

A. 大规模真实数据集

数据集是阻碍这一领域发展的主要障碍。在现阶段,提出的基于神经网络的漏洞检测技术都是在自构建的数据集上进行评估的。由于针对各种检测的方法不同粒度,由现有研究构建的基础真实数据集在不同级别进行标记(例如,在代码行级别或功能级别进行标记)。此外,现有研究收集的数据集要么是合成的,要么是从现实世界的程序中收集的。因此,迫切需要一个标准的基准数据集来作为评估和比较所提出方法有效性的统一度量。为了填补这一空白,工作[58]首次提出了一个基准测试数据集,其中包含了用C编程语言编写的9个开源软件项目中收集的易受攻击的源代码。他们的数据集提供了两个粒度级别的标签,即函数级和文件级。然而,他们提出的数据集仍处于初步阶段,因为它仅由大约1400个易受攻击的函数和1300个易受攻击的文件组成。理想情况下,一个标准的基准测试数据集应该针对专注于多级检测粒度的方法进行精心定制,并且应该包含大量的合成和真实世界的代码样本,用于定性和定量的评估和比较。
有许多数据存储库提供了合成漏洞样本。由美国国家标准与技术研究院(NIST)提供的软件保证度量和工具评估(SAMATE)项目[10]是为评估自动化工具以确保软件质量而建立的。根据[89],SAMATE项目由几个数据集组成,包括朱丽叶测试套件[12],SARD[11],情报高级研究项目活动(IARPA)[2]的安全承担新的不确定来源的可执行软件(STONESOUP)项目,以及用于评估静态分析工具的静态分析工具博览会(SATE)数据集[75]。朱丽叶测试套件和SARD项目被[55]、[56]和[89]等几项综述研究采用,其中主要包含可编译的人工构建代码样本。然而,Choi等人质疑朱丽叶测试套件中测试用例的代码模式不够多样化。许多代码样本遵循类似的编码格式,并且大部分代码在许多样本中保持相同。
更重要的是,上述数据存储库缺乏来自实际软件项目的标记代码样本。真实世界测试用例的性能评估可以真实地反映所提出的漏洞检测方法在真实世界环境中的表现。为了解决这个问题,许多被审查的研究构建了真实世界的数据集进行评估,但只有少数研究公开了他们自己构建的数据集。表5列出了在撰写本文时被评审研究收集的数据集的公开链接。然而,可供使用的数据集通常规模较小,提供的标记不足的漏洞数据[58]-[61]或提供无法编译的合成样本[18],[89]。研究提供的数据集规模相对较大,这可能需要使用商业工具[55],[56],[127]。因此,我们呼吁这一领域的研究人员继续向公众贡献他们的数据和代码。
image.png

B. 代码分析和神经学习

从综述的文献中可以看出一个趋势,用于漏洞检测的网络模型正变得越来越复杂,表达能力也越来越强,以便更好地学习指示脆弱代码片段的代码语义。从早期应用MLP的研究[92]到最近使用CNN[38]、[86]或LSTM[56]的研究[61],直到最近采用记忆网络[18]的研究[89],不断发展的网络结构表明,研究人员在探索神经网络在代码语义推理和促进漏洞发现的丰富模式方面的潜力方面付出了巨大的努力。来自ML和NLP社区的研究人员已经被激励采用最先进的工具/方法进行漏洞检测的代码分析[7]。
另一个趋势也可以揭示,随着网络变得越来越复杂,需要付出的努力减少了代码分析的工作量。该研究应用了MLP[92],它使用来自cfg和ddg的手工特征来学习输入验证和清理代码模式。提取cfg和ddg需要大量的代码分析工作以及获得特性的专业知识。后来的研究使用了CNN[38][86],可以直接从lexxed源代码中学习特征,需要较少的代码分析工作,而最近应用记忆网络的研究将源代码作为输入,不需要任何代码分析。尽管如此,来自软件工程和网络安全领域的专业知识和知识仍然需要定义具有代表性和有效的特征来指导网络架构的设计,以便更好地发现潜在和复杂的易受攻击的语义和模式。
图3基于[8],说明了使用更具表现力的模型来学习易受攻击语义的趋势,代码分析所需的工作量更少。此外,图3还显示了一些被审查的研究所做的权衡点,以平衡现实场景中的模型学习/设计工作和代码分析工作。在实践中,基于ml的任务需要考虑在设计/训练一个复杂但有能力的模型的努力与定义高质量和代表性特征的努力之间进行权衡。松散定义的特征需要一个表达模型从零开始学习,而开发/训练一个适合感兴趣任务的表达模型也具有挑战性[114]。
神经模型学习/设计工作与代码分析工作之间的权衡。在设计一个有能力/有表现力的模型的努力和生成有效特征[8]的代码分析努力之间,需要考虑一些权衡点。

C. 带有语义保留的神经模型

推进将神经网络应用于漏洞检测领域的一个关键点是,通过使神经模型能够更好地与编程语言[7]、[33]的语义进行推理来填补语义空白。在算法层面,开发更具表现力和能力的模型来学习代码语义和句法结构,可以有助于解决语义差距。尽管所审查的研究所应用的网络正变得越来越复杂,但最先进的实现,如记忆网络,被证明仅在包含简化代码样本的合成数据集上表现良好(达到f1分数的91.7%),而不是在真实世界的代码样本上。然而,这并不能阻止研究人员进一步探索复杂神经模型的潜力。最近一项应用生成对抗网络(GAN)[37]修复C/ c++合成代码示例漏洞的研究已经证明了神经模型在理解代码逻辑和语义方面的能力。
在NLP领域,序列建模和自然语言理解的最新进展令人鼓舞。例如,基于自注意机制的Transformer神经网络架构[107]在自然语言翻译任务中表现优于最先进的方法,并在自然语言理解方面表现出强大的能力。NLP领域的丰硕研究成果越来越多地应用于软件工程研究[28],例如采用Word2vec和Bi-LSTM进行代码语义学习[56],[61]。将Transformer这样的模型应用于代码分析任务(如漏洞发现)中,以更好地理解编程语言语义,将是令人兴奋的。
另一个需要填补的空白是应用基于树/图的神经网络进行漏洞检测。许多程序表示都是树或图的形式。例如,AST以树的层次结构来描述代码组件。CFG可以是显示程序控制流的有向图,PDG使用图表示法显式表示数据依赖关系和控制依赖关系。现有的研究利用这些程序表示,但以“扁平”的形式,并使用FCN、CNN或rnn以“顺序”的方式处理它们,这可能不可避免地失去包含可能易受攻击的代码语义的层次和/或结构信息。因此,为了更好地处理和保存隐藏在基于树/图的程序表示中的层次和/或结构信息,基于树/图的神经网络可能是理想的选择。[105]中提出的树状结构LSTM (TS-LSTM)网络和[97]中的递归神经网络已经证明了它们在处理以树状结构组织的自然语言的语法属性方面的有效性。这些网络可以适用并可能有效地处理ast以学习树状结构代码语义。还有大量基于图的神经网络(也称为图神经网络(gnn)[118])可以直接操作基于图的程序表示(例如,cgf和PDGs),用于学习指示潜在漏洞代码的高级特征表示。例如,图卷积网络(GCNs)[48]和图自动编码器(GAEs)[14]可以促进图结构中呈现的程序表示的学习,以及描述代码实体关系的节点和边之间的相互依赖关系。帮助模型学习代码语义的另一个可能的解决方案可以是提供与代码相关的其他信息源,以支持模型学习。开源存储库,如GitHub,提供了丰富的软件项目的文本足迹,可以用作促进模型学习代码语义的相关信息源,例如,向代码存储库提交的消息[79],描述/解释一段代码的注释,以及代码评审的注释。

D. 代码表示学习

从数据处理的角度来看,可以通过设计更好的特征工程技术来缩小语义差距,将丰富的语义和句法代码特征结合起来,以提高模型学习能力。一方面,定义代表易受攻击代码特征的高质量特征有助于模型学习,这可以显著促进基于ml的检测系统[33]的成功。另一方面,高质量的特征较少依赖可能需要大量数据进行训练的复杂和富有表现力的模型。
在漏洞检测领域,由于易受攻击的代码模式是多样的,而构成易受攻击代码上下文的语句要么在功能边界内(过程内),要么跨越多个功能(过程间),定义能够普遍表征所有类型漏洞的特征集几乎是不可行的,也是不可能的。因此,定义反映某些类型漏洞特征的特征集可能是一种折衷的选择,但开发针对特定类型漏洞的检测系统已经取得了可喜的结果[56],[121]。
由于我们希望有更好的特征来表示/描述漏洞的特征,我们也需要更有效的嵌入技术。在将代码或文本特征转换为向量表示时,我们的目标是保留文本令牌的更多语义含义,以便下游模型可以学习更丰富、更具表达性的语义。大量被审查的工作依赖于基于频率(例如,n-gram模型)和基于预测(例如,Word2vec模型[67],[68])的词嵌入解决方案。基于频率的嵌入技术根据出现在给定上下文中的词频产生词嵌入,从而捕获有限的词语义。基于预测的模型,特别是Word2vec,可以从相对较小的上下文窗口中学习单词语义,但无法捕获目标单词与其上下文之间相互依赖的整体意义[80]。因此,需要一种更有效的嵌入技术,为学习系统提供更丰富的语义信息以供学习。

E. 可解释性

ML模型,特别是神经网络模型,是黑盒子[85],这意味着模型如何进行预测/分类背后的原因对于从业者来说是未知的。大量被审查的研究没有努力解释模型的行为。在漏洞检测领域,无法理解模型如何预测一段代码是易受攻击的/非易受攻击的,可能会导致模型的实用性受到质疑。人们可能会提出以下问题:模型值得信赖吗?或者这个(个体)预测/分类可靠吗?无法理解模型的行为可能是阻碍基于神经网络的模型在实践中应用于漏洞检测的障碍之一。
与线性模型不同,神经网络引入了非线性,其分层结构给模型的可解释性带来了困难。特别是,当将神经模型应用于高级表示的自动学习作为特征时,获得的特征是抽象的,人类无法读取。为了解决这个问题,LIME10[85]被提出,通过在预测样本周围局部学习一个简单且可解释的模型(例如,线性或决策树模型),为任何模型提供可解释性。然而,当神经网络模型被用作特征提取器时,LIME就不适用了,这些特征提取器被用来训练分类器。注意机制可以作为解释该模型的一种手段。通过注意机制,CNN/RNN可以在一次[53]有选择地关注或关注输入的一部分(例如,图像或文本序列)。通过绘制被关注的部分(例如,注意权重矩阵),可以为模型提供一定程度的可解释性。例如,注意力网络架构被应用于从函数的AST[8]的路径中学习函数级表示。为了组合一袋路径-上下文向量来形成一个表示,注意网络可以学习对每个路径-上下文应该给予多少注意。通过获得注意力向量,作者可以定量测量网络对AST内的每个路径上下文给予了多少关注,这表明在表示生成过程中每个路径上下文被给予的不同程度的重要性。最近,注意力网络已被应用于缺陷预测[30],为提供可解释的基于深度学习的代码分析和漏洞/缺陷预测指明了一个有前途的研究方向。

5 结论

神经网络在漏洞检测中的应用是一个不成熟的研究领域,有许多问题尚未解决。随着ML领域的快速发展,ML和深度学习的重大进展将为漏洞检测工具包增加价值。我们回顾了应用神经网络进行漏洞检测的现有研究,显示了采用网络结构来更好地学习脆弱代码片段特征的发展趋势,旨在弥合从业者如何理解漏洞和神经网络模型可以从中学习的获得的语义之间的差距。神经模型的表示学习能力及其可定制的结构为复杂的易受攻击代码模式的自动学习提供了令人兴奋的潜力,这将激励和吸引更多的研究人员为这一有前途的领域做出贡献领域。
发展趋势,旨在弥合从业者如何理解漏洞和神经网络模型可以从中学习的获得的语义之间的差距。神经模型的表示学习能力及其可定制的结构为复杂的易受攻击代码模式的自动学习提供了令人兴奋的潜力,这将激励和吸引更多的研究人员为这一有前途的领域做出贡献领域。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值