简介

  • 模糊测试是发现未知漏洞的有效手段
  • 定向模糊测试与传统相比在流程上稍有不同
    • 目的:到达一个指定的目标位置
    • 应用:错误复现, 补丁测试等
  • 问题: 目前的模糊技术在某些漏洞的探寻上是效果不佳的
    • 比如: “Use-After-Free” (UAF)
      UAF漏洞往往是敏感信息泄露、数据损坏或其它攻击的第一步
  • 解决方法: 针对UAF漏洞量身定制的定向模糊测试方法

UAFuzz是第一个定向灰盒模糊探寻UAF漏洞的工具

背景

什么是Use-After-Free?

  • 堆元素在已经释放后再次被使用

    • 可能造成的严重后果
    • 数据损坏
    • 信息泄露
    • 拒绝服务攻击

    image-20211122153918173

image-20211122153930482

image-20211122153906577

一个UAF示例

image-20211122154049348

  • PoC: ‘AFU’
  • Bug Target: 14 (alloc) → 17 → 6 → 3 (free) → 19 (use)

三种模糊测试

image-20211122154215431

黑盒Fuzz不关心程序执行的状态,认为程序是一个黑盒。其直接产生输入然后尝试找到结果

白盒Fuzz在测试之前通常会先对应用进行分析,获取一定的信息来辅助其创建的输入能在应用程序中发现崩溃。负载相对较高

灰盒 集二者之所长,使用黑盒Fuzz进行执行,也一定程度上使用轻量的白盒方式为黑盒提供反馈。比单纯的白盒Fuzz更轻量级,比黑盒Fuzz更有效率。

定向灰盒模糊测试 (DGF)

传统模糊测试主要方法是增大自己的覆盖率范围以增加漏洞发现的概率,但是通过盲目地扩展代码覆盖范围来测试软件效率较低,特别是在极端情况下。因此研究人员提出了导向型模糊测试。

与基于覆盖的模糊测试的全局范围覆盖不同,导向型模糊测试会将大部分时间花在特定目标位置(容易出bug的地方)。

  • 输入: 源码 + 目标点

  • 目标 = 能够覆盖目标点

  • AFLGo (2017), Hawkeye (2018)

  • 应用:
    错误重现
    补丁测试
    静态分析报告的验证

为什么模糊测试很难探测到UAF漏洞?

难以被fuzzer发现:

  • 复杂性: 触发UAF漏洞需要在程序执行中在同一个内存位置触发3个事件序列(即alloc、free和use),同时要按照一定的顺序执行到这三个事件,但是在程序中这些事件跨越了多个函数,这导致要执行到UAF漏洞代码变得复杂。
  • 时间和空间的限制: 相比于缓冲区溢出只需要一个单独的界外内存访问,UAF具有的时间和空间约束的结合在实践中很难满足。
  • 无反馈: 不会像内存错误那样报错,在这种情况下,如果只是简单地观察计算机崩溃行为就不能检测到测试案例触发了UAF漏洞

image-20211122154530701

UAF bugs found (1%) by OSS-Fuzz

UAFuzz整体流程

image-20211122154650127

作者由此提出了 uafuzz,展示了三种用于UAF漏洞检测的动态种子度量,功率调度器对每个选定种子的度量分数确定能量,以此来引导模糊测试过程向漏洞位置靠近

UAFuzz的关键

★种子选择: 基于输入跟踪的相似性与顺序

★功率调度: 基于3个 种子指标**[细粒度不同]**

   [function level] 距离度量: 筛选更接近目标的种子
   [edge level] 切边覆盖率: 筛选在决策节点做出更好决策的种子
   [basic block level] 目标相似度: 筛选与目标路径更相似的种子

★UAFuzz第一个将可感知顺序的目标相似性度量引入到DGF中

★利用轻量化工具Binsec实现二进制级的快速预计算,开销更小

1.扁平化操作

  • UAFuzz首先对进行了目标路径扁平化操作,得到如图中一系列堆栈信息
  • 这些信息并不适合轻量级工具,因此UAFuzz将三个堆栈信息中的每一个都被看作是调用树中的一条路径,通过合并堆栈信息重建动态调用树。根据UAF事件的顺序对子节点进行排序(来自alloc事件的子节点先于来自free事件的子节点),对树进行前序遍历,得到包含目标位置及其相关函数的路径序列如图所示。

image-20211122155020211

2.1目标相似性

  • [basic block level] 目标相似性测量种子s的执行路径与目标路径T之间的相似性。从4个方面定义了相似性,分别测量了相同前缀(P)、相同前缀中的UAF事件(3TP)数量、相同节点(B)和相同节点中UAF事件(3TB)的数量,例如图6中的路径,红色表示需要度量的输入路径,目标路径中的UAF事件节点为0、2、5。测量到相同前缀0-1-2-3,相同节点0-1-2-3-5。测量得到tP(s,T) = 4,t3TP (s,T) = 2,tB(s,T) = 5,t3TB(s,T) = 3
  • UAFuzz基于P-3TP-B目标相似性原则进行种子选择,首先选择覆盖前缀多的种子(p),使fuzz可以更好地朝着目标前进。接着(在tP相同的情况下)选择相同前缀中UAF事件最多的种子,最后是相同节点最多的种子(B)

image-20211122155134796

2.2距离测量

  • [function level] 在距离测量上UAFuzz通过修改调用图中函数之间的距离权重来体现倾向性,使用轻量级静态分析降低调用图中这些事件之间的边的权重来实现。
  • UAFuzz计算在漏洞路径中可以调用UAF事件函数的函数集Ralloc、Rfree和 Ruse,例如fa∈Ralloc,fb∈Rfree∩Ruse或者fa∈Ralloc∩Rfree,fb∈Ruse则表示执行fa→fb的边可能会按顺序覆盖这三个UAF事件。从fa到fb通过降低其权重(β=0.25)来优先选择这条边。与AFLGO一样,UAFuzz优先用到达目标最短的路径,更容易获得覆盖UAF事件的输入。

image-20211122155300519

2.3切边

  • [edge level] UAFuzz提出切边的概念,在边级别上比较当前种子的执行路径与目标路径中边的相似性。
  • 切边指决策节点的传出边,并且通过切边能够到达目标基本块,主要关注跳转过程。如果一个输入的执行路径覆盖了更多切边和更少非切边,这个输入就可能覆盖目标路径的更多位置。因此给种子s计算一个切边得分es(s,T),覆盖越多切边得分越高,覆盖越多非切边,得分越低。

image-20211122155404347

3.度量器

综合以上提出的三个度量方式,作者提出了一个功率调度函数对UAFuzz进行种子的功率调度,给以下种子分配更多的能量:

  • 更接近目标的种子(基于UAF的距离d); 基于UAF的种子距离d(s,T)
  • 与目标路径更相似的种子(目标相似性t); 前缀目标相似性度量tP(s,T)
  • 在决策节点做出更好决策的种子(切边覆盖率e)。 切边覆盖率度量es(s,T)

image-20211122155507721

实验

错误复现能力:性能评估

  • Total success runs:与第二名的AFLGo相比 +34%
  • Time-to-Exposure (TTE):与其他工具相比时间缩短了近2倍

image-20211122155655854

UAFuzz在UAF漏洞复现方面优于目前市面上主流的模糊测试器

补丁测试

UAFuzz已经被证明在面向补丁的压力测试中是有效的,利用补丁测试在6个开源程序中发现30个新的bug(7个cve)

image-20211122155728800

UAFuzz总结

  • UAFuzz是第一个定向灰盒模糊UAF漏洞的方法

  • UAFuzz在UAF漏洞暴露的时间和成功运行的次数方面都优于现有的模糊测试程序,在bug复现和补丁测试中都是非常有效的

  • 类似UAFuzz这样对特定类型漏洞的特点,研究有针对性的Fuzz工具,也是模糊测试领域的一个新方向

  • 开源:

      https://github.com/strongcourage/uafuzz
      https://github.com/strongcourage/uafbench

实际尝试

项目整体架构

  • IDA Pro v6.9(32位)和Python v2.7:提取CFG
  • Graph-Easy v0.7.6:用于将生成的关系调用图转换为dot格式
  • 分析工具Valgrind:用于提供目标点和堆栈信息的展平
  • 二进制分析框架BINSEC:三个维度的指标
  • AFL v2.52b:进行模糊测试,将afl-fuzz.c与 BINSEC 的静态部分连接起来,以共享目标位置和模糊测试状态等信息

(1)目标编译—>IDA—>IDA python—>.IDA文件&.funcs文件—>callgraph.gdl

image-20211122160105928

BINIDA 插件是BINSEC v0.3的一部分。该插件的目标是使用反汇编器 IDA Pro 提取 x86 中输入二进制的信息,然后构建由 BINSEC 的数据结构表示的控制流图 (CFG)

(2)用valgrind追踪记录POC的UAF路径信息

image-20211122160148845

(3)根据.valgrind中记录的地址进行展平依次为alloc、free、use,对应地址分别对应有序节点创建动态关系调用图DCT.png

image-20211122160218517

image-20211122160224489

(4)依据DCT.png中关系细分为.tgt.tgt_cut.tgt_uaf三个子文件记录目标特征信息,用于后续进行度量

image-20211122160251033

(5)开始运行UAFuzz,此时Binsec也会不断运行将第一步信息与第四步目标点依据三个维度进行比较

image-20211122160324638

三个维度的判定源规则均在Binsec插件目录中由Ocaml书写

(6)一段时间后,成功跑出相对应的UAF漏洞

image-20211122160400950

  • UAFUzz仅支持32位二进制