AFL-Fuzzing新手初探纪 本文累计 11579 字, 最后更新时间:2022年03月15日 ### 0x00 说在前面 未完待续,大坑警告 (: 这次预计撰写一套系列文章,讲讲作为一个新手如何使用AFL(American Fuzzy Lop)来一步步接触学习Fuzzing漏洞发掘以及实战fuzz测试开源项目库,最终挖掘到属于自己的CVE漏洞。~~但愿..~~ 知识点预告: - C语言基础 - Docker简单操作 - 二进制漏洞发掘知识 - Linux文件ELF - ....想到再补充 ### 0x01 初探Fuzzing 我们先来简单介绍一些概念。 #### 什么是模糊测试? 定义:模糊测试是一种通过自动或半自动的生成随机数据输入到一个程序中,并监视程序异常,以发现可能的安全漏洞的技术,就是用大量的随机输入去测试软件的健壮性等,最早是软件测试的概念。后来出现了AFL,便出现了以覆盖率为导向的模糊测试技术。 #### 什么是AFL呢? American Fuzzy Lop (简称:Afl-fuzz)是一个优秀的模糊测试工具。使用Afl-fuzz 在有源码条件下可以使用afl-gcc 或者 afl-clang-fast 编译源码,afl在编译的时候完成插桩,如果无源码条件下可以使用qemu模式进行插桩. 对于Fuzzing网络程序,可以使用persistent模式进行测试。 #### 常见的漏洞发掘技术有哪些? 进行软件漏洞挖掘时,通常有静态分析(staticanalysis)、动态分析(dynamicanalysis)、符号执行(symbolicexecution)、模糊测试(fuzzing)这几种技术手段。 **静态分析** 就是不真正的运行目标程序,但是通过对它进行各种语法、语义、数据流等的分析,来进行漏洞发掘。静态分析是由静态分析软件完成的;它的速度快,但是误报率高。 **动态分析** 就是我们通常见到的大佬们用od一步步跟踪程序运行进行的分析。它的准确率很高,但是需要调试人员丰富的知识储备,而且这种调试方法很难进行大规模的程序漏洞挖掘。 **符号执行** 简单来说,就是试图找到什么输入对应什么样的运行状态,它要去覆盖所有的执行路径。因此,当被分析的程序比较复杂,有很多执行路径时,就会遇到路径爆炸的问题。 **模糊测试** 不需要人过多的参与,也不像动态分析那样要求分析人员有丰富的知识。简单解释,它就是用大量的输入数据自动去执行程序,从而发现哪些输入能够使程序发生异常,进而分析可能存在的漏洞。当前比较成功的fuzzer(执行模糊测试的程序)有AFL、libFuzzer、OSS-Fuzz等。 #### 什么是插桩? 简单来说,它就是在目标程序的代码中插入一些额外的代码,来通知fuzzer目标程序的运行情况。 #### 输入数据 因为要用输入数据去自动执行程序,很明显数据的生成会极大的影响挖掘效率。 1. 假如目标程序的输入格式是pdf文件,那么不符合该格式的文件就很难进入到目标程序内部进行运行测试。 2. 即使是符合输入要求的数据,也许数据A和数据B触发相同的执行路径,那么让A和B都运行就是在浪费资源。 3. 对于单独的数据A,也许其中真正控制执行路径的只是一小部分,那么在其余部分的处理就是在浪费资源。 对于第一个输入格式的问题,generation-basedfuzzer给出了可行的解决方案。 简单来说,它要求一些关于输入数据格式的先验知识,这样它就可以更好地根据用户输入数据产生新数据。 对于第二和第三个问题,AFL中给出了相应的解决办法。Afl-cmin能够给出输入数据的最小集合, 也就是会把上述的A和B留其一; afl-tmin则能够将单个输入文件进行压缩。 #### 变异操作 用户给出的数据是有限的, 但是进行fuzz测试需要**大量的数据**, 因此fuzzer会根据用户给出的数据产生新的数据,这一过程即所谓的变异操作。 那么变异过程中定义哪些变异操作符(即哪些改变原输入数据的操作)? 在一次变异时面对多个变异操作符该选择哪个? 选用哪些输入数据进行变异? 注: 对Fuzz数据变异感兴趣的同学可以自行搜索“遗传算法”等。 #### 提高覆盖率 Fuzz的本质就是用输入去检测当前输入对应的执行路径会不会产生可能的漏洞。 因此,如果覆盖更多的路径,就意味着可能检测出更多的漏洞。 **提高覆盖率更像是一个根本性问题,前两个问题的解决其实也是在提高覆盖率。** #### 模糊测试的优点 与传统漏洞挖掘方法相比, 模糊测试技术有其无法比拟的优势。 模糊测试的测试目标是二进制可执行代码, 比基于源代码的白盒测试适用范围更广; 模糊测试是动态实际执行的,不存在静态分析技术中存在的大量误报问题; 模糊测试的原理简单,没有大量的理论推导和公式计算,不存在符号执行技术中的路径状态爆炸问题; 模糊测试自动化程度高,不需要逆向工程中大量的人工参与。 **模糊测试技术的优点使它成为一种应用范围广泛的漏洞挖掘技术。** #### 模糊测试的局限性 (1) 对访问控制漏洞无能为力,因为模糊测试系统无法理解程序的逻辑,所以如一些违反权限控制的安全漏洞难以发现。 (2) 受制于糟糕的设计逻辑。糟糕的设计逻辑并不会导致程序崩溃,而模糊测试发现漏洞一个主要依据是监控目标系统的异常和错误信息,因此模糊测试难以发现这类漏洞。 (3) 无法识别多点触发漏洞,当前的模糊测试技术往往只能挖掘出由单个因素引起的漏洞,而对于需要多条件才能触发的漏洞却无能为力。 **即,代码覆盖率到达不了100%, 代码覆盖率是说,这次自动化测试触发了的代码占整体代码的比率是多少.要想对一个程序的所有代码都要测试到,这样的代码覆盖率就是100% ,这是不可能的,因为会有很多的功能和代码是需要联合起来触发的,有的代码触发条件逻辑非常复杂,这些都是Fuzzing 的短板,Fuzzing 在对某一个攻击点测试上效果是很好的,一个程序会有很多的攻击点,所以要针对各个不同的攻击点都要写不同的Fuzzer ,提高Fuzzing 代码覆盖率.** #### 建议 1. 目前,Web应用中存在大量拒绝服务(Dos)、跨站脚本(XSS)、SQL注入(SQL injection)等漏洞,Web应用模糊测试不仅可以发现Web应用本身的漏洞,还可以发现Web服务器和数据库服务器的漏洞。建议通过模糊测试的方法和工具,对Web应用进行漏洞挖掘。 2. Android在手机的市场上占有率很高,通过模糊测试不但可以发现钓鱼欺诈、拒绝服务和权限提升等Android的常见漏洞,而且可以对App的稳定性进行分析验证。建议通过模糊测试的方法和工具,对App的Android版进行漏洞挖掘。 3. 随着智能手机、可穿戴设备、活动追踪器、无线网络、智能汽车、智能家居等终端设备和网络设备的迅速发展和普及利用,针对物联网设备的网络攻击事件比例呈上升趋势,攻击者利用物联网设备漏洞可入侵设备,获取设备控制权,通过控制大量物联网设备,黑客可以发起分布式拒绝服务网络攻击(DDoS)。 建议利用模糊测试,对物联网的网络协议和设备进行漏洞挖掘。 4. 随着业务发展和技术升级需要,会引入一些开源软件或者免费软件,而据Google的报告,开源软件或者免费软件的安全漏洞还是非常多,建议通过模糊测试的方法和工具,在引入开源软件或者免费软件的过程,做安全风险评估。 5. 针对业务特点和系统特征,构造模糊测试数据知识库,提升模糊测试数据的针对性,通过人工智能优化模糊测试数据生成和自动化执行过程,构建模糊测试平台,提供安全测试的服务给分行或者行外客户使用。 #### 前导知识补充 - ASAN https://github.com/google/sanitizers/wiki/AddressSanitizer - 查看系统版本 cat /etc/issue - Clang是一个高度模块化开发的轻量级编译器,编译速度快、占用内存小、有着友好的出错提示。在使用AFL编译时,实践表明afl-clang-fast相较于afl-gcc会更高效。 - 可以认为LLVM是一个完整的编译器架构,也可以认为它是一个用于开发编译器、解释器相关的库。且在使用LLVM架构的时候,Clang其实大致上对应到编译器的前端,主要处理一些和具体机器无关的针对语言的分析操作;编译器的优化器部分和后端部分就是LLVM后端。LLVM Mode模式编译程序也可以获得更快的Fuzzing速度 - 在C/CPP项目工程中, src文件夹:存放.cpp文件 include文件夹:存放.h头文件 example文件夹:存放例子代码 lib文件夹:存放编译时产生的链接库 - 将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中。 `docker cp 96f7f14e99ab:/www /tmp/` - afl-clang-lto相比于afl-clang-fast是更好的选择,因为它是一种无碰撞检测,而且比afl-clang-fast 快。编译项目插桩时,可以切换使用afl-gcc afl-clang-fast afl-clang-lto等编译器以获取更好的性能表现。 - 如果不确定何时使用哪种编译器,可参考如下内容: +--------------------------------+ | clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++) +--------------------------------+ see instrumentation/README.lto.md | | if not, or if the target fails with LTO afl-clang-lto/++ | v +---------------------------------+ | clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see instrumentation/README.llvm.md | | if not, or if the target fails with LLVM afl-clang-fast/++ | v +--------------------------------+ | gcc 5+ is available | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast) +--------------------------------+ see instrumentation/README.gcc_plugin.md and instrumentation/README.instrument_list.md | | if not, or if you do not have a gcc with plugin support | v use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang) - 编译源码时添加'-fsanitize=address' 想要在错误消息中添加更好的堆栈跟踪,启用 -fno-omit-frame-pointer,此外还可以使用-O1进行一级优化的编译。具体做法为: (1) 对于单个程序编译,直接在编译时添加在命令行 如:`gcc -g -fsanitize=address -O1 -fno-omit-frame-pointer ./test.c` (2) 对于含有Makefile的项目,在'CFLAGS'后面添加 如:`CFLAGS = -g -fsanitize=address ......` (3) 对于含有configure的项目 ./configure CFLAGS='-g -fsanitize=address' 即可 #### 来认识下AFL吧! 先贴一下如何运行一个简单的AFL入门实例,后面会有详细的分步讲解。 配置环境: `CentOS 7 Linux.` docker pull aflplusplus/aflplusplus docker run -ti -v /root/fuzz:/AFLplusplus/my_test --rm aflplusplus/aflplusplus cd my_test mkdir fuzz_in mkdir fuzz_out vi fuzz_in/testcase vi a.c afl-gcc -g -o test a.c afl-fuzz -i fuzz_in -o fuzz_out ./test ![image.png][1] 简单的几步操作,我们就可以初步运行一个AFL工具实例来Fuzzing漏洞啦,稍后我们详细讲解下。 ------------ 下来我们逐条命令讲解 `docker pull aflplusplus/aflplusplus` 意为: 开始拉取Docker镜像“aflplusplus/aflplusplus” 由于每个测试者的系统发行版,设备型号以及使用环境各有不同,为了尽可能减少从源码编译安装AFL过程中存在的问题,我们选用AFL官方提供的镜像。 即开即用,绝大多数运行参数已经配置完毕。 `docker run --name afl -ti -v /root/fuzz:/AFLplusplus/my_test` 意为: 创建以AFL为镜像的docker运行实例容器。 -it 是 -i -t 的结合 -i: 以交互模式运行容器,通常与 -t同时使用; -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用; 所以-it就是以交互模式运行aflplusplus/aflplusplus容器 --volume , -v: 绑定一个卷到容器中,整个命令 -v 本地目录:容器目录,其实就是将本地文件和容器的虚拟机共享,具体到上面的命令就是将我本地目录/root/fuzz映射到容器内的AFLplusplus/my_test :/ 这个就是映射的意思 (新手如果还是不太理解目录映射的话,自己动手实际操作下就明白了。) --name afl是给我的容器取个名字,“name”可以自定义。 cd my_test mkdir fuzz_in mkdir fuzz_out 这几句连起来讲一下, 我们进入docker容器后,首先切换目录到 my_test 该目录默认为 待测项目/程序的存放位置以及实际开展fuzz的工作目录 当然,你也可以自定义目录。 我们在该目录中使用mkdir命令分别创建fuzz_in与fuzz_out两个目录, fuzz_in 用于存放fuzz程序所需的输入样例 fuzz_out 用于存放fuzz程序所输出的报告结果 `echo "helloworld" > fuzz_in/testcase` 输入字符串“helloworld”到testcase文件中 `vi a.c` 编写漏洞程序并保存 ![](https://hack.best/usr/uploads/2022/01/4239339995.png) `afl-gcc -g -o test a.c` 使用afl-gcc编译插桩 afl-gcc是AFL套件对于gcc编译程序的封装,使用参数一致。 -o 指输出文件重命名 a.c即为目标源程序 ![](https://hack.best/usr/uploads/2022/01/730174474.png) `afl-fuzz -i fuzz_in -o fuzz_out ./test` 开始测试! `afl-fuzz -i /path/to/input -o /path/to/output /path/to/program/ @@` 其中,path/to/inputsample是指作为输入样本的文件夹的位置; 同理, /path/to/output是指存放fuzz出来的结果的地址; /path/to/program是指被fuzz的二进制程序的地址; @@是指当我们需要从文件中获取输入时,可以使用其来代替被测试程序命令行中输入文件名的位置; ![](https://hack.best/usr/uploads/2022/01/292207180.png) ![](https://hack.best/usr/uploads/2022/01/3576055131.png) #### Fuzzing何时停止? 原作者提到: > This is a difficult question. Basically if no new path is found for a long time (e.g. for a day or a week) then you can expect that your fuzzing won't be fruitful anymore. However often this just means that you should switch out secondaries for others, e.g. custom mutator modules, sync to very different fuzzers, etc. Keep the queue/ directory (for future fuzzings of the same or similar targets) and use them to seed other good fuzzers like libfuzzer with the -entropic switch or honggfuzz. 一般来说,AFL在fuzzing中不会自动停止,需要测试人员主动操作。 通常符合下面几种情况时就可以停掉了。 1. 状态窗口中 "cycles done" 字段颜色变为绿色该字段的颜色可以作为何时停止测试的参考,随着周期数不断增大,其颜色也会由洋红色,逐步变为黄色、蓝色、绿色。当其变为绿色时,继续Fuzzing下去也很难有新的发现了,这时便可以通过Ctrl-C停止afl-fuzz。 2. 距上一次发现新路径(或者崩溃)已经过去很长时间了,至于具体多少时间还是需要自己把握,看测试人员的耐心了。 3. 目标程序的代码几乎被测试用例完全覆盖,这种情况可能很少见,但是对于某些小型程序应该还是可能的。 4. 待续 #### AFL 状态讲解 AFL状态窗口 - Process timing: Fuzzer运行时长、以及距离最近发现的路径、崩溃和挂起经过了多长时间。 - Overall results: Fuzzer当前状态的概述。 - Cycle progress: 我们输入队列的距离。 - Map coverage: 目标二进制文件中的插桩代码所观察到覆盖范围的细节。 - Stage progress: Fuzzer现在正在执行的文件变异策略、执行次数和执行速度。 - Findings in depth: 有关我们找到的执行路径,异常和挂起数量的信息。 - Fuzzing strategy yields: 关于突变策略产生的最新行为和结果的详细信息。 - Path geometry: 有关Fuzzer找到的执行路径的信息。 - CPU load: CPU利用率 - queue:存放所有具有独特执行路径的测试用例。 - crashes:导致目标接收致命signal而崩溃的独特测试用例。 - crashes/README.txt:保存了目标执行这些crash文件的命令行参数。 - hangs:导致目标超时的独特测试用例。 - fuzzer_stats:afl-fuzz的运行状态。 - plot_data:用于afl-plot绘图。 #### 可能遇到的问题 问题一:AFL生成的out文件不可访问(提示权限不够) 解决方法:sudo chmod 777 out -R(设置此目录下所有文件可读可写) 问题二:crash文件为二进制文件,没有直接打开的可用软件 解决方法:利用vim/cat可查看 ------------ 2022.01.30更新 问题三: 使用ASAN分析Crash后无法获取具体函数信息,即不能排查错误点 / 无法使用GDB调试Binary文件。 解决方法: **一定要确保编译binary时的参数配置/Makefile中不能出现 `-s `参数以及在编译的时候一定要加上-g参数** 不加 -s 的分析结果: ![](https://hack.best/usr/uploads/2022/01/3950262534.png) 修改后: ![](https://hack.best/usr/uploads/2022/01/37368356.png) GDB: ![](https://hack.best/usr/uploads/2022/01/2843555805.png) ![](https://hack.best/usr/uploads/2022/01/1581741830.png) 问题四: 除了ASAN之外还有可用的内存泄露检测工具吗? 可以使用Valgrind. `apt-get install valgrind` `valgrind --tool=memcheck --leak-check=full ./test --leak-check=full` 所有内存泄露检查 ### 一些Fuzzing实例 #### Vim ![](https://hack.best/usr/uploads/2022/02/3006582531.png) ``` #!/usr/bin/env bash echo -e "[+] Cloning VIM" git clone https://github.com/vim/vim.git ; cd vim echo "[+] Compiling VIM with AFLPlusPlus" CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --with-features=huge --enable-gui=none export AFL_INST_RATIO=30 ; export AFL_HARDEN=1 ; make -j4 ; cd src echo "[+] Feeding Seeds" mkdir corpus ; mkdir output ; echo "a*b\+\|[0-9]\|\d{1,9}" > corpus/1 ; echo "^\d{1,10}$" > corpus/2 echo "[+] Adding Dictionary" wget https://raw.githubusercontent.com/vanhauser-thc/AFLplusplus/master/dictionaries/regexp.dict echo "[+] Fuzzing VIM Regex Engine" afl-fuzz -m none -x regexp.dict -i corpus -o output ./vim -u NONE -X -Z -e -s -S @@ -c ':qa!' ``` ### Old talk - 在进行Fuzz时,信息收集同等重要,如果是复现,需要知晓Fuzz目标的CVE信息。如果是漏洞挖掘过程,则难度会更上一个等级。 - 熟悉程序的构建过程、程序的功能是必不可少的步骤,如果完全不知道程序是干嘛的,那漏洞挖掘也就无从下手。 - 在复现漏洞时,应该考虑怎么去证明这个漏洞,以及程序是如何崩溃的,可以在崩溃时的上层函数打上断点单步跟踪,观察参数和函数调用过程 ------------ **欢迎加TG群一起交流Fuzzing.** [FuzzingBar](https://t.me/+JxpSvOK_gDJhNTc1 "FuzzingBar") **鸣谢:** 个人在学习AFL中遇到了一些问题,多方查阅资料及请教,特此感谢。 - @NISL_SecurityGroup Members. - @Exec 深蓝 部分资料引用于相关文章。 - https://github.com/google/sanitizers/wiki/AddressSanitizer - [https://bbs.pediy.com/thread-261253.htm#msg_header_h3_3](https://bbs.pediy.com/thread-261253.htm#msg_header_h3_3) - [https://paper.seebug.org/841/](https://paper.seebug.org/841/) - [https://www.pianshen.com/article/8319853753/](https://www.pianshen.com/article/8319853753/)https://github.com/aflnet/aflnet - https://blog.flanker017.me/ - https://www.pianshen.com/article/8319853753/ - http://galaxylab.pingan.com.cn/afl%E4%BD%BF%E7%94%A8101/ - https://www.its500.com/article?url=studyskill/p/9015449.html https://www.its500.com/article?url=arsense/p/7068995.html - http://cn-sec.com/archives/146342.html https://github.com/lcatro/Source-and-Fuzzing - https://josephg.com/blog/bug-hunting-with-american-fuzzy-lop/ [1]: https://hack.best/usr/uploads/2022/01/1906516729.png
my3in
orz