Vul-RAG:通过知识级 RAG 提升基于 LLM 的漏洞检测能力
Vul-RAG: Enhancing LLM-based Vulnerability Detection via Knowledge-level RAG
![![[Pasted image 20250324111816.png]]](/https://i-blog.csdnimg.cn/direct/8ab0424d64d14849a91d933c6cc558e7.png)
摘要
软件质量保证中,漏洞检测至关重要。近年来,深度学习模型(尤其是大型语言模型)在漏洞检测领域展现了巨大潜力。
在本工作中,我们提出了一种基于 LLM 的新型漏洞检测技术 Vul-RAG,该技术利用知识级检索增强生成(RAG)框架,分三个阶段对给定代码进行漏洞检测。首先,Vul-RAG 通过 LLM 从现有的 CVE 实例中提取多维度知识,构建漏洞知识库;其次,针对给定的代码片段,Vul-RAG 根据功能语义从构建的知识库中检索相关漏洞知识;第三,Vul-RAG 利用 LLM 推理检索到的漏洞知识中的漏洞成因及修复方案,从而检查给定代码片段的漏洞。
我们在自建基准数据集 PairVul 上对 Vul-RAG 进行了评估,结果表明,Vul-RAG 在准确率/配对准确率上相对提升了 12.96%/110%,显著优于所有基线方法。此外,我们的用户研究表明,由 Vul-RAG 生成的漏洞知识可作为高质量的解释,将人工检测的准确率从 0.60 提升至 0.77。
1 引言
软件中的安全漏洞为破坏性攻击敞开了大门,可能导致软件运行期间出现严重后果。迄今为止,已有大量关于自动化漏洞检测技术的研究。除了利用传统的程序分析方法外,鉴于人工智能领域的最新进展,深度学习也被引入到漏洞检测技术中。
基于学习的漏洞检测技术 [1–6] 主要将漏洞检测形式化为针对给定代码的二分类任务,即先在现有的漏洞代码和良性代码上训练不同模型(例如图神经网络或预训练语言模型),然后对给定代码进行漏洞预测。最近,大型语言模型(LLMs)的先进进展进一步推动了基于学习的漏洞检测技术的发展。由于 LLMs 具有强大的代码和文本理解能力,它们在分析代码中的恶意行为(如漏洞或错误)方面表现出令人期待的效果 [7–11]。例如,现有的基于 LLM 的漏洞检测技术通过结合提示工程(例如链式思维 [12, 13] 和少量样本学习 [14])实现了更准确的漏洞检测。
初步研究
然而,由于深度学习模型的可解释性有限,目前尚不清楚现有的基于学习的漏洞检测技术是否真正理解和捕捉到了与漏洞行为相关的代码语义,特别是当模型的输出仅为二元标签(即漏洞或良性)时。为了填补这一知识空白,我们首先基于以下假设进行了一项初步研究:“如果某技术能够精准区分一对具有高词汇相似性的漏洞代码和非漏洞代码(即仅在少数标记上存在差异),我们认为该技术具备更好的捕捉与漏洞相关语义的能力。” 由于两个词汇相似的代码片段可能在代码语义上存在差异,因此如果模型能够精准区分它们,则很可能已经捕捉到了高级别的与漏洞相关的语义。然而,目前尚无专注于此类高词汇相似性漏洞代码和非漏洞代码对的现有漏洞检测基准。为此,我们首先构建了一个新的基准数据集 PairVul,其中包含来自 2,073 个 CVE 的 4,314 对漏洞代码和修补后的代码函数。随后,我们在自建基准上评估了三种代表性的基于学习的技术(即 LLMAO [8]、LineVul [6] 和 DeepDFA [3])以及一种静态分析技术(即 Cppcheck [15]),以研究它们对这类代码对的区分能力。根据结果,现有基于学习的技术在区分此类词汇相似代码对方面的效果实际上相当有限。特别是在我们的基准数据集 PairVul 上,其准确率降至 0.50 ∼ 0.54,远低于先前基准报告的结果(例如,LineVul [6] 在 BigVul [16] 上的准确率为 0.99)。这些结果表明,现有训练模型在捕捉与给定代码中的漏洞行为相关的高级代码语义方面能力有限。
技术
受初步研究观察结果的启发,我们的见解是利用高级漏洞知识来区分漏洞代码与看似相似但正确的代码。具体而言,基于开发者如何手动识别漏洞的观察,理解漏洞通常涉及三个维度的代码语义:(i) 代码实现的功能,(ii) 漏洞的成因,以及 (iii) 漏洞的修复方案。这种高级代码语义可以作为漏洞检测中的漏洞知识。
为此,我们提出了一种基于 LLM 的新型漏洞检测技术 Vul-RAG,它利用知识级检索增强生成(RAG)框架来检测给定代码中的漏洞。Vul-RAG 的核心思想是利用 LLM 基于现有漏洞中的相似漏洞知识进行推理以实现漏洞检测。具体而言,Vul-RAG 包含三个阶段。首先,Vul-RAG 通过 LLM 从现有 CVE 实例中提取多维知识(即功能语义、成因和修复方案)来构建漏洞知识库;其次,对于给定的代码片段,Vul-RAG 根据功能语义从构建的知识库中检索相关漏洞知识;第三,Vul-RAG 利用 LLM 通过对检索到的漏洞知识中的漏洞成因和修复方案进行推理,检查给定代码片段的漏洞。Vul-RAG 的主要技术创新包括:(i) 一种新颖的多维漏洞知识表示,关注更高层次的代码语义而非词汇细节,以及 (ii) 一种新颖的知识级 RAG 框架,该框架首先基于功能语义检索相关知识,然后通过漏洞成因和修复方案进行推理以检测漏洞。
评估
我们进一步在基准数据集 PairVul 上对 Vul-RAG 进行了评估。首先,我们将 Vul-RAG 与三种代表性的基于学习的漏洞检测技术和一种静态分析技术进行了比较。结果表明,Vul-RAG 在更精准地识别漏洞代码与看似相似但正确的代码对方面显著优于所有基线方法,例如在准确率上提升了 12.96%,在配对准确率(即正确识别一对代码中漏洞代码和非漏洞代码的比例)上提升了 110%。其次,我们通过将 Vul-RAG 与基本的 GPT-4 以及结合代码级 RAG 增强的 GPT-4 进行比较,评估了漏洞知识的实用性。结果表明,Vul-RAG 在所有指标上均持续优于这两种基于 GPT-4 的变体。最后,我们进一步进行了有/无 Vul-RAG 生成的漏洞知识辅助下的漏洞检测用户研究。结果表明,漏洞知识可以将人工检测的准确率从 0.6 提升至 0.77,且用户反馈也显示生成的知识在帮助性、精确性和通用性方面具有高质量。总之,评估结果确认了所提出的知识级 RAG 框架的双重优势:(i) 通过更好地检索和利用现有漏洞知识增强自动化漏洞检测,以及 (ii) 通过提供对开发者友好的解释增强人工漏洞检测,以帮助理解漏洞或非漏洞代码。
总结
本文的主要贡献如下:
- 基准:我们构建了一个新基准数据集 PairVul,其中专门包含漏洞代码与看似相似但正确的代码对。
- 初步研究:我们首次发现现有的基于学习的技术在理解和捕捉与漏洞相关的代码语义方面能力有限。
- 技术:我们基于所提出的多维知识表示构建了一个漏洞知识库,并提出了一种新颖的知识级 RAG 框架 Vul-RAG 用于漏洞检测。
- 评估:我们评估了 Vul-RAG,并发现由 Vul-RAG 生成的漏洞知识在自动化和人工漏洞检测中均具有实用性。
2 背景
2.1 CVE 和 CWE
现有的漏洞分类系统,例如通用漏洞和暴露(CVE)[17] 和通用缺陷枚举(CWE)[18],为漏洞的分类和管理提供了全面的分类体系。CVE 是一个公开披露的常见安全漏洞列表,每个漏洞都被分配了一个唯一的标识符(CVE ID)。单个 CVE ID 可能与多个不同的代码片段相关联。
CWE 是一个公开访问的常见软件和硬件安全漏洞分类系统,其中每种缺陷类型都被分配了一个唯一的标识符(CWE ID)。尽管 CWE 提供了广泛的漏洞类型分类,但在特定 CWE 类别下导致漏洞的具体代码行为可能差异很大。例如,CWE-416(释放后使用)[19] 表示在内存被释放后引用该内存的问题。这一漏洞的根本原因可能源于竞争条件下的同步不当(例如 CVE-202330772 [20]),或引用计数错误导致对象过早销毁(例如 CVE-2023-3609 [21])。
2.2 基于学习的漏洞检测
深度学习的最新进展推动了许多基于学习的漏洞检测技术的发展。
- 基于图神经网络 (GNN) 的漏洞检测 [1–4] 通常将待检测的代码片段表示为基于图的中间表示形式,例如抽象语法树 (AST) 或控制流图 (CFG)。然后将图神经网络 (GNN) 应用于这些抽象的代码表示以提取特征。模型学习到的特征随后被输入二分类器进行漏洞检测。
- 基于预训练语言模型 (PLM) 的漏洞检测 [5, 6] 通常涉及在漏洞检测数据集上微调现有的 PLM。通过这种方式,代码片段被标记化并由预训练语言模型(PLM,例如 RoBERTa [22])处理,作为编码器。提取的特征随后用于二分类任务。
- 基于大型语言模型 (LLM) 的漏洞检测。此类方法利用大型语言模型(LLMs)通过提示工程或微调实现漏洞检测 [7–9]。前者利用不同的提示策略,例如链式思维(CoT)[12, 13] 和少量样本学习 [14, 23] 实现更准确的基于 LLM 的漏洞检测,而无需修改原始 LLM 参数;后者则通过对漏洞检测数据集进行训练来更新 LLM 参数,以学习漏洞代码的特征。
2.3 检索增强生成
检索增强生成(RAG)是一种通用范式,通过从外部数据库中检索相关信息并将其整合到输入中来增强 LLMs [24]。RAG 通常包括三个阶段:索引、检索和生成。首先,在索引阶段,从外部数据源构建外部数据库及其检索索引;其次,给定用户查询,检索系统利用这些索引获取相关文档片段作为上下文;第三,检索到的上下文被整合到 LLM 的输入提示中,LLMs 随后基于增强的输入生成最终输出。RAG 已被广泛应用于各个领域 [25–28]。例如,RAG 已被专门用于软件工程任务,如代码生成 [27, 28],通过从代码库中检索相似代码并将检索到的代码添加到提示中以进行模型推理。
3 初步研究
尽管现有的基于学习的漏洞检测技术显示出令人期待的效果,但由于深度学习模型的可解释性较弱,这些技术是否真正理解和捕捉到了与漏洞行为相关的代码语义仍然不清楚。为了填补这一知识空白,在本初步研究中,我们假设“如果某技术能够精准区分一对具有高词汇相似性的漏洞代码和非漏洞代码(即仅在少数标记上存在差异),我们认为该技术具备更好的捕捉与漏洞相关语义的能力”。
![![[Pasted image 20250324123123.png]]](/https://i-blog.csdnimg.cn/direct/a73309a87e084f07b1bdb0c914ec2d09.png)
如图 1 的示例所示,漏洞代码通过将语句 inet_frag_lru_add(nf, qp) 移入受锁保护的代码块得以修复,而这对漏洞代码和非漏洞代码虽然具有高词汇相似性,但在语义上存在差异。为此,我们首先提议构建一个基准数据集,其中包含漏洞代码及其对应的修补代码,因为修补代码通常与原始代码具有高度相似性;随后,我们在自建基准上评估现有的基于学习的技术,以研究它们对这类代码对的区分能力。
3.1 基准数据集 PairVul
为了进行初步研究,我们首先构建了一个新的基准数据集 PairVul,因为从现有的漏洞检测基准中准备漏洞代码和修补代码对既具有挑战性又耗时费力。
![![[Pasted image 20250324123140.png]]](/https://i-blog.csdnimg.cn/direct/a9c1c5966e144b2fb63962166155d4cd.png)
例如,表 1 显示了 2019 年 1 月至 2024 年 4 月期间发布的三个广泛使用的基准的详细统计数据,即 BigVul [16]、Devign [1] 和 Reveal [2]。最后一行展示了我们构建的基准数据集 PairVul 以供比较。具体而言,现有数据集并未专注于漏洞代码和修补代码对,例如,有些数据集不包含修补代码,而有些则包含与漏洞代码长度显著不同的非相似正确代码。因此,我们构建了一个新基准数据集 PairVul,专门包含漏洞代码和修补代码对。特别地,在本工作中,我们专注于函数级漏洞检测,因为它已在先前的基于学习的研究中被广泛探讨 [3–5, 29]。
数据格式
具体而言,我们的基准数据集为每个漏洞包含以下信息:
- CVE ID:分配给通用漏洞和暴露(CVE)系统中报告漏洞的唯一标识符。
- CVE 描述:CVE 系统提供的漏洞描述,包括漏洞的表现、潜在影响以及漏洞可能发生的环境。
- CWE ID:通用缺陷枚举(CWE)标识符,用于分类漏洞利用的类型。
- 漏洞代码:包含漏洞的源代码片段,将在提交中被修改。
- 修补代码:已提交的用于修复漏洞代码的源代码片段。
- 补丁差异:漏洞代码和修补代码之间的详细逐行差异,包括添加和删除的行。
构建过程
鉴于 Linux 内核在现代复杂软件系统中的代表性,我们使用 Linux 内核 CVE 作为基准数据的来源。具体的基准构建过程包括以下两个步骤:
-
漏洞代码和修补代码收集:我们首先从开源项目 Linux Kernel CVEs [30] 中收集所有与 Linux 内核相关的 CVE,该项目致力于自动跟踪上游 Linux 内核中的 CVE。基于收集到的 CVE ID 列表,我们进一步从国家漏洞数据库(NVD)中提取相应的 CWE ID 和 CVE 描述,以丰富我们的数据集,提供详细的漏洞分类和描述。基于 CVE ID 列表,我们解析每个 CVE 的提交信息,提取函数级的漏洞代码和修补代码对。提交差异前的漏洞代码片段被标记为正样本,修补代码片段被标记为负样本。通过这种方式,我们最初获得了涵盖 2,174 个 CVE 的 4,667 对函数级漏洞代码和修补代码的数据集。
-
修补代码验证:修补代码并不总是无漏洞的,因此验证修补代码的正确性非常重要。为此,我们进一步实施了一个过滤过程,确保修补代码未被其他提交回滚或修改。
基准统计
最终,我们得到了一个新的基准数据集 PairVul,其中包含来自 2,073 个 CVE 的 4,314 对函数级漏洞代码和修补代码。在本工作中,由于模型执行和人工分析的成本较高,我们重点关注基准中排名前五的 CWE 类别。特别地,由于本工作关注通常需要训练数据集的基于学习的技术,我们进一步将基准划分为训练集和测试集,具体步骤如下:对于每个 CVE,我们随机选择一个实例进入测试集,其余实例(如果有)进入训练集。我们排除了代码长度超过 GPT-3.5-turbo 当前令牌限制(即 16,384 个令牌)的情况。最终,训练集包含 896 个 CVE 和 1,462 对漏洞代码和修补代码函数,而测试集包含 373 个 CVE 和 592 对。我们基准中每个 CWE 类别的统计数据如表 2 所示。
![![[Pasted image 20250324123240.png]]](/https://i-blog.csdnimg.cn/direct/ad3b0d01237e44be935bb5f4a07363f6.png)
3.2 研究基线
我们在基准数据集 PairVul 上评估了以下最先进的(SOTA)漏洞检测技术:
- LLMAO [8]:一种基于 LLM 的故障定位方法,微调了 LLM(即 CodeGen),并进一步在 Devign 数据集上进行了微调以用于漏洞检测。
- LineVul [6]:一种基于 PLM 的漏洞检测模型,提供函数级和行级检测粒度。
- DeepDFA [3]:一种基于 GNN 的检测技术,采用数据流分析引导的图学习框架,专为函数级漏洞检测设计。
- Cppcheck [15]:一款广泛使用的开源静态分析工具。
我们直接使用所有基线的公开实现。为了使这些技术适应我们的基准,我们在训练集上对基于学习的基线进行了 10 个周期的微调。此外,由于 LLMAO 是一种行级漏洞检测技术,我们将其适配到函数级,将任何包含高于 0.5 可疑度评分的行的函数视为漏洞函数。
3.3 指标
为了进一步评估在区分具有高词汇相似性的漏洞代码和非漏洞代码对方面的能力,我们开发了一项新指标——配对准确率(pairwise accuracy),用于计算漏洞代码和修补代码均被正确识别的代码对比例。此外,我们还使用了漏洞检测任务中常用的六项指标,即 FN、FP、准确率、精确率、召回率和 F1 分数。FN 是假阴性的比例;FP 是假阳性的比例;准确率是正确检测实例的比例;精确率是所有阳性预测中真正阳性预测的比例;召回率是所有实例中真正阳性预测的比例;F1 分数是精确率和召回率的调和平均值,平衡了这两个值。
3.4 结果
![![[Pasted image 20250324123253.png]]](/https://i-blog.csdnimg.cn/direct/a985e1c915dd420696b79a8bebb048db.png)
如表 3 所示,现有技术在我们的基准数据集 PairVul 上表现出的效果有限。特别是,与先前基准报告的效果相比(例如,LineVul 在 BigVul [6] 上的准确率为 0.99),现有技术在 PairVul 上的表现明显较差(准确率范围为 0.50 至 0.54),甚至低于随机猜测的水平(即将所有实例识别为漏洞)。具体而言,配对准确率范围为 0.01 至 0.10,表明现有的基于学习的技术未能捕捉到相似漏洞代码和非漏洞代码之间的细微差异。这些观察结果表明,基于学习的模型在理解与漏洞相关的语义方面能力有限。
我们的见解
事实上,两个仅有细微词汇差异的代码片段可能具有不同的语义(即实现不同的功能)。因此,基于高级代码语义识别漏洞有助于更好地将漏洞代码与看似相似但正确的代码区分开来。特别地,根据开发者如何手动识别漏洞的观察,理解漏洞通常涉及三个维度的代码语义:(i) 代码实现的功能,(ii) 漏洞的成因,以及 (iii) 漏洞的修复方案。这种高级代码语义可以作为漏洞检测的知识依据。因此,在本工作中,我们提议通过增强 LLM 的高级漏洞知识来区分漏洞代码与看似相似但正确的代码。具体而言,我们首先利用 LLM 自动从现有的漏洞实例中构建漏洞知识库,然后进一步利用这些知识提升 LLM 在漏洞检测中的表现。
4 方法
4.1 概述
在本工作中,我们提出了一种基于 LLM 的新型漏洞检测技术 Vul-RAG,该技术利用知识级 RAG(检索增强生成)框架来检测给定代码中的漏洞。Vul-RAG 的核心思想是利用 LLM 基于现有漏洞的相似漏洞知识进行推理以实现漏洞检测。图 2 展示了我们方法的总体流程,包括以下三个阶段:
![![[Pasted image 20250324123333.png]]](/https://i-blog.csdnimg.cn/direct/5e4449620792459aaac064816ed0e595.png)
- 阶段 1:离线漏洞知识库构建(第 4.2 节):Vul-RAG 首先通过 LLM 从现有的 CVE 实例中提取多维知识,构建漏洞知识库。
- 阶段 2:在线漏洞知识检索(第 4.3 节):针对给定的代码片段,Vul-RAG 根据功能语义从构建的知识库中检索相关的漏洞知识。
- 阶段 3:在线知识增强漏洞检测(第 4.4 节):Vul-RAG 利用 LLM 通过对检索到的漏洞知识中的漏洞成因和修复方案进行推理,检查给定代码片段的漏洞。
4.2 漏洞知识库构建
为了全面总结漏洞,我们提出了一种三维表示的漏洞知识表示方法(第 4.2.1 节)。基于该知识表示方法,Vul-RAG 利用 LLM 从现有的 CVE 实例中提取相关漏洞知识,从而构建知识库(第 4.2.2 节)。
4.2.1 漏洞知识表示
![![[Pasted image 20250324123446.png]]](/https://i-blog.csdnimg.cn/direct/f5ec0f643725483d9b696ad2fc17807b.png)
Vul-RAG 从三个维度表示一个 CVE 实例的漏洞知识:功能语义、漏洞成因和修复方案。图 3 展示了 CVE-2022-38457 的三维表示示例。在此案例中,漏洞代码在 RCU 读锁上下文中访问共享数据结构时未使用适当的同步机制,导致竞争条件和释放后使用漏洞。为修复此漏洞,修补代码添加了一个自旋锁以保护共享数据结构。
-
功能语义:总结漏洞代码的高层次功能(即代码的作用),包括:
- 抽象目的:对代码意图的简要总结。
- 详细行为:对代码行为的详细描述。
-
漏洞成因:通过比较漏洞代码及其对应的补丁,描述触发漏洞行为的原因。我们考虑从不同角度描述的成因,包括:
- 抽象漏洞描述:对成因的简要总结。
- 详细漏洞描述:对成因的具体描述。
- 触发动作:直接触发漏洞的动作,例如图 3 中的“并发访问共享数据结构”。
-
修复方案:通过比较漏洞代码及其对应的补丁,总结漏洞的修复方法。
4.2.2 知识提取
对于每个现有的漏洞实例(即漏洞代码及其补丁),Vul-RAG 提示 LLM 提取三维知识,并对提取的知识进行抽象,以便形成更通用的表示。接下来,我们将详细解释每个步骤。
功能语义提取
给定漏洞代码片段,Vul-RAG 使用以下指令提示 LLM 分别总结其抽象目的和详细行为,其中占位符 [Vulnerable Code] 表示漏洞代码片段。
- 抽象目的提取提示:
[Vulnerable Code] 上述代码片段中函数的目的是什么?请用一句话总结答案,格式为:“函数目的:”。
Prompt for Abstract Purpose Extraction: [Vulnerable Code] What is the purpose of the function in the above code snippet? Please summarize the answer in one sentence with the following format: “Function purpose:”.
- 详细行为提取提示:
[Vulnerable Code] 请用列表形式总结上述代码片段的功能,无需其他解释:“代码片段的功能是:1. 2. 3...”
Prompt for Detailed Behavior Extraction: [Vulnerable Code] Please summarize the functions of the above code snippet in the list format without any other explanation: “The functions of the code snippet are: 1. 2. 3…”
图 3 展示了功能语义的示例输出。
漏洞成因与修复方案提取
由于漏洞成因和修复方案通常在逻辑上相互关联,Vul-RAG 将它们一起提取,以更好地利用 LLM 的推理能力。具体而言,Vul-RAG 采用两轮提取:第一轮要求 LLM 解释为什么需要修改漏洞代码片段;第二轮要求 LLM 基于第一轮生成的解释进一步总结漏洞成因和修复方案。这种两步策略基于链式思维(CoT)范式,通过分步思考激发 LLM 的推理能力,从而实现更好的提取效果 [12, 13, 31, 32]。此外,为了使 LLM 能够以适当格式总结成因和解决方案,Vul-RAG 结合少量样本学习,在输入长度有限的情况下包含两个漏洞成因和修复方案的示范示例。根据第 4.4 节概述的漏洞知识表示方法,我们手动构建了两个示例。详细的提示如下,其中占位符 [Vulnerable Code]、[Patched Code] 和 [Patch Diff] 分别表示漏洞代码、修补代码和给定漏洞的代码差异,而 [CVE ID] 和 [CVE Description] 表示给定漏洞的详细信息。
- 第一轮提取提示:
这是一个包含漏洞 [CVE ID] 的代码片段:[Vulnerable Code] 漏洞描述如下:[CVE Description] 正确的修复方法是通过 [Patch Diff] 修改后的代码如下:[Patched Code] 为什么上述修改是必要的?
Extraction Prompt in Round 1: This is a code snippet with a vulnerability [CVE ID]: [Vulnerable Code] The vulnerability is described as follows:[CVE Description] The correct way to fix it is by [Patch Diff] The code after modification is as follows: [Patched Code] Why is the above modification necessary?
- 第二轮提取提示:
我希望你作为一名漏洞检测专家,根据上述漏洞修复信息组织漏洞知识。请总结导致漏洞的代码行为以及修复漏洞的具体方法。以 JSON 格式整理你的发现。以下是引导你提取细节的示例: [漏洞成因与修复方案示例 1] [漏洞成因与修复方案示例 2]
Extraction Prompt in Round 2: I want you to act as a vulnerability detection expert and organize vulnerability knowledge based on the above vulnerability repair information. Please summarize the generalizable specific behavior of the code that leads to the vulnerability and the specific solution to fix it. Format your findings in JSON. Here are some examples to guide you on the level of detail expected in your extraction: [Vulnerability Causes and Fixing Solution Example 1] [Vulnerability Causes and Fixing Solution Example 2]
知识抽象
不同的漏洞实例可能共享共同的高层次知识(例如相似的成因和修复方案),因此对提取的漏洞知识中的高层次共性进行抽象可以进一步提炼出更通用的知识表示,减少与具体代码实现细节的绑定。
为此,Vul-RAG 利用 LLM 对提取的漏洞成因和修复方案中的以下具体代码元素(即方法调用、变量名和类型)进行高层次抽象。我们不对功能语义进行抽象,因为它仅在检索阶段使用,在漏洞检测过程中不会作为增强知识提供给 LLM。接下来,我们将描述知识抽象的指导原则和示例。
- 抽象方法调用:提取的知识可能包含带有详细函数标识符(例如
io_worker_handle_work函数)和参数(例如mutex_lock(&dmxdev->mutex))的具体方法调用,这些可以被抽象为更通用的描述(例如“在处理 IO 工作流程期间”和“采用类似于mutex_lock()的锁定机制”)。
Abstracting Method Invocations. The extracted knowledge might contain concrete method invocations with detailed function identifiers (e.g., io_worker_handle_work function) and parameters (e.g., mutex_lock(&dmxdev->mutex)), which can be abstracted into the generalized description (e.g., “during handling of IO work processes” and “employing a locking mechanism akin to mutex_lock()”).
- 抽象变量名和类型:提取的知识可能包含具体的变量名或类型(例如“未初始化
&dev->ref”),这些可以被抽象为更通用的描述(例如“未正确初始化引用计数器”)。
Abstracting Variable Names and Types. The extracted knowledge might contain concrete variable names or types (e.g., “without &dev->ref initialization”), which can be abstracted into the more general description (e.g., “without proper reference counter initialization”).
Vul-RAG 使用以下提示来利用 LLM 进行知识抽象,要求 LLM 抽象方法调用和变量名。
知识抽象提示:
基于前一阶段提取的详细漏洞知识,您的任务是对这些知识进行抽象和概括,以增强其在不同场景中的适用性。请遵循以下提供的指导原则和示例:
[知识抽象指导原则和示例] ...
Prompt for Knowledge Abstraction: With the detailed vulnerability knowledge extracted from the previous stage, your task is to abstract and generalize this knowledge to enhance its applicability across different scenarios. Please adhere to the following guidelines and examples provided: [Knowledge Abstraction Guidelines and Examples] …
最终输出是每个漏洞实例的三维知识(即表示为一个知识项)。特别地,给定一组现有的漏洞实例(即从第 3.1 节提到的 PairVul 构建的训练集),我们对每个漏洞实例重复提取过程,并将所有实例提取的知识项聚合为最终的漏洞知识库。
4.3 漏洞知识检索
对于给定的漏洞检测代码片段,Vul-RAG 通过三步检索过程从构建的漏洞知识库中检索相关漏洞知识项:查询生成、候选知识检索和候选知识重排序。
查询生成
Vul-RAG 不仅依赖代码作为检索查询,还结合代码及其功能语义作为多维查询。首先,Vul-RAG 提示 LLM 提取给定代码的功能语义,如知识库构建部分所述(第 4.2.2 节)。抽象目的、详细行为以及代码本身共同构成后续检索的查询。
候选知识检索
Vul-RAG 使用基于相似性的检索方法,利用三个查询元素:代码、抽象目的和详细行为。它分别针对每个查询元素检索排名前 n(在我们的实验中 n = 10)的知识项。因此,Vul-RAG 总共检索到 10 至 30 个候选知识项(考虑到不同查询元素检索到的知识项之间可能存在重复)。检索基于每个查询元素与知识项对应元素之间的相似性。Vul-RAG 采用 BM25 [33] 进行相似性计算,这是一种因高效性和有效性而广泛应用于搜索引擎的方法 [11]。给定查询 q 和用于检索的文档 d,BM25 根据以下公式 1 计算 q 和 d 之间的相似性得分,其中 f(wi,q)f(w_i, q)f(wi,q) 是词 wiw_iwi 在查询 q 中的词频,IDF(wi)IDF(w_i)IDF(wi) 是词 wiw_iwi 的逆文档频率。超参数 k 和 b(其中 k=1.2,b=0.75)用于归一化词频并控制文档长度的影响。在计算 BM25 相似性之前,查询和检索文档都经过标准预处理步骤,包括分词、词形还原和停用词移除 [34]。
SimBM25(q,d)=∑i=1nIDF(wi)×f(wi,q)×(k+1)f(wi,q)+k×(1-b+b×∣q∣avgdl)Sim_{BM25}(q, d) = \sum_{i=1}^{n} \frac{IDF(w_i) \times f(w_i, q) \times (k + 1)}{f(w_i, q) + k \times \left(\text{1-b} + b \times \frac{|q|}{avgdl}\right)}SimBM25(q,d)=i=1∑nf(wi,q)+k×(1-b+b×avgdl∣q∣)IDF(wi)×f(wi,q)×(k+1)
候选知识重排序
我们使用倒数排名融合(RRF)策略对候选知识项进行重排序。对于每个检索到的知识项 k,我们通过汇总其在所有三个查询元素中的排名倒数来计算其重排序得分。如果某个知识项 k 未被特定查询元素检索到,则将其排名设为无穷大。知识项 k 的重排序得分根据以下公式 2 计算。E 表示所有查询元素的集合(即代码、抽象目的和详细行为),rankt(k)rank_t(k)rankt(k) 表示基于查询元素 t 的知识项 k 的排名。
ReRankScorek=∑t∈E1rankt(k)ReRankScore_k = \sum_{t \in E} \frac{1}{rank_t(k)}ReRankScorek=t∈E∑rankt(k)1
最终,我们获得重排序得分最高的前 10 个候选知识项,作为提供给 LLM 进行漏洞检测的最终知识项。
4.4 知识增强漏洞检测
基于检索到的知识项,Vul-RAG 利用 LLM 推理给定代码是否具有漏洞。然而,直接将所有检索到的知识项整合到一个提示中可能会降低模型的效果,因为 LLM 在处理冗长上下文时通常表现不佳 [35]。因此,Vul-RAG 通过迭代方式利用每个检索到的知识项,依次检查给定代码是否表现出相同的漏洞成因或修复方案。如果给定代码表现出与知识项相同的漏洞成因但缺乏相关的修复方案,则被识别为漏洞代码;否则,Vul-RAG 无法通过当前知识项识别代码为漏洞,并进入下一次迭代(即使用下一个检索到的知识项)。如果代码无法通过任何检索到的知识项被识别为漏洞,则最终被识别为非漏洞代码。迭代过程在以下两种情况下终止:(i) 代码被识别为漏洞代码,或 (ii) 所有检索到的知识项均已考虑完毕。特别地,用于识别漏洞成因和修复方案的提示如下:
寻找漏洞成因的提示:
给定以下代码及相关漏洞成因,请检测代码中是否存在漏洞成因。[代码片段]。在类似代码场景中,发现了以下漏洞:[漏洞成因][修复方案]。请结合您对漏洞的知识以及上述漏洞知识,检测代码中是否存在漏洞。
Prompt for Finding Vulnerability Causes: Given the following code and related vulnerability causes, please detect if there is a vulnerability cause in the code. [Code Snippet]. In a similar code scenario, the following vulnerabilities have been found: [Vulnerability causes][fixing solutions]. Please use your own knowledge of vulnerabilities and the above vulnerability knowledge to detect whether there is a vulnerability in the code.
寻找修复方案的提示:
给定以下代码及相关漏洞修复方案,请检测代码中是否存在漏洞。[代码片段]。在类似代码场景中,发现了以下漏洞:[漏洞成因][修复方案]。请结合您对漏洞的知识以及上述漏洞知识,检测代码中是否存在相应的修复方案。
Prompt for Finding Fixing Solutions: Given the following code and related vulnerability fixing solutions, please detect if there is a vulnerability in the code. [Code Snippet]. In a similar code scenario, the following vulnerabilities have been found: [Vulnerability causes][fixing solutions]. Please use your own knowledge of vulnerabilities and the above vulnerability knowledge to detect whether there is a corresponding fixing solution in the code.
5 评估设置
我们通过回答以下四个研究问题来评估 Vul-RAG 的有效性和实用性:
- RQ1:与 SOTA 技术相比:Vul-RAG 与最先进的(SOTA)漏洞检测技术相比表现如何?
- RQ2:与基于 GPT-4 的技术相比:Vul-RAG 与基于 GPT-4 的检测技术相比表现如何?
- RQ3:对开发者的实用性:Vul-RAG 生成的漏洞知识能否帮助开发者进行人工漏洞检测?
- RQ4:失败案例分析:为什么 Vul-RAG 在检测某些漏洞时会失败?
5.1 实现
我们在 GPT 系列模型的基础上构建了 Vul-RAG。具体而言,在离线知识库构建阶段,由于需要生成大量漏洞知识项,我们使用 gpt-3.5-turbo-0125 模型 [36],因为它响应迅速且成本效益高 [11];在在线知识增强检测阶段,我们使用 GPT-4 模型 [37],因为它目前是效果最佳的 LLM 之一,具有卓越的理解和逻辑推理能力 [38]。对于知识检索过程,我们使用 Elasticsearch [39] 作为搜索引擎,它基于 Lucene 库并采用 BM25 作为默认评分函数。
6 结果
6.1 RQ1:与 SOTA 技术相比
在 RQ1 中,我们在初步研究(第 3 节)的相同设置下评估 Vul-RAG,包括相同的基准数据集(即 PairVul)、相同的指标和相同的基线(即 LLMAO、LineVul、DeepDFA 和 Cppcheck)。由于篇幅限制,我们不再重复基线结果(先前已在表 3 中展示),而是将 Vul-RAG 的结果展示在表 4 中。
![![[Pasted image 20250324124347.png]]](/https://i-blog.csdnimg.cn/direct/24e5af90b026421e9d87bd0e10ad4eeb.png)
基于两张表的结果,我们得出以下发现:
首先,Vul-RAG 在所有基线中实现了最高的准确率(即 0.61)和配对准确率(0.21),相对最佳基线 LLMAO 分别提升了 12.96% 和 110%。配对准确率的显著提升表明 Vul-RAG 在区分漏洞代码和看似相似但正确的代码方面具有优势。
此外,Vul-RAG 在召回率和精确率之间实现了最佳权衡,这两项指标均为 0.61。虽然这些分数并非单独最高,但其他在某一项指标上得分更高的基线往往在另一项指标上表现不足。例如,召回率最高的 LineVul(0.87)倾向于将大多数代码预测为漏洞,导致其精确率仅为 0.50(与随机猜测相同)。特别地,我们认为 F1 指标在我们的基准中实际意义有限,因为随机猜测达到了最高的 F1 值(召回率为 1.0,精确率为 0.5)。然而,建议所有代码均为漏洞对开发者实际帮助有限。尽管如此,所有技术的整体有限效果表明捕捉细微语义差异非常具有挑战性,这需要未来工作更多关注。
6.2 RQ2:与基于 GPT-4 的技术相比
RQ2 通过将 Vul-RAG 与两个基于 GPT-4 的基线进行比较,评估知识级 RAG 框架的实用性。
6.2.1 基线
- 基础 GPT-4:直接查询 GPT-4 进行漏洞检测,提示设计如图 4(a) 所示。这表明了 GPT-4 在漏洞检测中的基本能力。
- 基于代码的 RAG:通过从训练数据集中检索相似代码片段增强基础 GPT-4,提示设计详见图 4(b)。将 Vul-RAG 与此基线进行比较可以研究知识级 RAG 相较于代码级 RAG 的贡献。
![![[Pasted image 20250324124447.png]]](/https://i-blog.csdnimg.cn/direct/a370b06c82fe49c3a3c88ccb9ba775e6.png)
6.2.2 结果
表 4 展示了 Vul-RAG 与两个基于 GPT-4 的基线之间的比较。总体而言,Vul-RAG 在所有指标上均持续优于两个基线,证明了我们知识级 RAG 框架的有效性。具体而言,我们使用两个 Vul-RAG 能成功检测但两个基线无法检测的示例,解释 Vul-RAG 相较于两个基线的优势。
知识表示:图 4 展示了一个示例,说明了我们知识表示的优势。在检测来自 CVE-2023-30772 的给定代码时,基础 GPT-4 未能识别漏洞的真实原因(如图 4(A) 所示)。GPT-4 错误地建议“platform_get_irq_byname()”缺少返回值检查可能导致漏洞,而此处并不需要这种检查。然而,它忽略了真正的问题,即异步事件处理不当导致竞争条件,进而引发释放后使用漏洞。这种误解延续到 GPT-4 检测对应的修补代码时,导致假阳性并影响配对准确率。增强 GPT-4 的基于代码的 RAG 同样未能检测漏洞。如图 4(B) 所示,尽管检索到的代码对具有相似的功能语义和漏洞成因,GPT-4 仍然难以将检索到的源代码中隐含的漏洞知识与目标代码关联起来。相比之下,提供我们方法 Vul-RAG 提炼的高级漏洞知识后,GPT-4 不仅成功检测到漏洞代码的根本原因,还准确识别了修补代码(图 4©)。这一对比表明,高级漏洞知识可以有效帮助 LLM 理解漏洞代码的行为,从而提高漏洞检测的准确性。
![![[Pasted image 20250324124458.png]]](/https://i-blog.csdnimg.cn/direct/03542ada4a7041eeb74948b9a954fe79.png)
检索策略:图 5 比较了基于代码检索(即仅通过代码片段检索)和我们的检索策略(即通过代码片段和提取的功能语义检索)对给定代码片段的检索结果。如图 5 所示,在检测来自 CVE-2023-1989 的给定代码片段时,基于代码的检索找到一个代码片段(来自 CVE-2021-33034),它与目标代码共享更多操作资源(黄色高亮),但在功能语义上存在显著差异,导致漏洞的根本原因不同。相比之下,我们的检索策略找到一个代码片段(来自 CVE-2023-1855),它与目标代码具有更高的语义相似性(绿色高亮)。此外,它们具有相同的漏洞根本原因,即在设备移除过程中未能充分处理异步事件。这表明我们的检索策略可以帮助 LLM 找到具有更相似漏洞成因的代码对。
6.3 RQ3:对开发者的实用性
在 RQ3 中,我们进行了一项用户研究,以调查 Vul-RAG 生成的漏洞知识是否能够帮助开发者更精确地识别漏洞代码。
6.3.1 用户研究方法
任务
我们从基准数据集 PairVul 中选择了 10 个案例用于用户研究。具体而言,我们从 PairVul 的五个 CWE 类别中随机选择两个案例,包括真正阳性(即确实存在漏洞的代码片段)和假阳性(即被 Vul-RAG 错误预测为漏洞的正确代码片段)。为确保评估的平衡性,我们将每个 CWE 类别的两个案例随机分配到两个相等的组(TA 和 TB),每组包含 5 个案例。
参与者
我们邀请了 6 名具有 3-5 年 C/C++ 编程经验的参与者参与用户研究。我们通过预实验调查了他们的 C/C++ 编程专业知识,并基于此将他们分为两组(GA 和 GB),两组的专业知识分布相似。
流程
每位参与者需要识别给定代码片段是否存在漏洞。为了进行比较,参与者在两种设置下完成任务:(i) 基础设置:仅提供代码片段和 Vul-RAG 生成的检测标签;(ii) 知识辅助设置:提供代码片段、Vul-RAG 生成的检测标签以及 Vul-RAG 生成的漏洞知识。特别地,GA 组的参与者在 TA 组中使用知识辅助设置,在 TB 组中使用基础设置;反之,GB 组的参与者在 TA 组中使用基础设置,在 TB 组中使用知识辅助设置。除了记录每位参与者的输出(即是否存在漏洞),我们还对参与者进行了关于漏洞知识的帮助性、精确性和通用性的调查,采用 4 点李克特量表 [40](即 1-不同意;2-部分不同意;3-部分同意;4-同意)评分,具体内容如下:
- 帮助性:Vul-RAG 提供的漏洞知识有助于理解漏洞并验证检测标签。
- 精确性:漏洞知识提供了精确且详细的漏洞描述,避免过于笼统的叙述无法充分识别根本原因。
- 通用性:漏洞知识保持了一定的通用适用性,避免过于具体的描述降低其广泛实用性(例如,过度依赖源代码中的变量名的叙述)。
6.3.2 结果
与基础设置相比,使用 Vul-RAG 生成的漏洞知识的参与者能够更精确地识别漏洞代码和非漏洞代码(即知识辅助设置下的检测准确率为 77%,而无知识辅助设置下的检测准确率为 60%)。这表明 Vul-RAG 生成的漏洞知识确实有助于开发者更好地理解给定代码中的语义和漏洞。此外,根据调查反馈,参与者对帮助性、精确性和通用性的平均评分分别为 3.00、3.20 和 2.97。这些结果进一步表明了 Vul-RAG 生成的漏洞知识的高质量和实用性。
6.4 RQ4:失败案例分析
为了了解 Vul-RAG 的局限性,我们进一步手动分析了错误案例(即 Vul-RAG 报告的假阴性和假阳性)。特别地,我们对手动分析了来自 CWE-119 的所有 19 个假阴性和 21 个假阳性案例。表 5 总结了这些案例的原因及其分布。
![![[Pasted image 20250324124535.png]]](/https://i-blog.csdnimg.cn/direct/6f9d1776570a4471904c34a519b28adc.png)
假阴性的原因
假阴性的原因主要分为以下三类:
- 不准确的漏洞知识描述:我们观察到,在 5 个案例(26.3%)中,Vul-RAG 成功检索到了相关的漏洞知识,但由于知识描述不精确而未能检测到漏洞。例如,对于 CVE-2021-4204 的漏洞代码片段,尽管 Vul-RAG 成功检索到了同一 CVE 的相关知识,但由于漏洞知识描述模糊(即仅简要提到“缺乏适当的边界检查”,未明确说明应执行何种边界检查),导致了假阴性。
- 未检索到相关漏洞知识:我们观察到,在 2 个案例(15.8%)中,Vul-RAG 未能检索到相关漏洞知识,从而导致假阴性。虽然知识库中存在与给定代码具有相似漏洞根本原因和修复方案的实例,但它们的功能语义差异显著,因此 Vul-RAG 未能从知识库中检索到它们。
- 不存在相关漏洞知识:根据我们的手动检查,12 个案例(63.2%)属于此类。即使知识库中存在同一 CVE 的其他漏洞代码和修补代码对,其漏洞行为和修复方案也不同,使得这些案例无法通过当前知识库解决。这一限制是基于 RAG 框架的固有特性。在未来工作中,我们将通过提取更多 CVE 信息来扩展知识库,以缓解这一问题。
假阳性的原因
假阳性的原因可分为以下两类:
-
不匹配的修复方案:在 11 个案例(52.4%)中,尽管 Vul-RAG 成功检索到了相关漏洞知识,但代码片段仍被视为漏洞,因为未应用检索到的知识中的修复方案。这是因为一个漏洞可能有多种替代修复方案。
-
无关漏洞知识检索:在 10 个案例(47.6%)中,假阳性是由 Vul-RAG 检索到无关漏洞知识引起的。根据我们的手动检查,这些错误检索的知识描述通常过于笼统,例如“缺少对特定值的适当验证”,这对 GPT-4 精确识别漏洞造成了困难。
7 对有效性的威胁
基准数据集中的威胁:漏洞基准数据集与 GPT-4 的训练数据之间可能存在潜在的数据泄露问题。然而,Vul-RAG 相较于基础 GPT-4 的显著改进表明,Vul-RAG 的有效性并非仅仅源于对数据的记忆。
泛化性中的威胁:由于 Linux 内核 CVE 的普遍性和丰富的漏洞信息 [41],我们的基准数据集专注于 Linux 内核 CVE,这可能限制了结果的泛化性。然而,我们的方法并不局限于 Linux 内核 CVE,并且未来可以扩展到其他系统的 CVE。此外,Vul-RAG 的另一个泛化性问题出现在构建的知识库中未包含与待检测代码相关的知识时,这引发了关于提取的漏洞知识是否能够泛化以检测来自不同 CVE 的代码片段的担忧。为了缓解这一威胁,我们手动编译了一个小规模基准数据集,包含 30 个独特 CVE 的 60 个代码函数(30 个正样本和 30 个负样本)。对于该基准中的每个案例,我们手动验证知识库中是否存在从其他 CVE 提取的相关漏洞知识。Vul-RAG 在该基准上的性能(即召回率为 0.83,精确率为 0.76)证明了提取的漏洞知识在不同 CVE 中的泛化能力。
8 相关工作
基于深度学习的漏洞检测:大多数基于深度学习的研究主要利用图神经网络(GNN)模型和预训练语言模型(PLM)进行漏洞检测。Devign [1] 使用 GNN 高效提取联合图中的有用特征;REVEAL [2] 将函数级代码概念化为代码属性图(CPG),并使用 GGNN 进行 CPG 嵌入。VulChecker [4] 使用程序切片和消息传递 GNN 精确定位代码中的漏洞并分类其类型(CWE)。DeepDFA [3] 使用数据流分析引导的图学习框架模拟数据流计算。对于基于 PLM 的漏洞检测,VulBERTa [5] 使用 RoBERTa 模型 [22] 作为编码器,而 Linevul [6] 使用注意力得分进行行级预测。
基于 LLM 的漏洞检测:Wu 等人 [42] 和 Zhou 等人 [43] 探讨了 ChatGPT 在软件安全应用中的有效性和局限性;Gao 等人 [44] 构建了一个全面的漏洞基准 VulBench,用于评估 16 种 LLM 在漏洞检测中的有效性。Zhang 等人 [7] 研究了各种提示以改进 ChatGPT 在漏洞检测中的表现。Yang 等人 [8] 和 Shestov 等人 [9] 微调 LLM 以进行漏洞检测。此外,Li 等人 [10] 和 Sun 等人 [11] 将 LLM 与静态分析相结合以进行漏洞检测。Wang 等人 [45] 使用基于 LLM 的意图推断增强静态分析以检测资源泄漏。据我们所知,我们是首个基于知识级 RAG 框架的漏洞检测技术。此外,我们还首次尝试评估现有技术在区分漏洞代码和看似相似但无害代码方面的能力。
9 结论
在本工作中,我们提出了一种基于 LLM 的新型漏洞检测技术 Vul-RAG,该技术利用知识级检索增强生成(RAG)框架检测给定代码中的漏洞。总体而言,与四种代表性基线相比,Vul-RAG 显示出显著改进(即准确率提升 12.96%,配对准确率提升 110%)。我们的用户研究结果表明,漏洞知识可以将人工检测的准确率从 0.6 提升至 0.77,用户反馈也显示生成的知识在帮助性、精确性和通用性方面的高质量。

1844

被折叠的 条评论
为什么被折叠?



