【必看】2025简单部署 AFL++ 模糊测试工具,亲测少走一年弯路!

阅读量43036

发布时间 : 2025-03-28 16:57:04

1. 环境安装

 

1.1 源代码编译

源码地址:git clone GitHub – AFLplusplus/AFLplusplus: The fuzzer afl++ is afl with community patches, qemu 5.1 upgrade, collision-free coverage, enhanced laf-intel & redqueen, AFLfast++ power schedules, MOpt mutators, unicorn_mode, and a lot more!

1.2 官方镜像: aflplusplus/aflplusplus

1.3 包管理器安装: apt install afl++

解析:源代码编译在线下载大文件数据包,不够稳定;包管理其安装 afl++ 只是一个基础包,无法进行模糊测试,仍需安装其它依赖包;

推荐官方镜像安装:实时更新,环境完整,但是镜像较大,5.31GB大小。

 

2. 不可执行的二进制文件

 

如果目标二进制文件无法运行(不是由于架构不匹配、依赖缺失或环境配置问题,而是因为其本身不是一个可执行文件,或者其逻辑无法运行)

如果目标二进制文件是一个 .o 文件,可以通过编写一个测试 harness 来调用库中的函数。

方法:

a.编写一个简单的程序(harness),调用库中的目标函数。

b.使用 AFL++ 对 harness 进行模糊测试。

 

2.1 测试驱动调用函数

目标是一个不可运行的二进制文件(例如一个函数),需要编写一个测试驱动(harness)来调用目标函数。

 

2.1.1 准备目标二进制文件

二进制文件 libtarget.o ,其中包含一个函数 vulnerable_function,其签名为:

 

这个二进制文件可能是通过以下方式编译的:

 

其中 target.c 的内容如下:

 

2.1.2 编写测试驱动

由于二进制文件不可直接运行,编写一个测试驱动(harness)来调用目标函数。创建一个文件 harness.c:

 

 

2.1.3 编译测试驱动和目标二进制文件

将测试驱动和目标二进制文件链接在一起,并使用 AFL++ 的编译器进行插桩:

 

2.1.4 准备测试用例

创建一个目录来存放初始的测试用例:

 

2.1.5 开始模糊测试

使用 AFL++ 进行模糊测试:

 

 

注意事项

1.函数签名:确保在测试驱动中正确声明目标函数的签名。

2.输入处理:测试驱动需要正确处理输入文件,并将其传递给目标函数。

3.插桩:确保使用 AFL++ 的编译器进行插桩,以便 AFL++ 能够收集覆盖率信息。

 

2.2 模糊测试未知函数

如果无法确定参数类型,可以编写一个通用的测试驱动,尝试以不同的方式调用目标函数。

通用的模糊测试

1.void vulnerable_function(char *input):

参数是 char *,即一个指向字符类型的指针,通常用于处理字符串。

这个函数通常用于处理 C 风格的字符串(以 null 结尾的字符数组)。

例如,你可以将 input 看作一个字符串,可以通过 input 来访问和操作字符数据。

2.void vulnerable_function(void *arg):

参数是 void *,即一个通用的指针类型,可以指向任何类型的数据。

这种声明使得函数能够接受任意类型的数据,并且可以通过类型转换来处理它。

它提供了更大的灵活性,但也更容易导致潜在的错误,因为在使用时需要确保正确地将 void * 转换为实际的数据类型。

总结:

char *input 适用于专门处理字符串或字符数组。

void *arg 提供了更大的通用性,可以处理任何类型的数据,但需要额外的小心以确保类型转换正确。

 

 

2.3 dlopen 和 dlsym

2.3.1 dlopen 和 dlsym

dlopen 和 dlsym:用于动态加载共享库并调用已知函数,但无法直接读取函数名和参数类型。

dlopen 用于打开一个共享库文件,并返回一个句柄,供后续使用。

dlsym 用于从共享库中查找符号(函数或变量)的地址。

2.3.2 动态加载共享库并调用其中的函数

共享库代码

编译共享库

 

 

主代码程序

 

 

编译

 

 

运行

 

 

2.4 函数签名

在 C 语言中,共享库(.so 文件)本身不存储函数的签名信息

要读取一个 .so 文件中的函数签名(即函数名、参数类型、返回类型等),dlopen 和 dlsym 不能直接提供这样的信息,因为它们只会加载符号并返回其地址。要解析函数签名,你需要用一些工具来分析 .so 文件的符号表,或者借助一些更高级的调试和反汇编工具。

 

nm

可以列出共享库中的符号表(包括函数名、地址、类型等),但无法直接显示完整的函数签名(参数类型和返回值)

 

 

objdump

objdump 可以反汇编代码,通过分析函数调用栈和寄存器传递参数的方式,间接推测函数签名。

readelf 查看 ELF 文件头和符号

nm或objdump只能得到函数名和可能的参数类型,但不够准确,特别是对于复杂类型或用户自定义类型。

提供头文件或文档

.so 文件(共享库)中直接提取头文件是不可行的

 

2.5 通用驱动程序

要将目标函数通过命令行传入,而不是在代码中硬编码 unknown_function,通过命令行参数传递目标函数的名称,并使用函数指针来调用它。

 

 

 

 

编译

确保目标函数在编译时被正确导出(例如,使用 -rdynamic 或 -export-dynamic 编译选项)

 

 

 

 

中科固源专注于通讯协议安全与模糊测试,提供Wisdom系列工具和Swift系列工具,帮助企业构建全面的网络安全防护体系。了解更多产品与解决方案。加入我们,开启你的高效代码创新之旅!

 

①扫描二维码或添加微信,获取1V1线上云指导。

②解锁免费高效的开源级开发工具,还有更多专属权益等你来拿。

③关注我们,在评论区留言“我要学习资料”,即可免费获得独家学习资料包,包括详细使用教程、应用案例分析及相关技术文档。

本文由中科固源原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/305949

安全KER - 有思想的安全新媒体

分享到:微信
+11赞
收藏
中科固源
分享到:微信

发表评论

Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全KER All Rights Reserved 京ICP备08010314号-66