admin管理员组

文章数量:1630184

LLM 4 Vulnerability Detection

  • 1.InferROI
    • 1.1.introduction
    • 1.2.motivation
    • 1.3.Approach
    • 1.4.Evaluation
      • 1.4.1.RQ1.Effectiveness in Intention Inference
    • 1.4.2.RQ2.Resource Leak Detection
      • 1.4.3.RQ3.Open-Source Project Scanning
      • 1.4.4.RQ4.Ablation Study
    • 1.5.Discussion
  • 2.Latte
    • 2.1.Motivation
    • 2.2.Approach
      • 2.2.1.Function Chain Generation
      • 2.2.2.Dangerous Flow Generation
      • 2.2.3.Prompt Sequence Construction
    • 2.3.Evaluation
      • 2.3.1.RQ1.Latte漏洞检测性能
      • 2.3.2.SSF和EIS识别(source-sink识别)准确度
      • 2.3.3.RQ3.Dangerous Flow提取精度
      • 2.3.4.RQ4.Real world漏洞检查
    • 2.4.Discussion
  • 3.GPTScan
    • 3.1.Motivation
    • 3.2.Overview and Challenge
    • 3.3.Function Matching & Static Confirmation
  • 4.Lara
    • 4.1.Introduction
    • 4.2.Approach
      • 4.2.1.模式匹配
      • 4.2.2.LLM-aided Analysis

1.InferROI

paper地址

1.1.introduction

Issues:

  • Resource Acquisition/Release APIs的完全性以及漏报问题:现有resource leak的检测方式依赖于与定义API pair的完全性, 但FindBugs, Infer, CodeInspection只支持resource leak api的一个子集合。 因此,特定api相关 (AndroidHttpClient) 会被漏报。

  • Resource可达性分析以及误报问题:在现有的检测技术中,在CFG上分析resource reachability会有误报发生。Torlak通过空指针条件判断(cur != null)分析resource accessibility。然而,这种方法对于其它情况 (!bank.isDisabled)就不太适用,同时,误报在一些不可达路径也会被触发。

  • 现有检测范式的复杂程度:以定位CFG路径中的一些预定义的API对(例如,Socket 申请和释放)为核心的检测范式,由于其固有的复杂性,面临着重大挑战。某些技术进行了不必要的跨函数控制流分析并追踪调用链。这可能会极大地增加路径分析的难度,尤其是考虑到跨过程控制流分析的不精确性。

solutions:结合资源管理知识以及代码上下文理解推断资源操作 (resource acquistion/release, 可达性验证)。在接收到代码片段时,InferROI使用一个prompt template来引导LLM推断涉及的resource acquistion/release意图,从而消除了对资源API对的预定义需求。

LLM

  • 生成自然语言的输出,随后被解析成意图的形式表达。

  • 通过汇总这些推断出的意图,InferROI继续实施基于轻量级静态分析的算法,分析从代码中提取的CFG路径,实现对资源泄漏的检测。该算法考虑了沿着个别CFG路径进行的资源获取和释放,以找到潜在的泄漏。然后,它考虑了这些路径上资源可达性对兄弟分支的影响,减轻了误报,提高了泄漏检测的精度。

Evaluation Summary:

InferROI基于Java实现,这项研究采用了DroidLeaks数据集,其中包含了86个Android应用程序中的漏洞,产生了172个(2 × 86)代码片段,包括有漏洞版本和修复版本。为了评估InferROI在推断面向资源的意图和检测资源泄漏方面的性能,进行了以下实验:

  1. 意图推断Evaluation: 手动对代码片段中的资源意图进行了注释,并使用InferROI进行意图推断。结果表明,InferROI在意图推断方面取得了74.6%的精度和81.8%的召回率,同时在DroidLeaks中列出的28个Android资源中达到了67.9%的覆盖率。

  2. 资源泄漏检测Evaluation: 在172个代码片段上应用InferROI进行资源泄漏检测。在有漏洞版本的代码片段中,InferROI实现了相对较高的漏洞检测率(53.5%),而基线方法的检测率为3.4%56.9%。在修复版本的代码片段中,InferROI产生了较低的误报率(8.1%),而基线方法的误报率为0%41.8%。

  3. 开源项目资源检测Evaluation: 将InferROI应用于真实的开源项目,对100个方法进行资源泄漏检测。实验结果显示,InferROI检测到了12个未知的资源泄漏,其中7个在提交时已被开发人员确认。

1.2.motivation

  • HttpClient.newInstance(mUserAgent) 申请了http client资源。

  • 在bug版本中 HttpClient.close() 没有被调用。

识别这个resource leak存在以下难点:

  • 更全面地识别资源获取/释放操作: 在上述例子中,与 AndroidHttpClient 类相关的资源泄漏在DroidLeaks数据集中所评估的8个检测器均未被检测到。除了 AndroidHttpClient 之外,其它库/包中也实现相关http调用api。例如,在selenium库中,存在类似 HttpClientJdkHttpClientNettyClient等相关API。在DroidLeaks中评估的8个检测器也未能检测到所有这些API的资源泄漏。这种失败可以归因于检测器无法把握这些API共享的基本共同特征,这些特征本质上代表相同的资源概念,即HTTP客户端及其使用。

  • 更全面地进行资源可达性验证:资源可达性的验证是确定资源泄漏发生的关键因素。在修复版本中,第185行的 if 条件用于在其在第186行释放之前验证获取的HTTP客户端资源的可达性。如果忽略了用于可达性验证的这个 if 条件,将在 if 语句的 false 分支中触发误报,实际上获取的资源是不可达的。现有的检测技术,通常通过匹配空值检查条件来识别可达性验证。但有的API,比如 isDisabled(), isClose() 有等价功能。

  • 降低检测过程中程序分析的复杂性:现有的检测技术需要复杂的过程间分析技术来进行长距离调用链下的resource leak分析。比如 AndroidHttpClient 的资源分配通常封装了socket API。这其中涉及了复杂了调用链。通过推断封装关系,可以减少跨函数分析。示例中,如果能识别 AndroidHttpClient.newInstance 直接申请了资源就不需要深入调用链。

1.3.Approach

  1. Resource-Oriented Intentions

通常资源泄漏会涉及以下操作

  • Resource Acquisition:可以通过acquire(var, lineno) 表示,var 表明获取的资源,lineno 表示语句行号。上图代码可以表示为 acquire(client, 167)

  • Resource Release:释放资源操作,可以通过 release(var, lineno) 表示。上图代码可以表示为 release(client, 186)

  • Resource Reachability Validation:表明获取的资源是否可达(是否不为 null),可以通过 validate(var, lineno) 表示。上图代码可以表示为 release(client, 185)

  1. Intention Inference

根据以下prompt template输入LLM获取初始分析结果,随后提取formal expression

Task Description

Analyze the information about resource leaks in the provided code snippet
below. First, resolve the types of the involved objects. Then, identify the types
representing leakable resources. Next, identify the API/method calls for
acquiring the resources. After that, identify the API/method calls for releasing
the acquired resources. Finally, identify the if-conditions for checking whether
the acquired resources are closed or unclosed

Output format:

Desired format:
Leakable Resources:
<resource type>: <resource variable>

API/method Calls for Acquiring Resources:
line <line number>: `<API call>` acquires `<resource variable>` resource

API/method Calls for Releasing Resources:
line <line number>: `<API call>` releases `<resource variable>` resource

If-conditions for Checking Resources closed or not:
line <line number> `<if-condition>` checks `<resource variable>` resource

Code PlaceHolder:

Code Snippet: `java
{CODE}
``

Answer of GPT4:

Leakable Resources:
AndroidHttpClient: client

API/method Calls for Acquiring Resources:
line 167: `AndroidHttpClient.newInstance(mUserAgent)` acquires `client`
resource

API/method Calls for Releasing Resources:
line 185: `client.close()` releases `client` resource

If-conditions for Checking Resources closed or not:
line 186: `if (client != null)` checks `client` resource

随后,使用正则表达式解析GPT的Answer,从 "line <line number>: <API call> acquires <resource variable> resource 这样的字眼中提取 line number, API call, resource variable。基于以上信息可以提取到 acquire(client, 167), release(client, 185), validate(client, 186)

  1. Static Resource Leak Detection

通过轻量级静态CFG分析结合formal expression推测漏洞。

给定一个method-level的AST,作者遍历AST构建CFG,随后遍历entry到exit的路径,作者提出了2种策略修剪。

  • Loop:Loop的 true 分支对应的路径只会遍历一次。

  • Resource independent branch:对于 if 语句和 switch 语句,检查其分支条件是否无关于resource获取/释放并且不包含退出操作(return 语句)。如果这些条件满足,那么只保留一个分支,因为其它分支可能具有相同的resource行为。这个检查操作会基于formal expression进行。

上面代码中,解析出来的CFG path包括 [160-185, 186, 187-190], [160-185, 187-190]。

随后基于path进行resource leak检测。

  • 第一阶段是单路径分析,根据 acquirerelease意图初步识别相关资源的泄露风险路径。

  • 第二阶段是跨路径分析,通过识别 validate 意图消除引入误报的路径。这部分insight在于假如有一个 if 语句判断资源是否为 null,不为 null 则释放资源。那么在 false branch 就不会有释放资源的操作,这时 false branch 就会发生误报。因此需要通过 validate 意图识别消除这种 false branch 误报。

  • 完成两个阶段后,该算法检查是否存在具有相应 true 状态的路径。如果存在这样的路径,则报告 res 的资源泄露。

def LeakDetection(res, paths: Set[Path], intention_sets):
	'''
	res: concerned paths
	paths: CFG paths
	intention_sets: formal expressions of intention set
	'''

	# 单路径分析,标记潜在leak路径
	for path in paths:
	    rd_counter = 0
	    for node in path:
		    ln = get_line_number(node) # 获取该node对应的行号
		    if acquire(res, ln) in intention_sets: # 如果ln申请了对应资源
		        rd_counter += 1
		    elif release(res, ln) in intention_sets: # 如果释放了资源
			    red_counter -= 1
		if rd_counter > 0:
			path.risky = True
		else:
			path.risky = False

	# 跨路径分析,消除误报
	if_stmts = get_all_if_stmts(paths) # 获取路径集合中所有的if语句
	sort_stmts_in_line_number(if_stmts) # 按行号排序
	for if_stmt in if_stmts:
		ln = get_line_number(if_stmt)
		# 如果不是validate操作
		if not validate(res, ln) in intention_sets:
			continue
		G_prefix: Set[path] = group_paths_containing_if(if_stmt) # 提取所有包含validate if stmt的路径,set中的每一个元素为一个路径前缀
		for g in G_prefix:
			B1, B2 = group_paths_by_branches_of_if(if_stmt)
			propagate(B1, B2)

    # report leak
    for path in paths:
	    if path.risky:
		    report_leak(path, res)


def propagate(B1: Set[path], B2: Set[path]):
	if all([path.risky for path in B1]) and (not any([path.risky for path in B2])):
		for path in B1:
			path.risky = False
	elif all([path.risky for path in B2]) and (not any([path.risky for path in B1])):
		for path in B2:
			path.risky = False

在示例的fix版本中,InferROI在第一阶段识别leak路径: [160-185, 187-190],但是在第二阶段,其对应的 true 分支不存在泄漏,因此被识别为误报被消除。

对于 try-with-resources 语句,作者实现了一个基于规则的后处理方法。

1.4.Evaluation

1.4.1.RQ1.Effectiveness in Intention Inference

这部分主要研究InferROI识别resource-oriented操作的准确率。作者从DroidLeak数据集中选取了86个bug,算上fix版本总共172个代码片段,包含28种不同的资源类型,比如 CursorInputStream。其中两位作者手动在172个代码片段上标注3种操作 (acquire, validate, release)。最后,InferROI取得了74.6%的precision和81.8%的recall。

下表反映了28种资源类型中不同检测器可以识别的数量,可以看到InferROI最多。

Detector覆盖的资源类型数量
Code Inspection16 (57.1%)
Infer11 (39.3%)
Lint3 (10.7%)
FindBugs9 (32.1%)
Relda2-FS6 (21.4%)
RElda2-FI6 (21.4%)
Elite2 (7.1%)
Verifier2 (7.1%)
InferROI19 (67.9%)

不过,像 Camera 以及 MediaPlayer 并没有被成功识别。这类resource通常由Android lifecycle管理。

InferROI优势:

  • 通过代码理解能力进行资源操作识别,因此,像 AndroidHttpClient 都能被提取。

  • prompt也扮演了重要角色,如果没有前两个prompt,precision和recall直接下降20%-30%。

1.4.2.RQ2.Resource Leak Detection

通过召回率和误报率进行评估。

DetectorDetected BugsFalse Alarms
Code Inspection49 (56.9%)36 (41.8%)
Infer37 (43.0%)16 (18.6%)
Lint10 (11.6%)0 (0%)
FindBugs6 (6.9%)0 (0%)
Relda2-FS11 (12.7%)9 (10.4%)
RE lda2-FI8 (9.3%)4 (4.6%)
Elite6 (6.9%)4 (4.6%)
Verifier3 (3.4%)2 (2.3%)
InferROI46 (53.5%)7 (8.1%)

需要注意的是InferROI仅基于函数内分析就取得了相对较高的性能。无需进行复杂的跨函数分析。

1.4.3.RQ3.Open-Source Project Scanning

作者爬取了超过50 start的115个Java开源项目,这些项目是在2021年12月31日之后创建的。作者使用日期筛选条件以避免爬取gpt-4的训练集,随后,作者通过匹配20个常见的资源关键词,从13个项目中随机抽取了100个函数进行评估,而不是完全扫描这些项目。所使用的关键词如下:[stream、reader、client、writer、lock、player、connection、monitor、gzip、ftp、semaphore、mutex、stream、camera、jar、buffer、latch、socket、database、scanner、cursor]

作者用InferROI对这100个method进行检查。对于每个报告的漏洞,作者通过阅读代码和查询相关信息来手动标注是否是一个真正的漏洞。对于真正的漏洞,作者会提交相应的修复拉取请求,并要求项目开发者对其进行审查。

作者总共报告了16个resource leak,其中12个是true bug。paper提交的时候,7个已经被开发者确认。

12个bug中4个没有被现有的检测工具发现,resource type包括 URLClassLoaderManagedBuffer,以及project定制的 JDBCConnection

1.4.4.RQ4.Ablation Study

作者的ablation针对2部分:LLM-based资源意图识别以及静态leak检查。

为了进行ablation,作者创建了两个prompt模板,使gpt-4能够直接在代码中检测资源泄漏,从而得到两种资源泄漏检测器:GPTLeak和GPTLeak-chain。模版如下图所示:

GPTLeak

Identify resource leaks in the provided code snippet below.

Desired format:
<yes/no>
Leaky Resources:
<resource type >

Code Snippet: `java
{CODE}
`

GPTLeak-Chain

Identify resource leaks in the provided code snippet below.

Analyze the information about resource leaks in the provided code snippet
below. First, resolve the types of the involved objects. Then, identify the types
representing leakable resources. Next, identify the API/method calls for
acquiring the resources. After that, identify the API/method calls for releasing
the acquired resources. Subsequently, identify the if-conditions for checking
whether the acquired resources are closed or unclosed. Finally, identify resource
leaks

Identify resource leaks in the provided code snippet below.

Desired format:
<yes/no>
Leaky Resources:
<resource type >

Code Snippet: `java
{CODE}
`

对于GPTLeak,指令很简单,而对于GPTLeak-chain,则将额外的检测指令(最后一句话)合并到InferROI使用的模板中,以便在决策过程中向gpt-4模型提供具体的指导。

作者将这两种GPTLeak和GPTLeak-chain检测器应用到从DroidLeaks数据集收集的172个代码片段中。随后,计算每种检测器的bug检测率和误报率。

DetectorDetected BugsFalse Alarms
GPTLeak44 (51.2%)18 (20.9%)
GPTLeak-Chain32 (37.2%)36 (41.9%)
InferROI46 (53.5%)7 (8.1%)

结果表明,LLM可以通过代码理解能力辅助定位resource操作,但是LLM的推理能力依旧不足以进行漏洞检测。

1.5.Discussion

某些类型的资源泄漏可能会被漏报。例如,在Android回调中发生的资源泄漏代表了一个具有挑战性的领域,InferROI的轻量级静态分析可能会失败。

2.Latte

paper地址

  • SSF: security sensitive functions,安全敏感函数,sink点

  • EIS: external input source,外部输入,source点

  • PS: prompt sequence

  • DF: dangerous flow

2.1.Motivation

污点分析的复杂性和多样性以及其依赖人工定义污点规则的限制仍然阻碍了二进制污点分析工具器的整体性能。以下图中的整数溢出漏洞为例。

void bad(void) {
	signed char a, b, c, d;
	int e;
	bool f;
	a = ' ';
	fscanf(stdin, "%c", &a);
	b = a;
	a = '0x1';
	e = b + '0x1';
	printf("%d\n", (ulong)e);
	//No integer overflow after type conversion
	if (b == '0x7f'){
		printLine("data value is too larger" );
	}
	else {
		c = b + '0x1';
		printf("%02x\n", (ulong)(uint)(int)c);
		//No integer overflow after sanitization
	}
	return ;
}
  • 1.Source点-识别source以及分配污点label:在二进制文件中

    • 手动识别接收外部输入的污点源是一个繁琐的过程。不仅标准的C/C++函数(如 recvfscanffgets)可以接收外部数据,第三方函数(例如 OpenSSL 中的 SSL_readBIO_read )也可以接收外部数据。

    • 更重要的是,确定返回值参数的初始污点标签需要深入理解源语义。例如,只有了解 fscanf 的语义,我们才能确定fscanf 的第三个参数a(第6行)被污染。

    • 请注意,确定第三方函数的初始污点标签比标准C/C++函数更具挑战性,因为前者通常没有文档,而后者至少在C/C++语言标准中有所记录。错误的标记经常导致数据的污点信息被错误地传播。

  • 2.Propagation and Sanitization-定义污点传播规则:

    • 污点标签可以通过赋值 b = a 和算数运算 e = b + 0x1 传播,这可以通过数据依赖性分析自动识别。但是传播污点标签的过程不仅涉及标签传递,还涉及标签净化。
    • 除了直接将安全数据分配或复制到污染区域(a = 0x1)导致的净化外,还有与语义相关的净化情况。例如,if (b == 0x7f) 排除了 c = b + 0x1 溢出的可能。之前的工作 (EmTaint, SATC, Karonte)忽略了这些语义净化的情况,从而导致了许多误报。而手动定义净化操作繁琐复杂。
  • 3.Sink点-识别sink:和source一样,现有sink识别方法同样依赖人工标注,而不同类型漏洞需要不同的sink定义,它不仅包含标准库函数 (printf),还有不同第三方库函数,如 OpenSSL 中的BIO_printf。要检查 printf("%d\n", (ulong)e) 调用是否会引发CWE-134漏洞,需要检查printf 的第一个参数是否被污染;要检查基于第一个参数 %d 的调用是否会引发CWE-190漏洞,首先需要检查 printf 的第二个参数是否被污染,如果是污染的,还需要进一步检查该参数的计算过程是否溢出。需要注意的是,仅依赖于人类经验来理解和制定准确和全面的检查规则是不可扩展和可靠的。

2.2.Approach

dangerous flow: 一段涉及外部数据输入函数和可能导致漏洞的sink之间数据依赖链的函数链。

思路:首先基于LLM识别source和sink并构造一系列dangerous flow (func1 --> func2 --> func3),随后通过LLM逐函数分析dangerous flow。

2.2.1.Function Chain Generation

  1. Vulnerable Destinations Identification (sink):

难点: 安全敏感类函数的识别通常依赖于动态链接库

solution:

  • 对于动态链接库调用,函数名得意保留,Latte prompt LLM分析该函数是否可能成为sink;如果可能,LLM返回其可能导致漏洞的参数索引。
  • 对于静态链接库调用,LLM直接对库函数代码进行分析并摘要,识别是否成为sink以及导致漏洞的参数索引。

输出结果为一个 List[Tuple[str, str]],每个元素表示 (func_name, para)。比如,(system, 1) 表示 system 调用的第一个参数可能导致漏洞。func_name 为一个SSF (sink)。

随后,Latte识别所有的SSF的调用点。每个调用位置以 (Loc;SSF;Arg) 的形式保存,比如,(0x12345678;system;local_1),表示 system0x12345678 处调用,参数 local_1 需要进行污点验证。

  1. Backward Tracing:

获取每个SSF调用危险参数的数据依赖指令集合。

steps:

  • 1.构建call graph

  • 2.递归的过程间分析,直到没有跟当前caller的参数发生数据依赖或者找不到caller。

2.2.2.Dangerous Flow Generation

  1. Source Identification

使用LLM找到能够接收外部输入或者生成伪随机数的函数。返回值也是个 tuple。比如,(recv, 2) 表示 recv 第2个参数用来接收外部输入。

  1. Matching and Deduplication

从对应的function call chain中提取危险data flow。

  • 对于function call chain中的每个caller,识别是否调用了EIS。如果是,分析EIS的对应参数是否可达sink的对应参数。如果是,那么生成对应危险data flow。

  • 生成data flow时,每个function call chain保留最长的一个。

2.2.3.Prompt Sequence Construction

基于危险data flow识别漏洞。

prompt template:

每个prompt用来分析一个函数,如果一个dangerous flow有多个函数

start prompt:

As a program analyst, I give you snippets of C code generated by decompilation, using {start} as the taint source, and {parameter} marked as the taint label to extract the taint data flow. Pay attention to the data alias and tainted data operations. Output in the form of data flows.
  • start: source函数

  • parameter: 参数

middle prompt

Continue to analyze {function} according to the above taint analysis results. Pay attention to the data alias, tainted data operations, and {sources}.
  • function: callee function函数体。

end prompt

Based on the above taint analysis results, analyze whether the code has vulnerabilities. If there is a vulnerability, please explain what kind of vulnerability according to CWE.

2.3.Evaluation

Latte基于Ghidra和GPT-4.0实现,通过编写Ghidra插件(约2500行python代码)加载和分析二进制文件。Ghidra允许从二进制文件中提取反编译代码、控制流程图、导入表、堆栈帧和其他相关的信息供后续分析。使用GPT-4.0的API,Latte自动识别二进制中的SSF (sink)和EIS (source)。之后,LATTE执行反向数据依赖性分析来跟踪SSF调用点的数据流。dangerous flow代表可能导致漏洞的潜在程序路径。根据提取的dangerous和prompt模板,Latte构造prompt序列,以引导GPT-4.0进行漏洞检查。GPT-4.0在提供的指令上下文中分析代码段并执行检查以识别潜在漏洞。

数据集:

  • Juliet:也就是SARD,作者选用了CWE-78, CWE-134, CWE-190, CWE-606),作者同时删除了常量source的testcase(Juliet中有的代码直接将常量当作source,没有外部输入)。

  • Karonate:Karonte数据集包括了来自NETGEAR、D-Link、TP-Link和Tenda等流行厂商的real-world嵌入式设备固件数据集。数据集由49个基于Linux的固件样本组成。

作者选用了Arbiter和Emtaint作为baseline。

2.3.1.RQ1.Latte漏洞检测性能


与Emtaint和Arbiter相比,Latte在accuracy和F1分数方面表现更好,并支持更多的漏洞类型。在CWE-190的情况下,Arbiter能检测到更多的true positive。然而,这是因为Arbiter依靠符号表进行检查,如果将此信息提供给Latte,Latte可以检测到2576个真阳性,从而超越Arbiter。

2.3.2.SSF和EIS识别(source-sink识别)准确度

Latte以平均78%的精度自动识别SSF和EIS。识别结果100%正确覆盖了测试目标场景中的SSF和EIS。


在一些情况下,GPT-4错误地认为 recv 是一个SSF (sink),导致了误报。Emtaint和Arbiter依赖于手工定义source和sink,但Latte的标识结果可以帮助这些技术减少人工工作量。通过提供更精确和自动化SSF和EIS标识,Latte有助于简化漏洞分析流程并提高其他技术的效率。

2.3.3.RQ3.Dangerous Flow提取精度

下图结果显示,Latte提取dangerous flow的准确率达到95%。

错误主要来源于两方面:

  • Ghidra反编译错误:在解析函数调用的参数时出现错误,导致无法追踪数据依赖。

  • 纯虚函数调用:这些函数没有函数体,需要在子类具体实现。

2.3.4.RQ4.Real world漏洞检查

在Karonte的真实世界固件数据集上的评估中,Latte超过了Karonte、Emtaint和Arbiter,在49款固件上发现了119个独特的漏洞(包括CWE-78和CWE-120),并且覆盖了Karonte和Arbiter发现的所有漏洞。由于指针别名问题,Latte未能找到由Emtaint引发的16个漏洞。

Latte找到了37个以前未知的漏洞,7个被分配CVE编号。Latte的假阳性率和总分析时间为12.9% 和26.1小时,分别优于Karonte和Arbiter,但略逊于Emtaint。然而,Emtaint产生的警报和FP数量超过Latte,使得Latte更容易让分析师使用。此外,Latte提供了有价值的自然语言描述分析信息,帮助分析结果。

作者使用一个由Latte发现的真实漏洞作为例子来说明LLM污点分析的优势。不过由于页面限制,只放出了GPT-4的response。

函数语义描述:

The function FUN_0001bab0 takes a single parameter, a pointer to a char (char *param_1), and returns an undefined4 type value. The function appears to be checking the status of a process based on a file. The function can return three different values: 0, 0xffffffff, and 0xfffffffe. Here’s an analysis of the function: 1. If the input parameter (param_1) is NULL or an empty string, the function returns 0xffffffff. 2. If the parameter is not NULL or empty, the function attempts to open the file specified by the parameter
(param_1) in read-only mode (0). Omitted

漏洞分析结果

Based on the provided code snippet, there is a potential vulnerability related to CWE-120 (Buffer Copy without Checking Size of Input). The vulnerability arises from the following code block: memset(acStack_50,0,0x40); sVar2 = read(__fd,acStack_50,0x3f); Here, the buffer acStack_50 has a size of 68 bytes, and the code attempts to read up to 63 bytes from the file into the buffer. Omitted... To mitigate this vulnerability, you can add a null terminator explicitly after the read operation: sVar2 = read(__fd,acStack_50,0x3f); acStack_50[sVar2] = ’0’; By adding the null terminator, you ensure that string manipulation functions will not read past the buffer’s boundary, preventing potential buffer overflow issues.

从响应中,可以看到GPT-4不仅分析了 FUN_0001bab0 的数据流和控制流,还分析了调用者和被调用者、变量名和输出信息来理解函数的语义。根据对函数的理解,GPT-4通过污点分析进行漏洞检查。给出了漏洞触发路径和数据依赖项,还包括修复意见,这极大地帮助分析师识别和修复漏洞。

2.4.Discussion

虽然效果相比Emtaint等污点分析工具提升了,但Latte可能在处理诸如逻辑漏洞以及涉及复杂数学运算的竞争型漏洞(如时间窗口竞争)依旧存在问题。这些漏洞通常涉及复杂的嵌套和跳跃代码段,使得LLM难以有效地分析。另外,由于缺乏此类漏洞的公开信息,LLM在这方面的分析能力有限。

3.GPTScan

paper地址

这篇工作主要是将传统静态分析中一些需要形式化定义的规则利用GPT转换成通过自然语言描述。

3.1.Motivation

function deposit ( uint256 _amount ) external returns (uint256 ) {
   uint256 _pool = balance();
   uint256 _before = token.balanceOf(address(this));
   token.safeTransferFrom(msg.sender, address(this), _amount);
   uint256 _after = token.balanceOf(address(this));
   _amount = _after.sub(_before); // Additional check for deflationary tokens
   uint256 _shares = 0;
   if (totalSupply() == 0) {
     _shares = _amount;
   } else {
     _shares = (_amount.mul(totalSupply())).div(_pool);
   }
   _mint(msg.sender, _shares);
}

if (totalSupply() == 0) _shares = _amount; 这一句可能触发异常,static analysis tool会使用hard-coded patterns来检测 totalSupply() 逻辑。而这里有必要使用 GPT 来识别负责保管存款金额的变量 _amount 以及池中的总份额 _shares。但是GPT分析不出 totalSupply() == 0_shares = _amount; 中的逻辑关系。

function transfer(address account, uint256 amount) external override notPaused returns(bool) {
    require(msg.sender != account, Error.SELF_TRANSFER_NOT_ALLOWED);
    require(balances[msg.sender] >= amount, Error.INSUFFICIENT_BALANCE );
    // Initialize the ILiquidityPool pool variable
    pool.handleLpTokenTransfer(msg.sender, account, amount);
    balances[msg.sender] -= amount;
    balances[account] += amount;
    address lpGauge = currentAddresses[_LP_GAUGE];
    if (lpGauge != address(0)) {
        ILpGauge(lpGauge).userCheckpoint(msg.sender);
        ILpGauge(lpGauge).userCheckpoint(account);
    }
    emit Transfer(msg.sender, account, amount);
    return true;
}

ILpGauge(lpGauge).userCheckpoint(msg.sender); 应该在 balances[msg.sender] -= amount; 前执行。这里GPT有助于理解代码的语义。但是不能理解before这个概念。因此,需要static analysis来确认执行顺序。

3.2.Overview and Challenge

GPTScan的输入为一个智能合约project, 可能是一个solidity file或者 一个包含多个文件的framework-based 智能合约project。大致步骤为:

  • contract parsing + call graph analysis:计算function的可达性,过去获得candidate function set。

  • GPT-based Scenario and Property Matching:匹配candidate function与pre-abstracted scenarios以及相关漏洞类型。

  • Static Confirmation:识别matched function中的key variable以及statements。随后通过static analysis module进行验证。

需要解决的challenge包括:

  • C1:上下文长度限制-一个project可能包含若干solidity文件,一次输入GPT是不可能的。以及,没有非漏洞函数可能会影响GPT的检测能力。how to effectively narrow down the candidate functions for GPT matching becomes essential.

  • C2:现有GPT-based漏洞检测方法会输入一个high-level漏洞描述。这要么要求GPT具有好的推理能力,要么要求预训练好的漏洞知识。can we break down vulnerability types in a manner that allows GPT, as a generic and intelligent code understanding tool, to recognize them directly from code-level semantics?

  • C3:考虑到 GPT 可能产生不可靠的答案或无法识别类似功能的差异。further confirming the matched potential vulnerabilities becomes critical.

3.3.Function Matching & Static Confirmation

GPTScan 采用了一种不同的方法,将将漏洞类型分解为code-level场景和属性。

  • scenarios(场景)描述可能出现逻辑漏洞的代码功能

  • properties(属性)来描述的代码属性或操作

prompt trick:mimic-in-the-background

利用GPT识别出相关场景和属性有关的变量以及语句。再用static analysis来验证合法性,验证包括:

  • Static Data Flow Tracing (DF): 验证GPT提供的变量或者表达式是否具有数据依赖关系。

  • Value Comparison Check (VC):验证GPT提供的变量是否进行了比较。

  • Order Check (OC): 检查GPT提供的语句的执行先后顺序。

  • Function Call Argument Check (FA): 检查函数参数是否受外部控制。

4.Lara

paper地址,artifact地址(不过源码没开源)。

4.1.Introduction

这篇paper解决的是IOT污点漏洞检测中的source识别问题。在作者的threat model中攻击者可以从供应商网站获取相应IOT固件,并通过局域网(LAN)或广域网(WAN)访问目标设备,发送恶意 HTTP 请求到这些服务端。在服务端,包括中间件、CGI 程序以及相关的共享库在内的后端程序会处理这些恶意数据。通过分析后端程序,攻击者能够获取这些显性和隐藏的数据,并构造特定的 HTTP 请求,将恶意载荷注入到易受攻击的后端处理代码中,从而导致拒绝服务(DoS)或远程代码执行(RCE)等严重后果。

一个示例如下所示,对应了CVE-2022-28896(CVE-A)和CVE-2022-28901(CVE-B)。


从上图左边看:

  • 1.攻击者通过路由器 DIR-882 的Web界面(前端)与其进行交互,以配置网络设置。在 SubnetMask 字段中,攻击者输入了注入有效载荷,例如 ";rm -rf /;"

  • 2.前端生成了一个HTTP请求,用于配置路由器的网络设置。该请求使用了表单 SetNetworkSettings,并将键值对编码为表单数据。具体来说,SetNetworkSettings 被填充到HTTP包的 URI 字段中,而 SubnetMask 字段以及注入的有效载荷("SubnetMask=';rm -rf /;'")则被作为其中一个键值对填充到请求的主体字段中,编码为 form-data 格式。

  • 3.在接收到该 HTTP 请求后,路由器的后端根据表单的 URI 值找到相应的函数来处理请求。在这个案例中,处理该请求的函数是 sub_43AF7C

  • 4.在 sub_43AF7C 接收到 HTTP 请求的内容后,它会通过特定的函数提取键的值。在这个案例中,提取键值的函数是 websGetVarString

  • 5.在后端处理过程中,提取出的值(如攻击者注入的 ";rm -rf /;")会被作为命令的一部分传递,并调用 system 函数来执行该命令。这就使得攻击者能够执行任意代码。

从右边看:

  • 1.该漏洞的表单是隐藏的(即没有对应的前端代码),攻击者仍然可以生成并直接发送 HTTP 请求给后端。攻击者并不需要通过前端交互来利用漏洞,而是手动构建 HTTP 请求并将其发送到后端。在此攻击场景中,使用的表单是 SetTriggerLEDBlink。虽然用户无法通过正常的用户界面访问这个表单,但攻击者通过分析固件或网络通信日志可以确定其存在,并且构造出正确的 HTTP 请求格式。这种手动构造的请求包含必要的 URI 和表单数据,并通过将恶意负载(如命令注入)填充到表单数据的字段中,绕过了前端的限制。

  • 2.根据表单的 URI 值,后端调用函数 sub_4395CC 来处理这个HTTP请求。在这种情况下,后端通过解析 URI 来决定由哪个处理函数来处理该请求。对于表单 SetTriggerLEDBlinkURI 映射到函数 sub_4395CC,该函数负责提取并处理 HTTP 请求中包含的表单数据。

  • 3.在 sub_4395CC 接收到HTTP请求后,它会提取键 Blink 的值。这个过程通常涉及解析请求体中的键值对,并从中提取 Blink 对应的值进行后续处理。

  • 4.提取的 Blink 键值被用来通过 sprintf 函数格式化为命令,并传递给 twsystem 函数执行。需要特别注意的是,twsystem 函数并不在路由器的主二进制文件(prog.cgi)中,而是位于共享库 libcrm.so 中。

  • 5.在 twsystem 函数内部,用户控制的值通过 execv 函数执行,从而触发漏洞。

从前面的案例看,一些用户输入项是非隐藏的,因为它们有对应的前端处理逻辑(例如 SubnetMask,通过key SetNetworkSettings 对应的函数处理)。相反,某些用户输入项是隐藏的,因为它们没有相应的前端处理逻辑(例如 Blink,通过key SetTriggerLEDBlink 处理)。所有隐藏和非隐藏用户输入项的后端处理代码都可以用于提取污点分析的源。目前SOTA检测器SATC用关键字匹配查找source,但是对于 SubnetMask 不在关键字列表会被漏报,而 Blink 没有前端处理也会被漏报。

作者发现:

  • 1.用户输入项可以分为URIs(SetNetworkSettings, SetTriggerLEDBlink)或键值对(SetNetworkSettings --> SubnetMask, SetTriggerLEDBlink --> Blink)。识别它们对应的处理代码及其关系,有助于同时识别隐藏和非隐藏的用户输入项,并定位污点分析的源头。

  • 2.通过结合LLM辅助分析与传统的静态分析方法,可以实现更高的准确性和更低的假阳性率,从而提高整体的漏洞检测效率(说白了就是拿函数签名语义进行比对)。示例中存在键处理函数 websGetVarString。由于 IPAddress 的存在,仅使用规则匹配会错误地将 websXMLBodyResponse(a1,"IPAddress") 中的 websXMLBodyResponse 当作键处理函数。然而,通过函数名称,人类专家可以意识到它不是一个键处理函数,而是一个响应生成函数。而LLM虽能分析语义,但也有可能错误将 websGetResponseData 识别为键处理函数,而其函数签名匹配不上。因此可以交叉对比消除误报。

4.2.Approach

架构图如下,大部分都是关于source分析,sink分析(sink extractor部分)只是通过递归分析预定义sink的wrapper function,Taint Analyzer部分感觉跟之前的工作没太大区别。

source分析可分为:模式匹配、LLM-aided部分。

4.2.1.模式匹配

主要包括URI分析、键值对识别。

注册类型:

  • Binding Code Type I — Registration Function: 下图中 websFormDefine, websAspDefine 被称为registration function,将 BasicSettings 等URI绑定到对应的处理函数。

  • Binding Code Type II — Constant Data: 在12,13行。**定义常量数据 (DCD) **指令分配了一段连续的内存,并初始化为字符串 getstr 的地址以及处理该URI getstr 的函数 sub_AB16C 的地址。URI 和对应的 URI 处理函数作为成对存储在二进制文件的 .data 段的内存地址范围内。当程序接收到 HTTP 数据包时,会通过遍历该地址范围来匹配 URI,并使用下一条指令的内容作为相应的 URI 处理函数入口地址进行调用(图中的第6到11行)。

  • Binding Code Type III - Process Creation: 函数 websGetCgiName 从 HTTP 请求中提取 URI,并将其作为参数传递给函数 websLauchCgiwebsLauchCgi 使用 fork 启动一个新进程,并通过环境变量将 HTTP 请求传递给该新进程。新启动的进程处理 HTTP 请求中的用户输入,而启动的程序是 uri.cgi。相应的 URI 处理函数则位于该启动的程序中。


Lara分析URI集合算法如下图所示

LARA 使用与 URI 提取类似的方法来处理键(key)的提取。当程序解析 HTTP 请求的主体时,它会识别负责提取每个键对应值的函数。例如,在下图中,键 time 是从前端提取的。函数 websGetVar 从 HTTP 请求中提取键 time 对应的值(由变量 wp 表示),并将其赋值给局部变量 time_interval,该过程发生在 URI 处理函数 formSetSchedLed 中 。此外,Lara 还能通过相同的键处理函数 websGetVar 提取到隐藏键,比如前端文件中未找到的 ledCloseType

此外,LARA 还能通过相同的键处理函数 websGetVar 提取到隐藏键,比如前端文件中未找到的 ledCloseType

4.2.2.LLM-aided Analysis

上面分析过程中涉及到一环是键处理函数(比如 websGetVar )和注册函数的识别,比如下图中模式匹配只识别到注册函数 websFormDefine,而LLM可以辅助分析出 websAspDefine。对于LLM分析的结果,Lara会进行参数类型匹配,成功的话添加到对应函数集合中。

本文标签: LLMvulnerabilityDetection