fuzz测试libmodbus | AFL篇

下载编译libmodbus

首先在github上下载libmodbus库的源码

git clone https://github.com/stephane/libmodbus/

下载好之后进入到文件夹中,在编译过程中选择使用afl-gcc而不是默认的gcc

cd libmodbus/
./autogen.sh
CC=afl-gcc CXX=afl-g++ 
./configure --enable-static
make -j8

这里在我第一次运行./autogen.sh时,报错提示autoreconf not found
在这里插入图片描述
查了一下README里面提示说需要autoconf和libtool,新装的虚拟机上好像没安装,装上之后问题就解决了,正常情况下运行autogen.sh后会有如下提示,最后会告诉你可以运行./configure了
在这里插入图片描述
另外注意在./configure之前一定要更改环境变量的CC和CXX为afl的编译器,以便对libmodbus进行插桩。
如果过程顺利,最终会看到如下图所示的界面,很多afl插桩提示
在这里插入图片描述

安装Preeny库

为什么需要Preeny

Modbus协议依托socket实现进程间的通信,而AFL本身并未提供对socket通信的支持。使用AFL对其进行fuzzing时,需要将其输入输出重定向stdio中。纵然可以修改部分代码使其socket通信转移到stdio,但这一过程可能会对fuzz的结果造成影响,同时工作量可能也较为繁杂。若是直接修改系统的socket.h,可能会对其他的程序造成难以估量的影响。
而Preeny提供了一系列有趣的模块,其中就包括了一个可以将socket通信重定向至console的desock模块。这个模块,原本的socket函数实现
在这里插入图片描述

安装Preeny的前置条件

在Preeny的README中,明确提示了preeny需要使用libini_config来实现相关功能,在安装preeny之前需要先装好,否则在make时会报错。
在这里插入图片描述
此外,在编译过程中还需要用到seccomp/h头文件,需要安装libseccomp

sudo apt-get install libseccomp-dev -y

编译安装

在满足了上述前置条件后,直接到preeny目录下make即可自动完成编译,编译过程中可能会有些warning,不影响正常功能。
安装成功后,可以在preeny目录下的src/中找到desock.so,可以通过一个简单的测试小程序确认desock模块是否正确工作

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
        int sock;
        char send_buf[] = "hello, world! \n";
        char recv_buf[100] = {'\0'};
        sock = socket(AF_INET, SOCK_STREAM, 0);
        send(sock, send_buf, strlen(send_buf), 0);
        recv(sock, recv_buf, 100, 0);
        printf("The following msg is recvd:\n %s \n", recv_buf);
        return 0;
}

在这里插入图片描述
可以看到,send函数成功将消息发往了stdout,而recv函数也成功从stdin中接收了消息,说明本部分工作已经完成

创建测试程序与样例

编译测试程序

在libmodbus目录下有一个tests文件夹,包含几个官方提供的测试样例,可以通过afl-gcc对其进行插桩编译,作为被测程序。此处值得注意的是,在编译时要注意手动指定modbus库和头文件
如:

afl-gcc bandwidth-server-many-up.c -o server -I libmodbus/src/ libmodbus/src/.libs/libmodbus.a

-I后面两个参数分别指定了modbus.hlibmodbus.a的路径,两者缺一不可

生成测试用例

在AFL的文档中,建议为fuzzing测试提供一些“特别”(interesting)的测试用例作为种子。显然,如果直接用一串随机字母数字组合作为modbus测试程序的输入并不够interesting。好在libmodbus提供的测试用例中,random-test一对就可以为我们提供不错的测试数据,这是tests/README.md中对于他们的描述
在这里插入图片描述
在本地运行这一对程序,然后通过tcp将数据包保存至本地,然后再随机挑选几个数据包出来作为输入样例。

开始测试

使用afl-fuzz命令即可开始fuzzing测试,需要通过-i参数给出存放测试用例的目录 -o参数给出用于输出测试结果的目录,如果目录不为空会报错 最后直接给出被测程序的路径即可。
注意为了将socket输入输出重定向到stdio,我们需要在运行的同时指定LD_PRELOAD=desock.so。完成操作即如下所示:

LD_PRELOAD=./desock.so afl-fuzz -i inputs/ -o outputs/ ./server

关于测试用例

测试用例一次不要给太多,按照afl官方所给的建议(/usr/local/doc/afl/perf-tips.txt),第一条就指出要让测试用例尽量小。第一次没注意到这个问题,把抓到的近一千个包一口气全放到了测试用例目录中,结果如下图所示:
在这里插入图片描述
除了第一个case之外,后面的都提示“may be useless"
在这里插入图片描述

测试过程

正确配置各项参数后,AFL的运行界面如下:
在这里插入图片描述

测试结果

过程图表

使用AFL自带的afl-plot可以将测试过程中的一些数据变化绘制成基于html的图表,使用方法为“

afl-plot /path/to/fuzz/outputs /path/to/plot

正确执行后会有简单的提示,然后就可以在指定plot输出的文件夹中找到index.html
在这里插入图片描述
图表结果如下:
在这里插入图片描述
在这里插入图片描述

从中可以看到测试过程中的的执行路径、运行速度等数据。但是对于覆盖率,在这个分析图表中并没有体现。

覆盖率分析

afl-cov是一款针对afl-fuzzer的覆盖率分析工具,可以非常方便的从github上下载

https://github.com/mrash/afl-cov

下载得到的afl-cov本身不需要编译安装,直接就可以使用,但是在使用前需要确保本地已经安装了gcov和lcov
在这里插入图片描述
afl-cov可以解析已经执行完毕的afl-fuzz输出结果,也可以与afl-fuzz同时运行,实时监控每次测试的覆盖率,这里我采用的是实时的方法。

编译副本

根据afl-cov的README, 使用afl-cov前需要重新对目标程序编译一个副本,并且在编译过程中加入gcov。另外注意重新编译的和被测程序是同样的源码,由于我这里是对modbus程序进行测试的,所以仍然需要像之前afl-gcc插桩编译时一样的手动指定modbus头文件和库文件的位置。
综上,编译命令为:

gcc server.c -o server_copy -I libmodbus/src/ libmodbus/src/.libs/libmodbus.a -fprofile-arcs -ftest-coverage 

编译成功后,除了会出现server_copy.o之外,还会有一个同名的.gcno文件。

启动afl-cov

接下来,根据文档启动afl-cov,执行如下命令

./afl-cov -d ../fuzz_713 --live -c ./ -e "cat AFL_FILE | ./server_copy"

其中,-d参数指明了afl-fuzz输出结果的目录,–live表示afl-cov与fuzzer同时运行, -c参数是存放了目标文件副本的目录,即包含了.gcno文件的目录, -e表示执行后面给出的命令行代码。在运行过程中,afl-cov会自动将AFL_FILE替换为fuzzer输出结果的文件名(也就是id:0000开头的文件)。

启动afl-cov后,会提示[-] Sleep for 60 seconds for AFL fuzzing directory to be created... 这时就可以运行afl-fuzz并保持输出目录与刚刚指定的目录一致即可。

实时分析

在afl-fuzz开始运行并生成测试结果后,afl-cov将自动从目录中读取,并在命令行中展示实时的代码覆盖率
在这里插入图片描述
可能是由于我的被测程序运行较慢的原因,cov偶尔会提示没有新的测试用例,等待60秒后继续。

遇到错误

在测试某些程序时,可能会发现afl-cov无法正确启动覆盖率分析,而是疯狂刷出错误信息,像这样:
在这里插入图片描述
在afl-cov的github页面中,有一个issue指出了这个问题

在这里插入图片描述
如何对gcc降级,参考这篇文章。降级后重新编译,然后运行afl-cov,发现错误仍然存在……目前这个错误仍然没有被解决,在StackOverflow上面也有人遇到类似的问题,一样是未解决状态……

结束测试

在afl-fuzz测试终止后,afl-cov会随之自动停止,并给出一系列分析结果
在这里插入图片描述
分析结果保存在afl-fuzz测试结果目录下的cov/文件夹中,其中zero-cov中保存了在运行过程中从未被执行到的代码或是函数,pos-cov中保存了在运行过程中被执行过至少一次的内容。同时,在cov/目录下的web文件夹中有一个index.html文件,即根据分析结果给出的可视化页面。
在这里插入图片描述

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
AFL(American Fuzzy Lop)是一款非常受欢迎的模糊测试工具,可以用于发现软件程序中的漏洞和错误。而QEMU是一款开源的虚拟机监控程序,可以模拟不同的系统架构,用于测试和调试。 在进行AFL QEMU测试二进制之前,我们首先需要安装AFL和QEMU这两个工具。安装完成后,我们可以通过以下步骤进行测试: 1. 准备一个待测试的二进制文件,可以是目标软件程序的可执行文件; 2. 使用AFL对二进制文件进行处理,将其变成可模糊测试的目标; 3. 设置AFL和QEMU的参数,如模糊测试的目标文件、输入样本和输出文件等; 4. 运行AFL QEMU,开始进行模糊测试AFL会根据设置的参数,生成各种变异的输入样本,并将其输入到待测试的二进制文件中; 5. QEMU会模拟执行这些输入样本,并监控目标程序的执行过程。它会在发现异常情况时,如程序崩溃或产生错误输出,记录下这些情况; 6. 模糊测试结束后,AFL会生成一个测试报告,包含了发现的漏洞和错误。我们可以根据这些报告,进行漏洞修复或错误修正。 通过AFL QEMU测试二进制,我们可以有效地发现软件程序中的潜在问题,提高程序的安全性和稳定性。同时,由于AFL和QEMU都是开源工具,可以根据需要进行自定义设置和扩展,以满足不同测试需求。总之,AFL QEMU测试二进制是一种非常有效的方法,可以帮助开发人员提升软件质量和性能。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值