Evocatio: Conjuring Bug Capabilities from a Single PoC

文章目录

Fuzzing 等动态软件测试技术可以快速生成 PoC 测试用例来触发程序中的 bug,但当开发者获得了大量的 PoC 后,又该如何在人力有限的情况下快速地分析 bug 的严重性和优先级?今天分享的论文 Evocatio: Conjuring Bug Capabilities from a Single PoC 就尝试通过自动探索 bug capability 解决这一问题(evocatio 在拉丁语中是 calling forth 和 conjure,即呼唤的意思)

背景动机

先前有工作基于 root cause 对 PoC 聚类来辅助评估一堆 PoC 里的 bug 数量,但仅仅是聚类并不足以揭示攻击者可以如何利用 bug 造成怎样的漏洞,仍然需要大量人力分析 bug 的危害,关键是理解 bug capability。

从内存漏洞的角度看,capability 可以由 bug 类型,访存类型(读/写),访存长度,访存对象名称,在对象内的偏移,内存位置(栈/堆/全局) 这六个属性来定义,比如 (OOB, read, 5, buffer, 10, stack) 可以定义栈上变量 buffer 的第 10 个字节开始的长度为 5 的越界读。

覆盖引导的 fuzzer 往往只关注寻找 bug,当遇到触发相同执行路径的 PoC,仅保留第一个而丢弃其他所有,把评估 bug capability 的重任交在了开发者身上。

理论上漏洞自动利用生成(Automatic Exploit Generation, AEG)技术可以用来评估 bug capability,但大多数 AEG 工具依赖符号执行,受到固有的路径发散和路径爆炸问题限制。

因此作者提出了 Evocatio 来评估 bug capability,本文主要贡献如下:

  • 开发了 Evocatio 来帮助开发者从一个 PoC 揭示新的攻击能力,以优先修复关键 bug
  • 展示了 Evocatio 对内存 bug 的应用场景:定量评估 bug 严重性分数和验证 patch 有效性
  • 在 38 个 bug 上评估 Evocatio 发现 bug capability、发掘 bug 攻击能力和产生新 PoC 的效果

那么 bug capability 到底如何在源码中体现?作者举了下图这个例子来说明其 motivation

图中的程序包含一个堆缓冲区溢出,要触发这一漏洞,首先必须满足 src 的前两个字节分别为 ‘a’ 和 ‘b’,作者把这两个字节称为 control-flow bytes,因为它们影响程序的控制流,进而决定程序是否满足触发 bug 的约束条件。在第 21 行中输入 src[40-43] 被读取,影响 dest 这段数据的大小,最终决定堆缓冲区溢出的长度,作者把这四个字节称为 capability bytes。又因为第 22 行 if 语句中 src[40-42] 既影响控制流又在上一行影响程序的数据流,所以这三个字节同时属于两种类型。从 bytes 的长度分类,foo 函数中的四个 capability bytes 可以分为两种,其中 src[4] 是 single capability bytes,只有单个字节,src[20] - src[23] 是 sequences of capability bytes,是一连串字节。

架构设计

Evocatio 的工作流程如下图所示:

主要有以下两个组成部分:

Capability detection (CapSan)

在 fuzzing 中要提取 PoC 的 capability 最自然的方式是用 sanitizer,作者修改了 ASAN 以让 sanitizer 在检测到缓冲区越界(Out-of-Bounds, OOB)错误后仍然继续执行直到抵达新的数据结构,这样以完整地探索 OOB capability。

Capability discovery (CapFuzz)

Critical Bytes Inference 如前所述,程序输入中只有一小部分会影响程序行为和 bug capability,因此需要理解哪些字节是 critical bytes。之前已经有工作成功利用 single-byte inference 来改进 fuzzer 的 code coverage,而 Evocatio 则用 single-bytes inference 来判断哪些字节会促进新的 bug capability,就是逐字节枚举测试其是否影响 control flow 或 data flow;bytes-sequence inference 的搜索空间则更大,不可能穷举,故使用类似 fuzzing 的方法,先随机选择一段 bytes sequance 并随机变异,这样可能发现新的 bug capability,不过得到的整段 bytes 中会有一些冗余的杂音,作者使用基于分治策略的 ByteSequenceReduction 来减小变异程度尽可能恢复更多冗余字节。两者结合即为 critical bytes inference,算法如下所示:

Critical Bytes Prioritization 在 critical bytes inference 找出大量 capability byte sequence 后,还需要对其排序,优先变异更可能触发新 capability 的字节,即 most energetic sequence,这可以通过动态地更新 sequence 对最近发现 capability 的贡献来实现。

Mutation 为了发现具有相同执行路径的新 crash,CapFuzz 只对影响数据流的 critical bytes 进行变异,算法如下图所示:

Seed Retention 每次新产生测试用例都要检查验证其引入了 capability 才保留在队列,为了在 capability 数量增大时保持查询高效,使用哈希表存储所有 capabilities

Seed Selection 和传统覆盖引导型 fuzzer 一样,CapFuzz 会将触发程序新路径的测试用例存储在队列中以备之后变异,如何选择最有用的 seed,作者的标准是优先考虑新 sequence 和 energetic sequence 产生的 seed。

CapSan 利用 ASan 的 API 来获取运行时崩溃的信息,CapFuzz 则修改了 AFL++ 来使用 capability 作为引导的指标,使用 7 千行 C 代码写成。

实验评估

作者在 6 种类型 的 38 个 bug 上做实验,希望回答以下四个问题:

  • RQ1 相比于其他工具,Evocatio 能否发现更多的 capabilities?
  • RQ2 Evocatio 设计中的不同组件如何影响其效果?
  • RQ3 Evocatio 能否用于漏洞严重性评分?
  • RQ4 Evocatio 能否用于测试 patch?

对于第一个问题,目前唯一可以拿来对比的竞品只有 AFL++ 的 crash exploration mode (afl-cexp),结果表明 Evocatio 发现的不同 capabilities 数量是 afl-cexp 的十倍,因为 afl-cexp 不关注数据流的变化,尽管它能获得很多新的 PoC,但只能触发不同执行路径下的相同 capabilities。

对于第二个问题,作者设计了 retention only, critical bytes only, full design 这三种不同的配置,对比它们之间的效果,结果证明了 critical byte inference 和 most energetic sequences 这两种设计的有效性。

对于第三个问题,作者以可读写的地址范围、越界读写对象数量,越界读写对象大小和不同偏移数为指标,用 Evocatio 对 bug 进行自动评分,并和原 CVE 在 Common Vulnerability Scoring System (CVSS) 中的 impact metric 进行比较,一些 CVE 在 Evocatio 中的影响评分不如 CVSS,是由于 Evocatio 对 bug 在特定应用中的影响缺乏先验知识从而低估其严重性;一些 CVE 在 Evocatio 中的影响评分高于 CVSS,因为 Evocatio 能发现原本未知的漏洞利用类型,这就能帮助开发者快速预估漏洞的严重性,增进对 bug 的理解。

对于最后一个问题,作者选择了 16 个能找到补丁的 bug,在打过补丁的代码上再重放产生的 PoC,发现其中 7 个仍然能触发 crash,这说明 44% 的 bug 并没有被正确修复。

除此之外作者还给出了两个 case study,以 CVE-2018-7871 为例分析了 Evocatio 如何能够提升 bug 的威胁类型,将越界读转化为越界写,又以 sudo 的高危漏洞 CVE-2021-3156 为例,展示了 Evocatio 能在 10 分钟之内从 1 字节的堆内存溢出 PoC 生成多达 120 字节长度的越界写,而AFL++ 的 crash mode 经过 8 小时的 fuzz 也未能产生任何新的 PoC。

讨论总结

作者首先表明 Evocaio 的目标不是替代 CVSS 和手动分析,而是希望专注于 “interesting” 的 bug,和 CVSS 一起来帮助判断 bug 的严重性。

作者也指出了本文工作的一些限制:critical bytes 是和输入长度有关的,为避免在 fuzzing 时破坏 critical bytes,尚不支持探索和输入长度有关的 capability;因为 null pointer deference 和 double free 不直接导致 memory corruption,目前 Evocatio 无法发现这两类相关的 capability,留待后续工作;评分系统指标过于单一,无法泛化到其他 bug type,需要留待后续对 capability detection 做出改进。

这篇论文其实也可以看作 data flow 在 fuzz 中的应用,不过其视角颇为独特,从 bug capability 的概念入手,在越界读写这一种类型的漏洞利用增强上取得了较好的效果,结合 sudo 高危漏洞的案例,具有较强的现实意义。

论文地址:https://nebelwelt.net/files/22CCS.pdf

代码地址(尚未释出):https://github.com/HexHive/Evocatio

评论正在加载中...如果评论较长时间无法加载,你可以 搜索对应的 issue 或者 新建一个 issue