FUZZ 总览篇
0x00 前言
本文的目的在于对一些FUZZER进行收集,随后挑选几个去体验。
0x01 简介
模糊测试(Fuzz Testing)是一种自动化的测试方法,通过输入大量的随机、无效或异常数据(称为“模糊”或“模糊输入”)来评估目标程序的稳定性和安全性。在软件开发的安全性和鲁棒性方面,模糊测试被广泛用于查找潜在的漏洞和错误。
0x02 术语
1.Corpus 语料库
Or test corpus, or fuzzing corpus.一组测试输入。在大多数情况下,它指的是生成最大代码覆盖率的一组最小测试输入。
2.Cross-pollination
该术语源自植物学,其中一种植物为另一种植物授粉。在模糊测试中,异花授粉意味着使用一个 模糊目标的语料库来扩展另一个模糊目标的语料库。例如,如果有两个处理相同通用数据格式的库,那么对它们各自的语料库进行异花授粉通常是有益的。
3.Dictionary 字典
为模糊目标指定有趣标记的文件。大多数模糊测试引擎都支持字典,并且会调整其突变策略来一起处理这些标记。
4.Fuzz Target 模糊目标
Or Target Function, or Fuzzing Target Function, or Fuzzing Entry Point.应用模糊测试的函数。
5.Fuzzer 模糊器
"Fuzzer" 根据语境不同可以指代模糊目标,模糊测试引擎,变异引擎,测试用例生成器,模糊测试构建。
6.Fuzzer Build 模糊器构建
包含给定项目的所有模糊测试目标的构建,该构建使用特定的模糊测试引擎以特定的构建模式(例如启用/禁用断言)运行,并且可以选择与消毒剂结合使用。在OSS-Fuzz中,它也被称为作业类型。
7.Fuzzing Engine 模糊测试引擎
一种尝试通过执行模糊目标来找到有趣输入的工具。示例:libFuzzer、 AFL、 honggfuzz等。
8.Mutation Engine 突变引擎
一种工具,它将一组测试用例作为输入并创建其变异版本。它只是一个生成器,不会将突变提供给模糊目标。示例:radamsa(通用测试变异器)。
9.Reproducer 复制器
a testcase 一个测试用例,可以导致错误重现的测试输入。
10.Sanitizer 消毒剂
一种动态测试工具,可以检测程序执行过程中的错误。示例: ASan、 DFSan、 LSan、 MSan、 TSan、 UBSan。(可以发现一些不会造成程序Crash的漏洞)
11.Seed Corpus 种子语料库
准备一个小型初始语料库,旨在为模糊测试提供初始覆盖。种子语料库通常是根据现有的测试输入准备的,或者可以手工制作以提供有趣的覆盖范围,而不是由模糊器本身创建。它们经常与模糊目标一起检入源代码。
12.Test Generator 测试发生器
根据某些规则或语法从头开始生成测试用例的工具。示例: csmith(C 语言的测试生成器)、 cross_fuzz(跨文档 DOM 绑定测试生成器)。
13.Test Input 测试输入
用作模糊目标输入的字节序列。通常,测试输入存储在单独的文件中。
0x03 FUZZ技术
TODO
0x04 FUZZER
https://fuzzing-survey.org/ 可以看到基本上全部的FUZZER。
1.AFL
1.1 介绍
American Fuzzy Lop(AFL)是一款由Michał Zalewski创建的开源模糊测试工具,专注于通过输入模糊测试来发现软件中的漏洞和异常行为。AFL采用基于边界覆盖的模糊测试策略,自动化程度高且易于使用,成功用于广泛的应用程序和协议的安全性测试,成为安全研究和漏洞挖掘领域中的重要工具之一。
1.2 白皮书
https://lcamtuf.coredump.cx/afl/technical_details.txt
1.3 存在的问题
1.不在维护,传言是开发AFL的作者离开了Google,随后就不维护了。google替代AFL的是AFL++。
2.BItmap冲突,AFL通常使用较为简单的覆盖率信息,这种覆盖的不准确和不完整给fuzzing带来了严重的局限性。首先,它会导致路径冲突,从而影响fuzzing挖掘出导致新崩溃的潜在路径。更重要的是,它也会影响fuzzing的最优决策。
在AFL中,AFL要用到一个64KB bitmap来保存Coverage的信息,在AFL进行fuzzing的时候,会发生碰撞,两个块之间的路径构成一个边,AFL为边赋了hash值,这个hash值就代表这条边,可是不同的边计算出的hash值可能是一样的,于是就发生了Collision , Collision可能会导致某些input到达新的路径,但AFL却没有将该input作为seed
2. AFLPlusPlus
2.1 介绍
AFLplusplus是由Michał “lcamtuf” Zalewski创造的American Fuzzy Lop模糊测试器的继任者,最初的目标是整合多年来在AFL家族模糊测试器中开发的最佳功能,这些功能由于AFL自2017年11月以来未更新而未合并至AFL。
2.2 白皮书
3.Honggfuzz
3.1 介绍
honggfuzz是由谷歌开发的,和AFL类似的反馈驱动,使用遗传算法来变异的fuzzer。h
honggfuzz是一个多进程和多线程的fuzzer,所以用honggfuzz进行fuzzing的速度非常快,在安全漏洞发现中的表现十分突出。
4.libFuzzer
4.1 介绍
LibFuzzer 是一个进程内、覆盖引导的、进化的模糊测试引擎。
LibFuzzer 与正在测试的库链接,并通过特定的模糊测试入口点(也称为“目标函数”)向库提供模糊输入;然后,模糊器跟踪到达了代码的哪些区域,并在输入数据的语料库上生成突变,以最大化代码覆盖范围。
4.2 白皮书
https://llvm.org/docs/LibFuzzer.html
5.OSS-FUZZ
5.1 介绍
OSS-FUZZ旨在通过将现代模糊测试技术与可扩展的分布式执行相结合,使通用开源软件更加安全和稳定。
其使用Docker将开源项目以及Google的一些模糊测试相关项目结合,支持使用多种Fuzzing tool和Sanitizer去Fuzz开源项目,开源项目的Fuzzer由开源作者编写,所以可以一键开启Fuzzing(就是洞挺难挖的)。
5.2 白皮书
https://google.github.io/oss-fuzz/
0x05 SANITIZER
https://github.com/google/sanitizers
1.ASAN
1.1 介绍
AddressSanitizer (ASan) 是一个 C/C++ 的内存错误检测器。它能发现以下错误:
- Use after free (dangling pointer dereference)
- Heap buffer overflow
- Stack buffer overflow
- Global buffer overflow
- Use after return
- Use after scope
- Initialization order bugs
- Memory leaks
这个工具非常快速。被插桩程序的平均减速约为2倍(请参阅 AddressSanitizerPerformanceNumbers)。
该工具由一个编译器插桩模块(目前为LLVM插件)和一个运行时库组成,该库替换了 malloc 函数。
1.2 实现
此部分编写仅参考文档,并没有实验验证
实现简单来说就是用一个run-time library替代了malloc和free函数。随后对malloc和free的内存进行是否中毒的检测,如果中毒就报告错误。
详细实现为将程序的虚拟内存分为不相交的两个类,主程序内存和影子内存。影子内存和主程序内存存在对应关系,主程序内存有一个字节中毒意味着一些值会写入影子内存。
AddressSanitizer将 8 字节的应用程序内存映射到 1 字节的影子内存。
对于任何八字节对齐的应用程序内存,只有9个不同的值。
- qword 中的所有 8 个字节均未中毒(即可访问的)。阴影值为0。
- qword 中的所有 8 个字节均中毒(不可访问的),影子值是负数。
- 前k个字节未“中毒”,后8-k字节“中毒”,影子值是k。这一功能的达成是由malloc函数总是返回8字节对齐的内存块来保证的,唯一能出现该情况的场景就在申请内存区域的尾部。例如,我们申请13个字节,即malloc(13),这样我们会得到一个完整的未“中毒”的4字和前5个字节未“中毒”、后3个字节“中毒”的4字。
1.3 问题
1.内存如何更紧凑
2.目前不会捕获部分未对齐的越界访问
int *x = new int[2]; // 8 bytes: [0,7].
int *u = (int*)((char*)x + 6);
*u = 1; // Access to range [6-9]
2. LSAN
2.1 介绍
LSAN 是一个运行时内存泄漏检测器,它可以与 ASAN 结合使用以同时获得检测内存访问错误和内存泄漏的能力,它也可以单独使用。LSAN 是在进程结束时才开始泄漏检测,因此它几乎不会降低程序的性能。
2.2 实现
lsan 在进程 exit 的前一刻被触发,它首先暂停进程("StopTheWorld"),然后扫描进程的 memory,lsan将进程的内存分为两大类:heap region,live memory。
lsan 扫描进程的 live memory 以发现 live pointer,然后校验每个 heap block 是否有 live pointer 指向它,如果没有,那么 lsan 就判定它被泄漏了。
2.3 问题
1.存在假阳性。按照 lsan 的原理,它会将没有 live pointer 指向的 heap region 标记为泄漏;对于有 live pointer 指向的 heap region,如果在 process 退出的时候,它依然没有被释放,lsan 并不会将它标记为泄漏,这种情况是否算是泄漏其实很难界定,因为 OS 会在进程退出的时候,统一回收进程占用的资源,所以即使工程师没有释放,大多数情况下是没有问题的,但是如果程序的正确性依赖于某个 heap object 的 destructor 的执行,那么这种情况下应用程序可能是错误的。另外从严格的工程实践来说,工程师应该保证程序的完全正确,应该对资源管理完全负责,所以本文会将这种情况定义为泄漏,将这种情况视为 lsan 的 False negative。实际上,这种情况,目前基本上是没有工具能够检测出来的。
2.由于依赖ptrace,所以不支持windows。
3. TSAN
3.1 介绍
TSAN(ThreadSanitizer)是用于 C/C++ 和 Go 的快速数据竞争检测器。
3.2 实现
TSAN会对程序中的每个内存访问进行检测,除非可以证明它是无竞争的或冗余的。
https://zhuanlan.zhihu.com/p/38687826
算法的核心是状态机,每次内存访问更新Shadow State。
首先,线程时钟递增,创建与当前内存访问对应的Shadow Word。随后状态迭代所有存储在Shadow State中的Shadow Word。如果旧的Shadow Word之一与新的Shadow Word产生竞争。
3.3 问题
1.极小概率错过data race。
4. MSAN
4.1 介绍
MemorySanitizer (MSan)是一个检测C/C++程序中读取未初始化内存的检测器。
4.2 实现
MemorySanitizer 可以将每个未初始化的值追溯到创建它的内存分配,并在报告中使用此信息。此行为是通过该-fsanitize-memory-track-origins标志启用的。它带来了 1.5 倍到 2.5 倍的额外减速。
MSan 实现的是一个 bit to bit 的影子内存,每一比特都有映射,所以在计算影子内存的位置时,十分高效。
0 代表已初始化过的,1 代表未初始化的,所以开始时,影子内存填满了 0xFF。
MSan 的性能开销大概 ~3x,内存开销大概 ~2x。
5.UndefinedBehaviorSanitizer (UBSan)
5.1 介绍
UndefinedBehaviorSanitizer (UBSan) 是一种快速的未定义行为检测器。UBSan 在编译时修改程序以捕获程序执行期间的各种未定义行为,例如:
- Array subscript out of bounds, where the bounds can be statically determined
- Bitwise shifts that are out of bounds for their data type
- Dereferencing misaligned or null pointers
- Signed integer overflow
- Conversion to, from, or between floating-point types which would overflow the destination
5.2 实现
TODO
0xFF 参考
1.https://google.github.io/oss-fuzz/
3.https://www.aqniu.com/tools-tech/65203.html
4.https://github.com/google/fuzzing/blob/master/docs/
5.https://zhuanlan.zhihu.com/p/390555316
6.https://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
文章评论