使用afl对libmodbus进行fuzz

1. 过程概览

  1. 下载编译libmodbus
  2. 利用 preeny 库辅助fuzz
  3. 获取样本数据,数据处理
  4. 启动afl

2. 具体步骤

2.1 下载编译libmodbus

libmodbus库是一个用于 modbus 通讯的库,通过这个库可以很方便的实现 modbus 服务器和客户端的通讯。

下载地址:https://github.com/stephane/libmodbus

首先下载好源码,目录下的 tests 目录里面有一些示例程序。

然后编译 modbus server,使用 afl-gcc 编译 libmodbus ,对 libmodbus 插桩。

unzip libmodbus-master.zip 
cd libmodbus-master/
./autogen.sh 
CC=afl-gcc CXX=afl-g++ ./configure --enable-static
make -j4

然后在 src/.libs 下就可以看到编译好的库

ls src/.libs/
libmodbus.a  libmodbus.la  libmodbus.lai  libmodbus.so  libmodbus.so.5  libmodbus.so.5.1.0  modbus-data.o  modbus.o  modbus-rtu.o  modbus-tcp.o

2.2 利用penny库辅助

因为 afl 默认只能 fuzz 通过 stdin 和 文件 获取输入的程序, 要 fuzz 网络相关的程序,需要使用一个库penny。这个库利用 LD_PRELOAD 机制,重写了 很多库函数, 其中 desock.c 这个文件负责重写 socket 相关的函数,其实现的功能就是当应用从 socket获取输入时,其实是从 stdin 获取输入。

首先下载编译

git clone https://github.com/zardus/preeny.git
cd preeny/
make

然后会在 x86_64-linux-gnu 目录下生成编译好的 lib 。

写个测试脚本,测试一下 (根据 tests 目录里面的 sock.c 改造)

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

int main()
{
    int s = socket(AF_INET, SOCK_STREAM, 0);
    char buf[1024]={0};
    char send_msg[] = "hello, send by send() :\n";
    send(s, send_msg, strlen(send_msg), 0);
    recv(s, buf, 1024, 0);
    printf("recv from recv() : %s\n", buf);
}

编译运行

gcc test.c -o test
LD_PRELOAD="/home/路径/preeny/x86_64-linux-gnu/desock.so" ./test

往 socket 调用 send , 成功往 stdout 输出了 字符串。

从 stdin 输入 xxx ,可以看到成功写入 buf 里面。

2.3 获取样本数据

一组好的样本数据对 fuzzer 的影响还是非常大的,一般我们可以去网上搜索样本,比如图片,视频文件等。对于我们这次的目标 libmodbus , 它自带了很多的测试程序,我们可以利用这些测试程序测试,然后用 tcpdump 抓包, 最后在把其中的请求数据保存下来,作为测试样本集。

首先使用 random-test-server 在 127.0.0.1:1502 起一个 modbus tcp 服务

cd tests/
./random-test-server

然后开启 tcpdump , 保存数据包到 指定路径/modbus.pcap

sudo tcpdump -i lo -w ~/modbus.pcap

最后使用 random-test-client 随机发送各种 modbus 请求到 127.0.0.1:1502

cd tests/
./random-test-client

然后写一个脚本把 ~/modbus.pcap 中由客户端发送来的数据包的内容提取出来,把每个数据包内容保存为一个单独的文件。

#transfer.py
from scapy.all import *
save_path = "./seeds/"
uuid = 0

if not os.path.exists(save_path):
    os.system("mkdir %s" %(save_path))

def save_to_file(data):
    global uuid
    with open("{}{}".format(save_path, uuid), "w") as fp:
        fp.write(str(data))
    uuid += 1
    print "write test file: {}".format(uuid)

modbus_session = ''
pg = rdpcap("modbus.pcap")
session = pg.sessions()
for k in session.keys():
    if k.endswith("127.0.0.1:1502"):
        modbus_session = session[k]

for s in modbus_session:
    payload = s[TCP].payload
    if len(payload) > 4:
        save_to_file(payload)

print "Total: %d tests" %(uuid)

2.4 启动fuzz

无样本

直接用 echo 生成了一个测试文件,如果直接用这个去测的话会发现速度非常的慢。

afl-gcc bandwidth-server-one.c -I../src ../src/.libs/libmodbus.a -o server
mkdir in
echo 11111 > in/1
LD_PRELOAD="/home/路径/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -i in -o out ./server

在这里插入图片描述

有样本

然后以生成的样本集作为初始样本集进行 fuzz

LD_PRELOAD="/home/路径/preeny/x86_64-linux-gnu/desock.so" afl-fuzz -i /seeds/  -o out ./server

速度有一定的提升,而且总路径数直接 1000+

在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值