AFL(二)afl-qemu无源码fuzz
使用brew/apt方式安装的afl没有afl-qemu-trace(不支持使用QEMU模式),所以我们需要下载afl的源码自己编译。
0x1 安装配置
编译完成后,需要配置qemu环境。不过,afl提供了一个脚本,在
qemu-mode
文件夹下的build_qemu_support.sh
。运行这个脚本来配置qemu环境,但qemu-mode只支持linux,macOS可以在docker上使用,docker使用参考macOS上使用kali-linux for docker:$ ./build_qemu_support.sh
=================================================
AFL binary-only instrumentation QEMU build script
=================================================
[*] Performing basic sanity checks...
[-] Error: QEMU instrumentation is supported only on Linux.
编译成功信息如下:
[+] Build process successful!
[*] Copying binary...
-rwxr-xr-x 1 root root 10956864 Dec 13 12:26 ../afl-qemu-trace
[+] Successfully created '../afl-qemu-trace'.
[*] Testing the build...
[+] Instrumentation tests passed.
[+] All set, you can now use the -Q mode in afl-fuzz!
遇到的坑
- 运行后会提示libtool等资源库没有安装,使用
sudo apt install
安装即可:$ ./build_qemu_support.sh ================================================= AFL binary-only instrumentation QEMU build script ================================================= [*] Performing basic sanity checks... [-] Error: 'libtool' not found, please install first. $ apt-get install libtool-bin
- 安装一些软件包时,有时会出现找不到glib2的错误:
查看$ apt install glib2 Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package glib2
build_qemu_support.sh
相关代码,需要在/usr/include/glib-2.0/
或者/usr/local/include/glib-2.0/
有相关库:
可通过安装以下工具来解决:if [ ! -d "/usr/include/glib-2.0/" -a ! -d "/usr/local/include/glib-2.0/" ]; then echo "[-] Error: devel version of 'glib2' not found, please install first." exit 1
sudo apt-get install libgtk2.0-dev
- qemu编译错误:
afl默认qemu版本太老,官方已经patch:util/memfd.c:40:12: error: static declaration of 'memfd_create' follows non-static declaration static int memfd_create(const char *name, unsigned int flags) ^~~~~~~~~~~~ In file included from /usr/include/x86_64-linux-gnu/bits/mman-linux.h:115, from /usr/include/x86_64-linux-gnu/bits/mman.h:45, from /usr/include/x86_64-linux-gnu/sys/mman.h:41, from /root/afl-2.52b/qemu_mode/qemu-2.10.0/include/sysemu/os-posix.h:29, from /root/afl-2.52b/qemu_mode/qemu-2.10.0/include/qemu/osdep.h:104, from util/memfd.c:28:
./configure:
./util/memfd.c:@@ -3923,7 +3923,7 @@ fi # check if memfd is supported memfd=no cat > $TMPC << EOF -#include <sys/memfd.h> +#include <sys/mman.h>
修改完成后使用如下指令重打包,再修改@@ -31,9 +31,7 @@ #include "qemu/memfd.h" -#ifdef CONFIG_MEMFD -#include <sys/memfd.h> -#elif defined CONFIG_LINUX +#if defined CONFIG_LINUX && !defined CONFIG_MEMFD
build_qemu_support.sh
里的QEMU_SHA384
重新编译即可,SHA384
值可以使用sha384sum
获取:$ tar -Jcf qemu-2.10.0.tar.xz qemu-2.10.0/ $ sha384sum qemu-2.10.0.tar.xz
更换qemu版本
如果想使用更新版本qemu,可以直接将
build_qemu_support.sh
设置的版本换成官方的较新版本,但更换版本后问题较多:#VERSION="2.10.0"
VERSION="2.12.1"
#QEMU_SHA384="68216c935487bc8c0596ac309e1e3ee75c2c4ce898aab796faa321db5740609ced365fedda025678d0"
QEMU_SHA384="92957551a3a21b1ed48dc70d9dd91905859a5565ec98492ed709a3b64daf7c5a0265d670030ee7e6d16da96436795435"
- patch错误:
patch针对的是上层路径的文件更新,可以直接注释掉patching file linux-user/elfload.c Hunk #2 succeeded at 2233 (offset 146 lines). Hunk #3 succeeded at 2268 (offset 146 lines). patching file accel/tcg/cpu-exec.c Hunk #1 succeeded at 37 (offset 1 line). Hunk #2 succeeded at 147 with fuzz 2 (offset 1 line). Hunk #3 FAILED at 369. 1 out of 3 hunks FAILED -- saving rejects to file accel/tcg/cpu-exec.c.rej
#patch -p1 <../patches/cpu-exec.diff || exit 1
- 缺少pixman,安装即可
apt-get install libpixman*
- LINK错误:
上层patch中对源码文件做了修改,导致部分外部变量没有导入,注释掉相关patch即可:LINK x86_64-linux-user/qemu-x86_64 linux-user/syscall.o: In function `do_syscall': /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/syscall.c:11983: undefined reference to `afl_forksrv_pid' linux-user/elfload.o: In function `load_elf_image': /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2236: undefined reference to `afl_entry_point' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2236: undefined reference to `afl_entry_point' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2271: undefined reference to `afl_start_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2271: undefined reference to `afl_start_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2275: undefined reference to `afl_end_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2275: undefined reference to `afl_end_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2236: undefined reference to `afl_entry_point' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2236: undefined reference to `afl_entry_point' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2271: undefined reference to `afl_start_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2271: undefined reference to `afl_start_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2275: undefined reference to `afl_end_code' /root/afl-2.52b/qemu_mode/qemu-2.12.0/linux-user/elfload.c:2275: undefined reference to `afl_end_code' collect2: error: ld returned 1 exit status Makefile:193: recipe for target 'qemu-x86_64' failed make[1]: *** [qemu-x86_64] Error 1 Makefile:478: recipe for target 'subdir-x86_64-linux-user' failed make: *** [subdir-x86_64-linux-user] Error 2
# patch -p1 <../patches/elfload.diff || exit 1 # patch -p1 <../patches/syscall.diff || exit 1
afl-qemu-trace
测试失败
应该是用64位[+] Successfully created '../afl-qemu-trace'. [*] Testing the build... [-] Error: afl-qemu-trace instrumentation doesn't seem to work!
afl-qemu-trace
工具测试32位程序引起的,忽略即可,或者通过如下指令指定32位架构:
结果如下,实际也是忽略了测试:$ CPU_TARGET=i386 ./build_qemu_support.sh
[+] Successfully created '../afl-qemu-trace'. [!] Note: can't test instrumentation when CPU_TARGET set. [+] All set, you can now (hopefully) use the -Q mode in afl-fuzz!
0x2 使用afl-qemu fuzz
0x21 同cpu架构程序
以系统中
wget
指令为例,使用如下指令执行fuzz,-Q
参数表示使用qemu模式;-m
参数设置使用内存大小,不设置则默认200MB:$ afl-fuzz -i fuzz_in -o fuzz_out -m 200 -Q wget @@
0x22 不同cpu架构程序
0x221 获取目标文件
Android adbd程序为例,获取adbd文件:
$ file /system/bin/adbd
/system/bin/adbd: ELF executable, 64-bit LSB arm64, static, for Android 28, BuildID=2ef781f7497eaad0b8ba145996afd9a1, not stripped
$ adb pull /system/bin/adbd ./
0x222 编译目标架构qemu模式
如果fuzz的程序与qemu架构不同,则可能出现如下错误,需要用之前方式指定正确架构进行编译qemu模式:
$ afl-fuzz -i fuzz_in -o fuzz_out/ -Q ./adbd @@
...
[-] Hmm, looks like the target binary terminated before we could complete a
handshake with the injected code. There are two probable explanations:
- The current memory limit (200 MB) is too restrictive, causing an OOM
fault in the dynamic linker. This can be fixed with the -m option. A
simple way to confirm the diagnosis may be:
( ulimit -Sv $[199 << 10]; /path/to/fuzzed_app )
Tip: you can use http://jwilk.net/software/recidivm to quickly
estimate the required amount of virtual memory for the binary.
- Less likely, there is a horrible bug in the fuzzer. If other options
fail, poke <[email protected]> for troubleshooting tips.
[-] PROGRAM ABORT : Fork server handshake failed
Location : init_forkserver(), afl-fuzz.c:2253
编译arm64版本工具,qemu支持的架构类型见
./qemu-2.10.0/linux-user/host/
目录,其中arm为32位arm,aarch64为64位arm:$ ls ./qemu-2.10.0/linux-user/host/
aarch64 arm i386 ia64 mips ppc ppc64 s390 s390x sparc sparc64 x32 x86_64
以64位arm为例,编译指令如下:
$ CPU_TARGET=aarch64 ./build_qemu_support.sh
编译aarch64版本后,继续执行fuzz:
$ ../afl-2.52b/afl-fuzz -i fuzz_in/ -o fuzz_out/ -Q ./adbd
依然错误:
[-] PROGRAM ABORT : Test case 'id:000000,orig:testcase' results in a crash
Location : perform_dry_run(), afl-fuzz.c:2852
0x223 qemu user mode检查
由于可执行文件的架构不一样,所以需要按照QEMU user mode仿真做一下检查,运行成功后再进行fuzz,详情参考:IoT(七)通过qemu调试IoT固件和程序里的用户模式调试程序。
在该文中,adbd程序由于缺少外部资源依然执行失败(如需对有外部资源依赖的程序进行fuzz,可在该平台编译对应版本的fuzz工具),故重新选取能够执行成功的静态编译工具,如Android上的三方工具busybox:
$ file busybox
busybox: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, stripped
$ qemu-aarch64 busybox
BusyBox v1.25.0-NetHunter (2016-03-19 19:36:31 EDT) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.
Usage: busybox [function [arguments]...]
or: busybox --list[-full]
or: busybox --install [-s] [DIR]
or: function [arguments]...
....
此处可成功对busybox进行fuzz:
../afl-2.52b/afl-fuzz -i fuzz_in/ -o fuzz_out/ -Q ./busybox @@
大佬您好!我最近想尝试使用afl对路由器固件中的一些程序进行fuzz。我已经参照您的这个博客编译好了mipsel架构的工具,也参照https://github.com/shellphish/afl-other-arch配好了环境变量。但是很奇怪的是,我用afl-showmap -Q -m none -o out ./bin/busybox是可以运行的,但是在afl-fuzz -Q -m none -i in/ -o out/ ./busybox就会报Fork server handshake failed,在指定了AFL_NO_FORK=1之后,虽然不报Fork server handshake failed的错了,但是就会报no instrumentation detected的错。正常来说,afl的qemu模式不就是针对闭源二进制程序的吗?就算没有instrumentation应该也可以运行啊。您说应该去测试静态链接的工具,可是我这个路由器固件里就算busybox都是动态链接的,我在想这会是个原因吗?您文中提到“如需对有外部资源依赖的程序进行fuzz,可在该平台编译对应版本的fuzz工具”我并不是太明白您的意思,能有个具体的例子吗?总体来说,您对于如何使用afl对于mipsel架构,动态链接的固件二进制程序进行模糊测试有什么高见吗?若大佬能略微指点一二,感激不尽!
回复删除mipsel架构没试过,不过AFL编译链接可执行文件和库文件时,可以使用static link静态链接libxxx.a文件,对于动态链接库,需要将动态链接库(如当前目录)加到环境变量中:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
回复删除感谢大佬的回复!我这个问题已经解决了。说来惭愧,这是个很蠢的问题,让大佬见笑了……我在怎么尝试都不行的时候,感觉大家的环境都是Ubuntu。而我之前用的环境一直是kali,而且我看所有关于AFL的文档都没有说环境一定要是Ubuntu。我换了Ubuntu之后,啥都好使了orz另外我还有个小小的疑惑。我之前也看到有人提出想要加动态链接库的话,需要export LD_LIBRARY_PATH。但是https://github.com/shellphish/afl-other-arch中说要加动态链接库的话,需要export QEMU_LD_PREFIX。在我这里,export QEMU_LD_PREFIX好使,而export LD_LIBRARY_PATH不好使。我没有研究过AFL的源码,个人猜测https://github.com/shellphish/afl-other-arch不仅仅简化了构建其他CPU架构下的qemu mode的过程,可能还改了其他的东西。最后再次感谢大佬的回复!
回复删除大佬,求问一下。我在用qemu mode测服务器二进制文件的时候出现了Fork server handshake failed那个问题。我查到二进制文件的cpu架构是i386,然后用CPU_TARGET=i386 ./build_qemu_support.sh编译了。但是依旧会出那个错误。想问问是什么原因QAQ
回复删除同问上楼
回复删除如果出现Fork server handshake failed错误,可以参考这篇博客的后半部分:https://jackfromeast.site/2021-01/Vivotek%E6%91%84%E5%83%8F%E5%A4%B4%E5%9B%BA%E4%BB%B6%E6%BC%8F%E6%B4%9E%E6%8C%96%E6%8E%98-AFL-FUZZ%E5%AE%9E%E6%88%98.html
回复删除