结合静态与动态分析优势范围的fuzzer:Arbiter

发布时间 2023-07-01 17:28:17作者: 辰星-cxing

对于Arbier这款新型fuzzer的研究,目前网络上几乎没有内容,因此大部分内容的直接来源于Arbier的论文《Arbiter: Bridging the Static and Dynamic Divide in Vulnerability Discovery on Binary Programs》,该论文随着2022年8月的USENIX安全研讨会的论文集中发表。

1.引言

当前最先进的二进制程序分析方法在漏洞发现方面非常有效,但却受到准确性和可扩展性之间权衡的限制。而Arbiter通过确定一组漏洞的故意属性(或者说特征,分别是四类常见漏洞,下文会列出),可以借助当前先进的静态与动态漏洞检测技术,显著提高前者的精度与后者的可扩展性(静态分析技术大部分存在精度问题, 而动态分析技术大部分存在可扩展性差的问题)。
具体的,Arbiter针对这四类漏洞构建了一套特别的方法,CWE-131(Incorrect Calculation of Buffer Size ,缓冲区大小计算错误)、CWE-252(Unchecked Return Value,未检查的返回值)、CWE-134(Use of Externally-Controlled Format String,未控制的格式化字符串)、CWE-337(Predictable Seed in Pseudo-Random Number Generator,伪随机数生成器中的可预测种子)。
Arbiter相关的工作如下:

  1. 确定了一组特定漏洞的属性,这些属性允许静态分析与动态分析(尤其是DSE,DSE就是动态符号执行)的有效组合,在保持可扩展性的同时实现高精度。
  2. Arbiter结合了静态分析与DSE来识别bugs,且Arbiter的运行不需要任何源代码。Arbiter对现有的静态分析与动态分析技术有新颖的改进,Arbiter扩展新的漏洞属性规范的代价并不高。
  3. 从Ubuntu 18.04 LTS中的软件存储库收集了76516个二进制程序,在此基础上大规模的测试Arbiter对四类漏洞的发现能力。

2.Arbiter的理论基础

2.1 漏洞发现技术

这部分将讨论与Arbiter密切相关的漏洞发现技术,以及它们的优缺点。
白盒静态分析。基于图形的漏洞发现方法(Graph-based vulnerability discovery approaches),主要目标是寻找出代码易受攻击的部分、范围,减少研究和分析人员的工作量。但是这类方法有两个问题,一是精准度无法得到保证,二是不够自动化。诸如,Codeql、chunky和Joern就是典型代表。
当前利用模糊测试与DSE来识别漏洞的技术,可以使用DSE来生成测试用例、利用约束求解器进一步识别程序中的断言错误(算术溢出、危险的有符号与无符号转换等),但却有着与其他动态技术类似的限制,即受程序入口点符号执行所支持的探索的严重限制。
其他采用污点分析或DSE来发现程序漏洞的,如Statsym它使用统计引导的DSE,以及DIODE,它使用污点分析来寻找识别内存分配代码的位置,并使用DSE检查内存分配过程中的参数是否有溢出的可能性。在实践过程中,通常需要进行大范围的fuzzing。
DSE增强的二进制静态分析,对于这种技术,目前它们总是需要从程序的入口点开始,极大的限制了它们的可扩展性。

2.2 静态与动态分析的比较

下图的表中,提供了常见漏洞发现技术的定性比较。一般来说,动态分析具有高精准度但是难以提高代码覆盖率(相信有过使用AFL这类fuzzing的人深有感受)这回导致大量潜在的BUG被遗漏,静态分析有很高的代码覆盖率但却十分容易出现误报,精准度低。
image.png

2.2 Arbiter针对漏洞的分析

Arbiter对此的见解是,选择在静态分析与动态分析中都有可检查属性的漏洞,这样就可以结合静态分析与动态分析两种技术的优势,在保证可扩展性的同时,实现高精度。为此,Arbiter着手确定一组漏洞的“属性”,这些属性非常适合静态分析,同时也十分容易集成到动态分析中。Arbiter确定了三种这样的属性:

  1. 数据流敏感漏洞(Data-flow sensitive vulnerabilities)。对于数据流敏感的漏洞,我们可以通过理解输入源与输入源的接收器之间的数据流来发现,这可以通过静态分析技术来实现。
  2. 易识别的输入源或输入接收器(Easily identifiable sources or sinks)。输入源决定漏洞追踪的开始,而接收器觉决定数据流追踪的结束。若输入源是一个十分复杂的行为或结构,如从一个文件中读取的任意数据,则需要分析读取文件相关的系统调用、参数,追踪文件描述符,解析File IO指针等等,这太过复杂。同样的输入最终的接收器,也应当是明确的,例如你输入了一个数字,而这个数组最终处理为malloc函数的参数,这种接收器就是易识别的。
  3. 控制流中明确的符号意义(Control-flow-determined aliasing)。数据流的追踪几乎总是涉及符号意义的确定,这个过程代价高昂且困难。然而,许多漏洞所包含的数据流根本不涉及指针的复杂解引用,或者涉及解引用时指针始终可以解析出一个确定的对象。简言之,该属性可以运行Arbiter在CFG程序的控制流上,便捷的前进或后退。

通过上面三个关键属性,使得Arbiter能够找到静态分析与动态分析漏洞发现技术中的交集,Arbiter可以更加轻松的集成两者,专注于发现常见的几类漏洞类别的子集。

2.3 Arbiter的分析框架

2.png
Arbiter的分析框架如上图所示。

  1. 输入
    1. 目标二进制文件:为了分析二进制代码,Arbiter需要待检测的二进制文件。与纯粹的动态分析不同(例如Fuzz),提供给Arbiter的二进制文件不要求可运行。
    2. 漏洞描述(VD):Arbiter通过对三个漏洞属性,划定了四类漏洞的检测范围(CWE-131、CWE-252、CWE-134、CWE-337)。除了在2.2提出的三个漏洞描述属性,你还可以自定义漏洞描述属性给Arbiter,扩展Arbiter的漏洞发掘范围。
  2. 识别漏洞流量:Arbiter通过多种技术组合来识别可能满足符号VD的流。它首先在CFG搜索提供的VD,然后查询计算数据依赖图一识别与所提供的VD匹配的数据流,并计算流的路径,以提供给下一步使用
  3. 验证漏洞条件:Arbiter使用 Under Constrained Symbolic Execution(UCSE)来处理路径信息,并恢复源和接收器之间的符号关系,如果这种关系满足VD中描述的约束,则该路径被提供给下一步。
  4. 排除误报:满足VD约束条件的路径中,其中的数据流可能缺少高上下文敏感性的约束条件,而Arbiter将以符号执行的方式恢复这些约束条件,通过对敏感度级别的判断来排除误报。

2.4 Arbiter与其他工具的比较

与AFL的比较

AFL是众所周知的先进的动态执行的fuzzer。在Arbiter在15个二进制文件中找到的25个整数溢出漏洞,在这15个包含漏洞的二进制文件中,只有七个是可以独立执行的二进制文件,其余是利用工具才能执行的共享二进制文件(例如动态库),接下来会使用AFL对这个十五个二进制文件进行评估。
在四个AFL能够不进行额外设置的fuzzing二进制文件中,有两个AFL找到了与Arbiter相同类型的bug,以及一些不在Arbiter漏洞类别的bug。而在剩下的两个中,AFL没有发现bug。
这些结果表明,模糊测试和Arbiter中提出的技术的结合是一个可行且有研究价值的领域是。

与Codeql比较

Codeql是一根先进的、可用于源代码静态分析的引擎。我们评估Codeql是否可以识别出Arbiter中检测的BUG,以进行两者的比较。
在我们最初从Ubuntu中提取的二进制样本中,Codql发现了11个带有CWE-252和54个带有CWE-131的程序。Codeql没有发现不一致返回值的操作,并且只有一个真正的正分配大小溢出的漏洞。
这些结果表明,Arbiter可以识别Codeql等源代码分析器漏洞的bug。

3.结语

Arbiter是一种新颖的fuzzer漏洞发现框架,它结合了静态和动态分析的优势,通过提取静态与动态分析范围内的漏洞描述属性,可以十分高效的和有效的发现副符号这些漏洞描述的漏洞,并且Arbiter不要求二进制文件可运行。