目录
简介
文档
QuickStartGuide
README
perf_tips.txt
status_screen
INSTALL
安装
下载
编译
检查
例子
有源码-标准输入
源代码
编译
fuzz前的准备工作
开始fuzz
结果分析
参考
AFL(American Fuzzy lop)是一种面向安全的模糊器,它采用新型的编译时检测和遗传算法来自动发现干净、有趣的测试用例,这些用例会触发目标二进制文件中的新内部状态。这大大改善了模糊代码的功能覆盖范围。该工具生成的紧凑的合成语料库还可用于其他更耗费人力或资源的测试方案的种子。
与其他仪器化的模糊测试器相比,afl-fuzz的设计实用:它具有适度的性能开销,使用各种高效的模糊测试策略和工作量最小化技巧, 基本上不需要配置,并且可以无缝地处理复杂的实际用例,例如,常见的图像解析或文件压缩库。
2017年11月5日后不再更新...
1)用'make'编译AFL。如果构建失败,请参阅docs/INSTALL中的提示。
2)查找或编写一个合理快速,简单的程序,该程序从文件或标准输入,以值得测试的方式对其进行处理,然后干净地退出。
如果测试网络服务,请将其修改为在前台运行并从stdin读入。当模糊测试一个使用校验和的格式时,请注释掉校验和验证码。
遇到故障时,程序必须正确崩溃。当心自定义SIGSEGV或SIGABRT处理程序和后台进程。有关提示检测非崩溃的缺陷,请参阅docs/README中的第11节。
3)使用afl-gcc编译要模糊化的程序/库。常见的方法
CC =/path/to/afl-gcc CXX=/path/to/afl-g++./configure --disable-shared
make clean all
如果程序构建失败,请ping。
4)获取一个对程序有意义的小而有效的输入文件。当模糊测试冗长的语法(SQL,HTTP等),按照中dictionaries/README.dictionaries所述创建字典。
5)如果程序从stdin读取,请像这样运行'afl-fuzz':
./afl-fuzz -i testcase_dir -o discovers_dir-\
/ path / to / tested / program [...program's cmdline ...]
如果程序从文件中获取输入,则可以在程序的命令行添加@@; AFL将为您放置一个自动生成的文件名。
6)通过查看docs/status_screen.txt,来了解fuzzer UI中红色显示的内容。
在时间允许的情况下-尝试阅读以下文件:
-docs / README-AFL的一般介绍,
-docs / perf_tips.txt-有关如何快速模糊测试的简单提示,
-docs / status_screen.txt-用户界面中显示的提示的说明,
-docs / parallel_fuzzing.txt-在多个内核上运行AFL的建议。
1)导向性模糊测试的挑战
模糊测试是针对实际软件中的安全性问题最有效,最成熟的识别策略之一;它发现了迄今为止在安全性至关重要的软件中发现的绝大多数远程代码执行和特权提升错误。
不幸的是,模糊测试技术还比较浅显。盲目,随机的突变很难到达测试代码中的某些代码路径,从而导致某些漏洞是该技术无法发现的。
已经进行了许多尝试来解决这个问题。由Tavis Ormandy率先提出的早期方法之一是语料库蒸馏。该方法依靠覆盖信号从大量高质量的候选文件语料库中选择有趣种子的子集,然后通过传统方式对其进行模糊处理。该方法非常有效,但是需要这样的语料库是随时可用的。此外,块覆盖率测量仅提供了对程序状态的非常简单的理解,并且对于指导长距离的模糊测试工作没有多大用处。
其他更复杂的研究集中在诸如程序流分析(“共谋执行”),符号执行或静态分析之类的技术上。所有这些方法在实验环境中都是非常有前途的,但是在实际使用中往往会遇到可靠性和性能问题-并且目前还不能提供“愚蠢”模糊技术的可行替代方案。
2)afl-fuzz方法
American Fuzzy Lop是一种蛮力的模糊测试工具,采用了一个极其简单但是绝对可靠的,插桩代码导向的遗传算法。它使用修改后的边缘覆盖形式,毫不费力地拾取了程序控制流中局部的细微变化。
简化一下,整个算法可以总结为:
1)将用户提供的初始测试用例加载到队列中。
2)从队列中获取下一个输入文件。
3)尝试将测试用例修剪到最小尺寸,且不会改变该程序的测试行为。
4)使用平衡且经过充分研究的各种传统模糊测试策略反复更改文件。
5)如果产生的任何突变导致仪器记录了新的状态转换,则将变异的输出作为新条目添加到队列中。
6)转到2。
旧的测试用例会被更新的,覆盖率更高的测试用例所替代;并执行其他几个由仪器驱动的工作量最小的步骤。
作为模糊测试过程的附带结果,该工具创建了一个有趣的测试用例的小型独立式语料库。这些对于作为其他耗费人力或资源的测试机制的种子非常有用-例如,对浏览器,办公应用程序,图形套件或封闭源工具进行压力测试。
该模糊器经过了全面的测试,可提供开箱即用的性能,远优于盲目模糊或仅覆盖工具。
3)用于AFL的插桩程序
当源代码可用时,可以通过配套的注入检测工具,该工具可以在第三方代码的任何标准构建过程中替代gcc或clang。
仪器对性能的影响很小。结合由afl-fuzz实现的其他优化,大多数程序可以比传统工具更快地被模糊化。
重新编译目标程序的正确方法可能会有所不同,具体取决于生成过程的细节,但是几乎通用的方法是:
$C=/path/to/afl/afl-gcc ./configure
$make clean all
对于C++程序,您还需要设置CXX=/path/to/afl/afl-g++。
可以以相同的方式使用clang包装器(afl-clang和afl-clang++);clang用户也可以选择使用更高性能的检测模式,如llvm_mode/README.llvm中所述。
测试库时,您需要找到或编写一个简单的程序,该程序将从stdin或文件中读取数据,并将其传递给测试的库。在这种情况下,必须将此可执行文件链接到检测库的静态版本,或者确保在运行时加载正确的.so文件(通常通过设置LD_LIBRARY_PATH),这一点很重要。最简单的选择是静态构建,通常可以通过以下方式进行:
$CC=/path/to/afl/afl-gcc./configure --disable-shared
在调用“make”时设置AFL_HARDEN = 1将使CC包装器自动启用代码强化选项,从而使检测简单的内存错误更加容易。 Libdislocator是AFL随附的帮助程序库(请参阅libdislocator / README.dislocator)也可以帮助发现堆损坏问题。
PS:建议ASAN用户查看notes_for_asan.txt文件以获取重要注意事项。
4)检测二进制应用程序
如果没有源代码,则模糊器将提供实验支持,以快速、即时地检测黑匣子二进制文件。这是通过在鲜为人知的“用户空间仿真”模式下运行的QEMU版本完成的。
QEMU是与AFL分开的项目,但是您可以方便地构建,通过执行以下功能:
$ cd qemu_mode
$ ./build_qemu_support.sh
有关其他说明和警告,请参阅qemu_mode/README.qemu。
该模式比编译时检测工具慢大约2-5倍,对并行化的传导较少,并且可能还有其他一些怪事。
5)选择初始测试用例
为了正常运行,模糊器需要一个或多个启动文件,包含目标应用程序通常期望的输入数据的一个很好的示例。
有两个基本规则:
-文件较小。尽管并非绝对必要,但低于1KB是理想的。有关大小为何重要的讨论,请参见perf_tips.txt。
-仅在功能彼此不同的情况下才使用多个测试用例。使用五十张不同的度假照片来模糊测试图像库毫无意义。
您可以在此工具随附的testcases /子目录中找到许多很好的启动文件示例。
PS:如果有大量数据可用于筛选,则您可能需要使用afl-cmin实用程序来识别功能不同的文件的子集,这些文件在目标二进制文件中具有不同的代码路径。
6)模糊二进制
模糊处理过程本身由afl-fuzz实用程序执行。该程序需要一个带有初始测试用例的只读目录,一个单独的位置来存储其发现结果以及要测试的二进制文件的路径。
对于直接从stdin接受输入的目标二进制文件,通常的语法是:
$ ./afl-fuzz -i testcase_dir -o discovers_dir /path/to/program [... params ...]
对于从文件中获取输入的程序,请使用“@@”在目标的命令行中标记应放置输入文件名的位置。模糊测试器将代替您:
$ ./afl-fuzz -i testcase_dir -ofinders_dir/path/to/program @@
您也可以使用-f选项将变异数据写入特定文件。如果程序需要特定的文件扩展名,则此功能很有用。
可以在QEMU模式(在命令行中添加-Q)或传统的盲目模糊器模式(指定-n)中模糊非仪表式二进制文件。
您可以使用-t和-m覆盖已执行进程的默认超时和内存限制; 可能需要涉及这些设置的目标的罕见示例包括编译器和视频解码器。
perf_tips.txt中讨论了优化模糊测试性能的技巧。
请注意,afl-fuzz首先执行一系列确定性的模糊测试步骤,这可能需要花费几天的时间,但往往会产生简洁的测试用例。如果您想立即获得快速且肮脏的结果(类似于zzuf和其他传统的模糊测试器),请在命令行中添加-d选项。
7)解释输出
请参阅status_screen.txt文件以获取有关如何解释显示的统计信息和监视进程运行状况的信息。尤其是如果任何UI元素以红色突出显示时,请确保查阅此文件。
模糊过程会一直持续,直到您按Ctrl-C。至少,您希望允许模糊器完成一个队列周期,这可能需要几个小时到一周左右的时间。
在输出目录中创建并实时更新了三个子目录:
- queue/ 每个独特执行路径的测试用例,以及用户提供的所有起始文件。这是第2节中提到的综合语料库。
在将此语料库用于任何其他用途之前,可以使用afl-cmin工具将其缩小为较小的大小。 该工具将找到较小的文件子集,以提供等效的边缘覆盖率。
- crashes/ 导致被测试程序收到致命信号的独特测试用例(例如,SIGSEGV,SIGILL,SIGABRT)。这些条目按接收到的信号分组。
- hangs/ 导致测试程序超时的唯一测试用例。将某物分类为挂起之前的默认时间限制为1秒和-t参数的值中的较大者。
可以通过设置AFL_HANG_TMOUT来微调该值,但这很少需要。
如果关联的执行路径涉及以前记录的故障中未发现的任何状态转换,则崩溃和挂起被视为“唯一”。 如果可以通过多种方式解决一个错误,那么在此过程的早期阶段就会出现一定数量的膨胀,但这应该很快就会逐渐消失。
崩溃和挂起的文件名与父级非故障队列条目相关联。 这应该有助于调试。
当您无法重现由afl-fuzz发现的崩溃时,最可能的原因是您没有设置与该工具相同的内存限制。 尝试:
$ LIMIT_MB=50
$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )
更改LIMIT_MB以匹配传递给afl-fuzz的-m参数。 在OpenBSD上,还将-Sv更改为-Sd。
任何现有的输出目录也可以用于恢复已中止的作业。 尝试:$ ./afl-fuzz -i- -o existing_output_dir [...etc...]
如果安装了gnuplot,则还可以使用afl-plot为任何活动的模糊测试任务生成一些漂亮的图形。 举例来说,
参见http://lcamtuf.coredump.cx/afl/plot/。8)并行模糊
afl-fuzz的每个实例大约占用一个核心。 这意味着在多核系统上,并行化对于充分利用硬件是必需的。
有关如何在多核或多台联网机器上模糊通用目标的提示,请参阅parallel_fuzzing.txt。并行模糊模式也提供了一种简单的方法,用于将AFL与其他模糊器,符号执行程序或共存执行引擎等接口。 再次,请参见parallel_fuzzing.txt的最后一节以获取提示。
9)Fuzzer字典
默认情况下,afl-fuzz突变引擎针对紧凑的数据格式(例如图像,多媒体,压缩数据,正则表达式语法或shell脚本)进行了优化。 它不太适合具有特别冗长和冗余的语言的语言-特别是包括HTML,SQL或JavaScript。
为了避免构建语法感知工具的麻烦,afl-fuzz提供了一种方法,可以使用与目标数据类型关联的可选语言关键字,魔术头或其他特殊标记的字典来为模糊处理提供种子-并使用它来重构 随时随地的基础语法:
http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html
要使用此功能,首先需要以dictionaries/README.dictionaries中讨论的两种格式之一创建字典。 然后通过命令行中的-x选项将模糊器指向它。
(该子目录中已经提供了几个常用词典。)
无法提供对底层语法的更多结构化描述,但是模糊器可能会仅基于工具反馈来找出其中的一些。 实际上,这实际上是可行的,例如:
http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html
PS:即使没有给出明确的字典,afl-fuzz也会通过在确定性字节翻转期间密切观察工具来尝试提取输入语料库中现有的语法标记。 这适用于某些类型的解析器和语法,但不及-x模式。
如果真的很难获得字典,则另一种选择是让AFL运行一段时间,然后使用AFL附带的令牌捕获库。为此,请参见libtokencap / README.tokencap。
10)崩溃分类
基于覆盖率的崩溃分组通常会产生一个小的数据集,可以手动或使用非常简单的GDB或Valgrind脚本对其进行快速分类。
每次崩溃都可以追溯到队列中其父级非崩溃测试用例,从而更容易诊断故障。话虽如此,必须承认,如果不进行大量调试和代码分析工作,就很难快速评估某些模糊崩溃的可利用性。 为了协助完成此任务,afl-fuzz支持一种非常独特的“崩溃探索”模式,该模式启用了-C标志。
在这种模式下,模糊器将一个或多个崩溃的测试用例作为输入,并使用其反馈驱动的模糊策略来非常快速地枚举程序中可以到达的所有代码路径,同时将其保持在崩溃状态。
不导致崩溃的突变将被拒绝; 任何不影响执行路径的更改也是如此。
输出是一小批文件,可以对其进行快速检查,以查看攻击者对错误地址的控制程度,或者是否有可能越过初始越界读取-并查看其背后的内容。
哦,还有一件事:为了使测试用例最小化,请尝试一下afl-tmin。 该工具可以通过非常简单的方式进行操作:
$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
该工具适用于崩溃和非崩溃的测试用例。 在崩溃模式下,它将很乐意接受已检测和未检测的二进制文件。 在非崩溃模式下,最小化程序依靠标准的AFL工具来使文件更简单,而无需更改执行路径。
最小化器以与afl-fuzz兼容的方式接受-m,-t,-f和@@语法。
AFL的另一个最新功能是afl分析工具。 它获取一个输入文件,尝试顺序翻转字节,并观察被测试程序的行为。 然后,根据哪些部分看起来很关键,哪些不是关键部分,对输入进行颜色编码。 尽管不是防弹产品,但它通常可以提供对复杂文件格式的快速见解。 有关其操作的更多信息,请参见technical_details.txt的末尾。
11)超越崩溃
模糊测试也是一种发现未崩溃的设计和实现错误的出色且未充分利用的技术。 在以下情况下,通过修改目标程序以调用abort()来发现许多有趣的错误:
给定相同的模糊器生成的输入时,两个bignum库会产生不同的输出,
当要求图像库连续多次解码同一张输入图像时,图像库会产生不同的输出,
当迭代序列化和反序列化模糊器提供的数据时,序列化/反序列化库无法产生稳定的输出,
当要求压缩然后解压缩特定的Blob时,压缩库会产生与输入文件不一致的输出。
实施这些或类似的健全性检查通常只需要很少的时间。
如果您是特定软件包的维护者,则可以使用#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION(也与libfuzzer共享的标志)或#ifdef __AFL_COMPILER(此代码仅用于AFL)将此代码作为条件。12)常识性风险
请记住,与许多其他计算密集型任务类似,模糊测试可能会给您的硬件和操作系统造成压力。 特别是:
目标程序最终可能会失控地抢夺GB的内存或用垃圾文件填充磁盘空间。 AFL试图强制执行基本的内存限制,但不能防止每一个可能的事故。 最重要的是,您不应该对那些数据丢失风险不可接受的系统感到困惑。
模糊测试涉及对文件系统的数十亿次读取和写入。 在现代系统上,这通常会被大量缓存,从而导致相当适度的“物理” I/O-但有许多因素可能会改变此等式。
监视潜在故障是您的责任; 如果I/O非常繁重,则许多HDD和SSD的使用寿命可能会缩短。在Linux上监视磁盘I/O的一个好方法是'iostat'命令:
$ iostat -d 3 -x -k [...optional disk ID...]
13)已知的局限性和需要改进的地方
以下是AFL最重要的警告:
-AFL通过检查由于信号(SIGSEGV,SIGABRT等)而导致的第一个生成进程死亡来检测故障。安装这些信号的自定义处理程序的程序可能需要注释掉相关代码。同样,除非您手动添加一些代码来捕获被模糊目标所产生的子处理中的错误,否则可能会避开检测。
-与任何其他蛮力工具一样,如果使用加密,校验和,加密签名或压缩来完全包装要测试的实际数据格式,则模糊器的覆盖范围有限。
要解决此问题,您可以注释掉相关检查(请参阅experimental/libpng_no_checksum/以获取灵感);如果无法做到这一点,您还可以编写一个后处理器,如experimental/post_library/中所述。
-在ASAN和64位二进制文件上有一些不幸的折衷。这不是由于afl-fuzz的任何特定故障引起的;请参阅notes_for_asan.txt以获取提示。
-不直接支持需要UI交互才能正常工作的网络服务,后台守护程序或交互式应用程序的模糊化。您可能需要进行简单的代码更改,以使它们以更传统的方式运行。 Preeny也可能提供一个相对简单的选项-请参阅:
https://github.com/zardus/preeny
还可以在以下位置找到一些有关修改基于网络的服务的有用提示:
https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop-AFL不会输出人类可读的覆盖率数据。如果要监视覆盖范围,请使用Michael Rash的afl-cov:https://github.com/mrash/afl-cov
-有时,有意识的机器会与他们的创造者对立。如果您遇到这种情况,请查阅http://lcamtuf.coredump.cx/prep/。
除此之外,请参阅INSTALL以获取特定于平台的提示。
15)联系
有什么问题吗 有问题吗 错误报告? 通常可以通过
与作者联系。 该项目还有一个邮件列表。 要加入,请将邮件发送到
。 或者,如果您更喜欢浏览
首先存档,请尝试:https://groups.google.com/group/afl-users
PS:如果您希望提交原始代码以将其合并到项目中,请注意,AFL大部分内容的版权已由Google声明。 尽管您的确保留版权,但他们确实要求人们首先同意简单的CLA:
https://cla.developers.google.com/clas
如果造成的麻烦很抱歉。 当然,功能请求或错误报告不需要CLA。
性能优化技巧
该文件提供了对速度较慢或浪费时间的模糊作业进行故障排除的提示。
有关一般说明手册,请参见README。
1)使您的测试用例保持较小
这可能是最重要的一步!大型测试用例不仅需要被测试的二进制文件花费更多的时间和内存来解析,而且还使得模糊测试处理的效率大大降低。
为了说明这一点,假设您随机地一次翻转文件中的位。假设如果您翻转#47位,将会遇到一个安全漏洞;翻转任何其他位只会导致文档无效。
现在,如果您的开始测试用例的长度为100个字节,那么您将有71%的机会在前1,000个exec中触发错误——不错!但是,如果测试用例的长度为1 KB,则我们将在同一时间范围内随机击中正确模式的可能性将降低至11%。而且,如果它具有10 KB的非必需杂物,则几率骤降到1%。
最重要的是,在输入较大的情况下,二进制文件目前的运行速度可能比以前慢5到10倍-因此模糊测试的总体效率可能很容易下降高达500倍左右。
在实践中,这意味着您不应该用假期照片来对图像解析器进行模糊测试。而是生成一张很小的16x16图片,并通过jpegtran或pngcrunch运行该图片以取得良好效果。大多数其他类型的文档也是如此。
../testcases/*中有很多小型的开始测试用例-试试看或提交新的!
如果要以更大的第三方语料库开头,请首先在该数据集上运行afl-cmin并设置超时时间。
2)使用更简单的目标
考虑在模糊测试中使用更简单的目标二进制文件。例如,对于图像格式,捆绑的实用程序(例如djpeg,readpng或gifhisto)比ImageMagick的转换工具要快(10-20倍)——所有这些都在执行大致相同的库级图像解析代码。
即使您没有针对特定目标的轻量级工具,也请记住,您始终可以使用另一个相关的库来生成语料库,然后将其手动输入到耗费更多资源的程序中。
3)使用LLVM检测
当对缓慢的目标进行模糊处理时,可以使用llvm_mode / README.llvm中介绍的基于LLVM的检测模式,将性能提高2倍。请注意,此模式需要使用clang,不适用于GCC。
LLVM模式还提供了一种“持久”的进程内模糊测试模式,该模式对于某些类型的自包含库可以很好地工作,对于快速目标,可以将性能提高5-10倍;以及“延迟派生服务器”模式,该模式可以为具有高启动开销的程序提供巨大的好处。两种模式都要求您编辑模糊程序的源代码,但这些更改通常只相当于战略性地写一两行代码。。
4)分析并优化二进制文件
检查任何明显改善性能的参数或设置。例如,可以用以下命令调用IJG jpeg和libjpeg-turbo随附的djpeg实用程序:
-dct fast -nosmooth -onepass -dither none -scale 1/4
这将加快速度。解码图像的质量相应下降,但是您可能并不在意。
在某些程序中,可以完全禁用输出,或者至少使用计算上更快的输出格式。例如,使用图像转码工具,转换成BMP文件要比转换成PNG快得多。
对于某些悠闲的解析器,启用“严格”模式(即,在出现首次错误后进行救助)可能会导致文件更小,运行时间更长而又不牺牲覆盖率;例如,对于sqlite,您可能需要指定-bail。
如果程序仍然太慢,则可以使用strace -tt或同等的性能分析工具来查看目标二进制文件是否在做任何愚蠢的事情。有时,您可以通过指定/dev/null作为配置文件来加快速度,或者禁用一些工作中并不需要的编译时功能(尝试./configure --help)。众所周知,消耗资源的事情之一是通过exec *(),popen(),system()或等效调用来调用其他实用程序。例如,当tar确定输入文件是压缩档案时,它可以调用外部解压缩工具。
一些程序还可能故意调用sleep(),usleep()或nanosleep();vim是一个很好的例子。其他程序可能会尝试fsync()等等,有些第三方库可以很容易地删除此类代码,例如:
https://launchpad.net/libeatmydata
在由于不可避免的初始化开销而导致速度缓慢的程序中,您可能需要尝试LLVM延迟的forkserver模式(请参阅llvm_mode / README.llvm),如上所述,它可以使速度提高多达10倍。
最后但并非最不重要的一点是,如果您正在使用ASAN并且性能不可接受,请考虑暂时将其关闭,然后稍后使用启用了ASAN的二进制文件手动检查生成的语料库。
5)测试你想测试的
仅对您现在实际想要进行压力测试的库进行一次测试。让程序将系统范围内的非仪表库用于您实际上不想模糊的任何功能。例如,在大多数情况下,不应该仅仅因为您要测试依赖于大数数学的加密应用程序而检测libgmp。
谨防奇怪的第三方库附带的与源代码捆绑在一起的程序(Spidermonkey是一个很好的例子)。选中./configure选项以使用非仪器范围的副本。
6)使您的模糊器并行
该模糊器设计为每个作业需要〜1个核心。这意味着,在一个4核系统上,您可以轻松运行四个并行的模糊测试作业,而性能损失相对较小。有关如何执行此操作的提示,请参见parallel_fuzzing.txt。
afl-gotcpu实用程序可以帮助您了解系统上是否还有空闲的CPU容量。(它不会告诉您有关内存带宽,缓存未命中率或类似因素的信息,但不太可能引起您的关注。)
7)检查内存使用情况和超时
如果您增加了-m或-t限制,超出了实际需要,请考虑将其重置。
对于名义上速度非常快但对于某些输入变得缓慢的程序,您也可以尝试设置-t值,该值比afl-fuzz自己敢使用的值更具惩罚性。在快速闲置的机器上,降低到-t 5可能是一个可行的计划。
-m参数也值得一看。当出现病理性输入时,某些程序最终可能会花费大量时间来分配和初始化兆字节的内存。-m值低可以使它们更早放弃并且不浪费CPU时间。
8)检查操作系统配置
有几种操作系统级别的因素可能会影响模糊测试速度:
-高系统负载。尽可能使用闲置的计算机。杀死所有不必要的CPU消耗(空闲的浏览器窗口,媒体播放器,复杂的屏幕保护程序等)。
-网络文件系统,用于模糊器的输入/输出,或由模糊的二进制文件访问以读取配置文件(要特别注意主目录-许多程序在其中搜索点文件)。
-按需CPU缩放。Linux“按需”调控器会按特定的时间表执行分析,并且众所周知,它会低估由afl-fuzz(或任何其他fuzzer)产生的短暂进程的需求。在Linux上,可以通过以下方法解决此问题:
cd /sys/devices/system/cpu
echo performance | tee cpu*/cpufreq/scaling_governor
在其他系统上,CPU扩展的影响将有所不同。在进行模糊测试时,请使用特定于操作系统的工具来确定所有内核是否都在全速运行。
-透明的大页面。在内核中启用透明大页面(THP)时,某些分配器(例如jemalloc)可能会产生大量的模糊测试。您可以通过以下方式禁用此功能:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
-次优调度策略。每个目标的重要性各不相同,但是在Linux上,您可能需要确保设置以下选项:
echo 1 >/proc/sys/kernel/sched_child_runs_first
echo 1 >/proc/sys/kernel/sched_autogroup_enabled
为Fuzzer进程设置不同的调度策略(例如SCHED_RR)通常也可以加快速度,但是需要格外小心。
9)如果所有其他选项均失败,请使用-d
对于真正很慢的程序,如果您真的无法使用大输入文件来逃脱,或者仅想在早期获得快速而肮脏的结果,则始终可以使用-d模式。
该模式使afl-fuzz跳过所有确定性的模糊步骤,从而使输出的整洁度降低很多,并最终使测试的深度降低一些,但是它将为您提供其他模糊工具的熟悉体验。
了解状态屏幕
本文档概述了状态屏幕-以及用于解决所有警告的提示和UI中显示的红色文本。有关一般说明手册,请参见自述文件。
0)关于颜色的笔记
状态屏幕和错误消息使用颜色使内容保持可读性,并吸引您注意最重要的细节。例如,红色几乎总是表示“咨询此文档” :-)
不幸的是,只有当您的终端使用传统的un * x调色板(黑色背景上的白色文本)或接近该调色板时,UI才能正确呈现。
如果您正在使用反向视频,则可能需要更改设置,例如:
-对于GNOME终端,请转到“编辑”>“配置文件”首选项,选择“颜色”选项卡,然后从内置方案列表中选择“白底黑字”。
-对于MacOS X Terminal应用程序,通过“外壳程序”>“新建窗口”菜单使用“专业”方案打开一个新窗口(或将“专业”设置为默认设置)。
另外,如果您确实喜欢当前的颜色,则可以编辑config.h以注释掉USE_COLORS,然后执行“全部清除”。
我不知道有任何其他简单的方法可以在不引起其他副作用的情况下进行此工作-对此感到抱歉。
顺便说一句,让我们谈谈屏幕上的实际内容...
1)Process timing(处理时间)
+----------------------------------------------------+
| run time : 0 days, 8 hrs, 32 min, 43 sec |
| last new path : 0 days, 0 hrs, 6 min, 40 sec |
| last uniq crash : none seen yet |
| last uniq hang : 0 days, 1 hrs, 24 min, 32 sec |
+----------------------------------------------------+
本部分的内容不言自明:它告诉您模糊器已经运行了多长时间,以及自从最近一次发现以来已经花费了多少时间。它被分解为“路径”(触发新执行模式的测试用例的简写),崩溃和挂起。
在计时方面:没有硬性规定,但是大多数测试工作要持续数天或数周。实际上,对于一个中等复杂的项目,第一阶段可能需要一天左右的时间。时不时地,一些工作将被允许运行数月。
有一件重要的事情要提防:如果该工具在启动后的几分钟内没有找到新路径,则可能是您没有正确调用目标二进制文件,并且它永远也无法解析我们要扔给它的输入文件;另一个可能的解释是,默认内存限制(-m)过于严格,并且程序未能尽早分配缓冲区后退出。或者输入文件显然是无效的,并且始终未通过基本标头检查。
如果一段时间内没有新路径出现,您最终也会在此部分看到一个红色的大警告:-)
2)Overall results(总体结果)
+-----------------------+
| cycles done : 0 |
| total paths : 2095 |
| uniq crashes : 0 |
| uniq hangs : 19 |
+-----------------------+
本节的第一个字段为您提供到目前为止已完成的队列通过次数-即模糊器遍历到目前为止已发现的所有有趣测试用例,对其进行模糊处理并循环回到最开始的次数。每个模糊测试会话都应至少完成一个周期。理想情况下,运行时间应更长。
如前所述,第一次通过可能需要一天或更长的时间,因此请坐下来放松。如果您想立即获得更广泛但更浅的覆盖范围,请尝试-d选项-通过跳过确定性的模糊化步骤,它可以为您提供更熟悉的体验。但是,它在一些微妙的方面劣于标准模式。
为了帮助您在按下Ctrl-C时进行呼叫,循环计数器使用颜色编码。它在第一次通过时以洋红色显示,如果在随后的回合中仍在发现新发现,则变为黄色,然后在结束时变为蓝色-最终,在较长时间没有看到任何动作后,变成绿色。
屏幕的此部分中的其余字段应该非常明显:到目前为止,已经发现了数量众多的测试用例(“路径”)以及独特故障的数量。如自述文件中所述,可以通过浏览输出目录来实时探索测试用例,崩溃和挂起。
3)Cycle progress(周期进度)
+-------------------------------------+
| now processing : 1296 (61.86%) |
| paths timed out : 0 (0.00%) |
+-------------------------------------+
该框告诉您当前队列周期在模糊器的距离:显示当前正在处理的测试用例的ID,以及由于持续超时而决定放弃的输入数量。
有时在第一行中显示的“ *”后缀表示当前处理的路径不是“有利的”(此属性将在后面的第6节中讨论)。
如果您认为模糊器的进度太慢,请参阅本文档第2节中有关-d选项的注释。
4)Map coverage(地图覆盖)
+--------------------------------------+
| map density : 10.15% / 29.07% |
| count coverage : 4.03 bits/tuple |
+--------------------------------------+
本节提供一些有关目标二进制文件中嵌入的仪器所观察到的覆盖范围的琐事。
框中的第一行告诉您,我们已经命中了多少个分支元组,与位图可以容纳的比例成比例。左边的数字描述了当前输入;右边的是整个输入语料库的值。
提防极端情况:
-低于200的绝对数字表明以下三种情况之一:该程序非常简单;它没有被正确检测(例如,由于与目标库的非工具副本链接); 或它在输入测试用例中过早失效。模糊器将尝试将其标记为粉红色,以使您意识到。
-过度使用大量模板生成的代码的非常复杂的程序可能很少会发生超过70%的百分比。
因为高的位图密度使模糊器更难可靠地识别新程序状态,所以我建议使用AFL_INST_RATIO = 10左右重新编译二进制文件,然后重试(请参阅env_variables.txt)。
模糊器将以红色标记高百分比。很有可能,除非您用模糊处理软件(例如v8,perl和ffmpeg)进行测试,否则您永远不会看到它。
另一行处理二进制中元组命中计数的变化。本质上,如果对于我们尝试的所有输入,每个采用的分支始终采用固定的次数,则它将显示为“ 1.00”。当我们设法触发每个分支的其他命中计数时,指针将开始向“ 8.00”移动(8位映射命中的每个位),但可能永远不会达到极限。
在一起使用时,这些值可用于比较依赖同一检测二进制文件的几个不同的模糊测试作业的覆盖范围。
5)Stage progress(阶段进度)
+-------------------------------------+
| now trying : interest 32/8 |
| stage execs : 3996/34.4k (11.62%) |
| total execs : 27.4M |
| exec speed : 891.7/sec |
+-------------------------------------+
这部分让您深入了解模糊器当前正在做什么。它告诉您当前阶段,可以是以下任何一个:
-校准-预模糊阶段,在该阶段中,将检查执行路径以检测异常,确定基线执行速度等。只要有新发现,就会非常简短地执行。
-修剪L / S-另一个预模糊阶段,在该阶段中,将测试用例修剪为最短的形式,仍然产生相同的执行路径。长度(L)和步长(S)通常根据文件大小来选择。
-bitflip L / S-确定性的位翻转。在任何给定时间切换L位,使输入文件以S位递增。当前的L / S变体为:1 / 1、2 / 1、4 / 1、8 / 8、16 / 8、32 / 8。
-arith L / 8-确定性算术。模糊器试图将小整数减去或加到8位,16位和32位值。步进总是8位。
- interest L / 8-确定性值覆盖。模糊器有一个已知的“有趣的” 8位,16位和32位值列表供您尝试。步进为8位。
-额外功能-确定性地注入词典术语。这可以显示为“用户”或“自动”,这取决于模糊器是使用用户提供的词典(-x)还是自动创建的词典。您还会看到“ over”或“ insert”,具体取决于字典单词是覆盖现有数据还是通过偏移剩余数据以适应其长度来插入。
-破坏-具有一定长度的周期,带有堆叠的随机调整。在此阶段尝试的操作包括位翻转,使用随机和“有趣的”整数进行覆盖,块删除,块复制以及各种与字典相关的操作(如果首先提供字典)。
-拼接-一种最后的策略,在没有新路径的第一个完整队列周期后开始执行。它等效于“破坏”,除了它首先在任意选择的中点将来自队列的两个随机输入拼接在一起。
-sync-仅当设置-M或-S时使用的阶段(请参见parallel_fuzzing.txt)。不涉及真正的模糊测试,但是该工具会扫描其他模糊测试器的输出,并根据需要导入测试用例。第一次执行此操作可能需要几分钟左右。
其余字段应该是不言而喻的:存在当前阶段的exec计数进度指示器,全局exec计数器以及当前程序执行速度的基准。这可能会从一个测试用例到另一个测试用例波动,但是理想情况下,基准在大多数情况下应超过500 execs / sec-如果保持低于100,则工作可能会花费很长时间。
模糊测试器还将明确警告您有关慢速目标的信息。如果发生这种情况,请参阅模糊器随附的perf_tips.txt文件,以获取有关如何加快速度的想法。
6)(Findings in depth)深入发现
+--------------------------------------+
| favored paths : 879 (41.96%) |
| new edges on : 423 (20.19%) |
| total crashes : 0 (0 unique) |
| total tmouts : 24 (19 unique) |
+--------------------------------------+
这为您提供了一些最适合完成书呆子的指标。本节包括基于代码中包含的最小化算法(这将获得更多的播放时间),模糊器最喜欢的路径数。实际上导致更好的边缘覆盖率的测试用例(与仅仅推动分支命中计数器相反)。还有其他更详细的计数器,用于崩溃和超时。
请注意,超时计数器与挂起计数器有所不同。这包括超过超时的所有测试用例,即使它们没有超出超时的程度也足以将其分类为挂起。
7)Fuzzing strategy yields(模糊策略收益)
+-----------------------------------------------------+
| bit flips : 57/289k, 18/289k, 18/288k |
| byte flips : 0/36.2k, 4/35.7k, 7/34.6k |
| arithmetics : 53/2.54M, 0/537k, 0/55.2k |
| known ints : 8/322k, 12/1.32M, 10/1.70M |
| dictionary : 9/52k, 1/53k, 1/24k |
| havoc : 1903/20.0M, 0/0 |
| trim : 20.31%/9201, 17.05% |
+-----------------------------------------------------+
这只是另一个面向书呆子的部分,用于跟踪我们之前讨论的每种模糊测试策略中与尝试执行的人员数量成比例的网状路径。这有助于令人信服地验证有关afl-fuzz采取的各种方法的有效性的假设。
本节中的调整策略统计信息与其余统计信息略有不同。这行的第一个数字显示从输入文件中删除的字节数的比率;第二个对应于实现此目标所需的执行人员数量。最后,第三个数字显示了虽然无法删除但被认为没有效果并且被排除在某些更昂贵的确定性模糊处理步骤之外的字节比例。
8) Path geometry(路径几何)
+---------------------+
| levels : 5 |
| pending : 1570 |
| pend fav : 583 |
| own finds : 0 |
| imported : 0 |
| stability : 100.00% |
+---------------------+
本节中的第一个字段跟踪通过引导的模糊过程达到的路径深度。本质上:用户提供的初始测试用例被认为是“ 1级”。通过传统的模糊测试可以从中得出的测试用例被认为是“ 2级”。通过将它们用作后续模糊测试回合的输入而得出的结果为“ 3级”;等等。因此,最大深度可以大致代表您从af-fuzz采取的仪器指导方法中获得的价值。
下一个字段显示尚未经过任何模糊测试的输入数量。对于模糊器真正希望在此队列周期中到达的“最喜欢”条目,也提供了相同的统计信息(非最喜欢条目可能必须等待几个周期才能获得机会)。
接下来,我们获得了在此模糊测试部分发现的并在进行并行化模糊测试时从其他模糊测试器实例导入的新路径的数量;以及相同输入的出现程度有时会在测试的二进制文件中产生可变的行为。
最后一点实际上很有趣:它可以测量观察到的迹线的一致性。如果程序对于相同的输入数据始终表现相同,则它将获得100%的分数。当该值较低但仍显示为紫色时,模糊过程不太可能受到负面影响。如果变成红色,则可能会遇到麻烦,因为AFL将很难分辨调整输入文件的有意义和“幻像”效果。
现在,大多数目标只会获得100%的分数,但是当您看到较低的数字时,有几件事情要注意:
-在测试的二进制文件中结合使用未初始化的内存和某些内在的熵源。对AFL无害,但可能表示存在安全漏洞。
-尝试操纵持久资源,例如剩余的临时文件或共享内存对象。这通常是无害的,但您可能需要仔细检查以确保程序不会过早地退出。磁盘空间,SHM句柄或其他全局资源不足也会触发此情况。
-达到某些实际上旨在随机运行的功能。通常无害。例如,在对sqlite进行模糊处理时,输入“ select random();”之类的 将触发变量执行路径。
-多个线程以半随机顺序一次执行。当“稳定性”指标保持在90%左右时,这是无害的,但如果不是这样,则可能成为问题。这是尝试的方法:
-使用llvm_mode /中的afl-clang-fast--使用线程本地跟踪模型,该模型不太容易出现并发问题,
-查看目标是否可以在没有线程的情况下编译或运行。常见的./configure选项包括--without-threads,-disable-pthreads或--disable-openmp。
-用GNU Pth(https://www.gnu.org/software/pth/)替换pthread,这使您可以使用确定性调度程序。
-在持久模式下,“稳定性”指标的轻微下降可能是正常的,因为重新输入时并非所有代码的行为都相同;但重大下降可能表示__AFL_LOOP()中的代码在后续迭代中行为不正确(例如,由于状态的不完全清理或重新初始化),并且大部分的测试工作都浪费了。
检测到变量行为的路径在
/queue/.state/variable_behavior/目录中用匹配的条目标记,因此您可以轻松查找它们。 9)CPU load(CPU负载)
[cpu: 25%]
这个小部件显示了本地系统上明显的CPU利用率。通过获取处于“可运行”状态的进程数,然后将其与系统上的逻辑核心数进行比较来计算它。
如果该值显示为绿色,则说明您使用的CPU内核数少于系统上可用的CPU核数,并且可能可以并行使用以提高性能。有关如何执行操作的提示,请参见parallel_fuzzing.txt。
如果该值显示为红色,则说明CPU *可能*被超额订购,并且运行更多的模糊测试可能不会给您带来任何好处。
当然,此基准非常简单;它告诉您准备运行多少个进程,而不告诉您它们可能需要多少资源。它还没有区分物理内核,逻辑内核和虚拟CPU。这些功能的性能特征会有很大的不同。
如果要更精确的测量,可以从命令行运行afl-gotcpu实用程序。
10)Addendum: status and plot files(附录:状态和图文件)
对于无人值守的操作,一些关键状态屏幕信息也可以在输出目录的fuzzer_stats文件中以机器可读的格式找到。这包括:
-start_time-Unix时间,表示af-fuzz的开始时间
-last_update-与此文件的最后更新相对应的Unix时间
-fuzzer_pid-模糊器进程的PID
-cycles_done-队列周期到目前为止已完成
-execs_done-尝试执行execve()的次数
-execs_per_sec-当前每秒的execs数
-path_total-队列中的条目总数
-path_found-通过本地检测发现的条目数
-path_imported-从其他实例导入的条目数
-max_depth-生成的数据集中的级别数
-cur_path-当前处理的条目号
-ending_favs-仍在等待模糊处理的首选条目数
- pending_total -等待被模糊处理的所有条目数
- stability -行为一致的位图字节的百分比
-variable_paths-显示变量行为的测试用例数
-unique_crashes-记录的唯一崩溃次数
-unique_hangs-遇到的唯一挂起次数
其中大多数直接映射到前面讨论的UI元素。
最重要的是,您还可以找到一个名为“ plot_data”的条目,其中包含大多数这些字段的绘图表历史记录。如果安装了gnuplot,则可以使用随附的“ afl-plot”工具将其转换为不错的进度报告。
安装说明
本文档提供了基本的安装说明,并讨论了各种平台的已知问题。 有关一般说明手册,请参见自述文件。
1)在x86上的Linux
该平台有望运行良好。 用以下命令编译程序:
$make
您无需安装即可开始使用模糊器,但也可以
用以下命令安装:#make install
没有特别的依赖可言。 您将需要GNU make和有效的编译器(gcc或clang)。与该程序捆绑在一起的一些可选脚本可能取决于bash,gdb和类似的基本工具。
如果您使用的是clang,请查看llvm_mode / README.llvm; 与传统方法相比,LLVM集成模式可以显着提高性能。
您可能必须更改几个设置才能获得最佳效果(最显着的是,禁用崩溃报告实用程序并切换到其他CPU调控器),但是afl-fuzz会在必要时指导您进行操作。
其他平台的安装读者自己翻译吧,我只是边学边做笔记,不做工具人:)
环境:VMware,kali Linux
afl
我下载的是2.52b
apt-get http://lcamtuf.coredump.cx/afl/releases/afl-2.52b.tgz
tar -zxvf afl-2.52b.tgz
cd afl-2.52b
make
5秒左右完成。
make install
5秒左右完成。
afl-fuzz
afl-fuzz [选项] --需要模糊测试的应用程序的路径
必填参数:
-i 目录 带有测试用例的输入目录
-o 目录 用于保存模糊检查结果的输出目录
执行控制设置:
-f 文件 由模糊程序(stdin)读取的位置
-t 毫秒 每次运行的超时时间(自动缩放,50-1000毫秒)
-m 内存 子进程的内存限制(50 MB)
-Q 使用仅二进制检测(QEMU模式)
模糊行为设置:
-d 快速脏模式(跳过详细的步骤)
-n 不带指令的模糊测试(哑模式)
-x 目录 可选的模糊器字典(请参阅README)其他的东西:
-T 文字 文字横幅以显示在屏幕上
-M / -S id 分布式模式(请参阅parallel_fuzzing.txt)
-C 崩溃探索模式(秘鲁兔子的东西???什么鬼,大概是来自于某国语言)
有关其他提示,请查阅/ usr / local / share / doc / afl / README。
afl_test.c
#include
#include
#include
#include
#include
int vuln(char *str)
{
int len = strlen(str);
if(str[0] == 'A' && len == 66)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为A并且长度为66,则异常退出
}
else if(str[0] == 'F' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为6,则异常退出
}
else
{
printf("it is good!\n");
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100]={0};
gets(buf);//存在栈溢出漏洞
printf(buf);//存在格式化字符串漏洞
vuln(buf);
return 0;
}
afl-gcc -g -o afl_test afl_test.c
创建输入输出目录
mkdir fuzz_in fuzz_out
测试数据
vim testcase
里面就写aaa吧
Ctrl-C 结束
xxd查看crashes中的结果
源代码中设置的F开头报错。如果运行时间足够长,应该会发现所有问题。
语料库
lcamtuf的博客中有一篇文章凭空出现的JPEG,展示了AFL的强大,从hello world作为输入,到变异成JPEG,当然使用了8核系统,花费了6个小时,所以输入还是很重要的,有时间再做进一步的深入学习。
afl
AFL使用指南
初探AFL-Fuzz
未完待续...
更多内容查看:网络安全-自学笔记
喜欢本文的请动动小手点个赞,收藏一下,有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。