Fuzzing101系列 Exercise 1
Last Update:
Word Count:
Read Time:
Page View: loading...
转载 Fuzzing101系列 Exercise 1 - Xpdf
序言
Fuzzing101系列包含针对10 个真实目标的10个练习,在练习中一步一步学习Fuzzing技术的知识。
模糊测试(Fuzzing/Fuzz)是一种自动化软件测试技术,它基于为程序提供随机或变异的输入值并监视它的异常和崩溃。
AFL、libFuzzer 和 HonggFuzz 是现实世界应用中最多的三个模糊器,这三个都是覆盖引导的进化模糊器(Coverage-guided evolutionary fuzzer)。其中
- 进化(evolutionary)是一种受进化算法启发的元启发式方法,它基本上包括通过使用选择标准(例如覆盖率)随时间推移初始子集(种子)的进化和变异。
- 覆盖引导(Coverage-guided)是指为了增加发现新崩溃的机会,覆盖引导的模糊器收集和比较不同输入之间的代码覆盖率数据,并选择那些导致新执行路径的输入。
在这个练习中,我们将fuzz Xpdf PDF 查看器。目的是在 XPDF 3.02 中找到 CVE-2019-13288 的崩溃/PoC。
CVE-2019-13288 是一个漏洞,它可能会通过精心制作的文件导致无限递归。由于程序中每个被调用的函数都会在栈上分配一个栈帧,如果一个函数被递归调用这么多次,就会导致栈内存耗尽和程序崩溃。因此,远程攻击者可以利用它进行 DoS 攻击。可以在以下链接中找到有关不受控制的递归漏洞的更多信息:https://cwe.mitre.org/data/definitions/674.html
你会学到什么
完成本练习后,你将了解使用 AFL 进行 fuzz 的基础,例如:
- 使用检测编译目标应用程序
- 运行模糊器(afl-fuzz)
- 使用调试器 (GDB) 对崩溃进行分类
环境
所有练习都在 Ubuntu 20.04.2 LTS 上进行了测试。 我强烈建议您使用相同的操作系统版本以避免不同的模糊测试结果,并在裸机硬件而不是虚拟机上运行 AFL,以获得最佳性能。
否则,您可以在此处找到 Ubuntu 20.04.2 LTS 镜像。用户名为 fuzz
/ fuzz
。
AFL 使用非确定性测试算法,因此两个模糊测试会话永远不会相同。我强烈建议设置一个固定的种子(-s 123
),这样你的模糊测试结果将与本文的结果相似。
下载并构建目标
首先为要进行模糊测试的项目创建一个新目录:
1 |
|
为了完全准备好环境,需要安装一些额外的工具(make 和 gcc)
1 |
|
下载 Xpdf 3.02:
1 |
|
构建 Xpdf:
1 |
|
下面对 Xpdf 进行测试,首先下载一些 PDF 示例:
1 |
|
使用以下命令测试 pdfinfo 二进制文件:
1 |
|
安装 AFL++
我们将使用最新版本的 AFL++ fuzzer(https://github.com/AFLplusplus/AFLplusplus)
安装依赖项
1 |
|
构建 AFL++
1 |
|
执行afl-fuzz
,查看是否安装成功
认识 AFL++
AFL 是一个覆盖引导的模糊器(coverage-guided fuzzer),这意味着它收集每个变异输入的覆盖信息,来发现新的执行路径和潜在的错误。当源代码可用时,AFL 可以使用插桩(instrumentation),在每个基本块(函数、循环等)的开头插入函数调用。
要为我们的目标程序启用检测,我们需要使用 AFL 的编译器编译源代码。
首先,我们要清理所有之前编译的目标文件和可执行文件:
1 |
|
现在我们将使用 afl-clang-fast
编译器构建 xpdf:
1 |
|
现在可以使用以下命令运行 fuzzer:
1 |
|
每个选项的简要说明
-i
表示输入示例的目录-o
表示 AFL + + 将存储的变异文件的目录-s
表示要使用的静态随机种子@@
是占位符目标的命令行,AFL 将用每个输入文件名替换
fuzzer将会对每个不同的输入文件运行 $HOME/fuzzing_xpdf/install/bin/pdftotext <input-file-name> $HOME/fuzzing_xpdf/output
命令
出现错误,根据提示,执行以下操作:
1 |
|
成功运行,等待一段时间后,发现已经有了一个crash
可以在$HOME/fuzzing_xpdf/out/
目录中找到这些崩溃文件。一旦发现第一次崩溃,就可以停止fuzzer,上图中已经出现了一个独特的崩溃。根据您的机器性能,最多可能需要一到两个小时才能发生崩溃。
为了完成这个练习,下面尝试使用指定的文件重现崩溃,调试崩溃发现问题,并且修复问题。
重现崩溃
在$HOME/fuzzing_xpdf/out/
目录下找到 crash 对应的文件。文件名类似于id:000000,sig:11,src:000390,time:103613,execs:71732,op:havoc,rep:16
将此文件作为输入传递给 pdftotext
1 |
|
它将导致段错误segmentation fault并导致程序崩溃。
调试
使用 gdb 找出程序因该输入而崩溃的原因。
首先使用调试信息重建 Xpdf 来获得符号堆栈跟踪:
1 |
|
然后使用GDB,输入run
1 |
|
然后输入bt
回溯查看栈帧
发现有许多次Parser::getObj
的调用,它们似乎表示一个无限递归。如果你去 https://www.cvedetails.com/cve/cve-2019-13288/ ,你可以看到描述符合我们从 GDB 得到的回溯