afl-fuzz多线程
-
afl-fuzz多线程
https://blog.csdn.net/lesliegail1/article/details/70209351
首先,我们阅读这篇博客对afl-fuzz单机多线程进行了解。我们了解了命令格式如下:
./afl-fuzz -i input_dir -o sync_dir -M fuzzer01 .. ./afl-fuzz -i input_dir -o sync_dir -S fuzzer02 .. ./afl-fuzz -i input_dir -o sync_dir -S fuzzer03 ..
其中,
-M
指定Master进程,-S
指定Slave进程,一般只有一个Master进程,可以指定多个Slave进程。每一个fuzzer都在sync_dir文件夹中有一个单独的空间来存储其状态,如/sync_dir/fuzzer01/
。
至于,M/S是确定性变异还是havoc变异,实验过程中发现,默认均为havoc变异。我们可以使用-D
对Master进程进行设置,只需要设置主进程即可。就像执行print(random.random())
语句,使用20个进程同时运行的结果可能不同;但是对于执行print(1)
语句,没有必要使用2个进程,因为结果都一样。 -
编程自动化实现
为了使用多进程,我们需要打开多个窗口执行不同的fuzz命令,如果我们设置进程数为32及以上,我们希望能通过编程自动化实现。本程序的关键是多进程及对afl-fuzz命令的拼接,还有一些细节上的设计。#!/usr/bin/env python import subprocess, threading, time, shutil, os, sys from typing import List def locate(label): ''' :param label: :return: the location of label in the cmd ''' try: separate: int = sys_args.index(label) except: print(label, 'should be appeared in the command!') exit(-1) return separate def separate(sys_args: List[str]): label = "--" separate: int = locate(label) after_args = sys_args[separate + 1 :] return after_args def input_dir(sys_args: List[str]): label = "-i" separate: int = locate(label) return sys_args[separate + 1] def output_dir(sys_args: List[str]): label = "-o" separate: int = locate(label) return sys_args[separate + 1] def do_work(cpu, input_dir, output_dir, hours, after_args): deterministic_arg = "-D" master_arg = "-S" if cpu == 0: master_arg = "-M" try: with open("logs/fuzzer{}.log".format(cpu), "w+") as f: cmd = ["afl-fuzz", "-m", "none", "-t", "5000"] if cpu == 0: cmd.extend([deterministic_arg]) input_dir = 'seeds_in' # 这里对主进程的input_dir进行了单独设置,根据实验要求可进行删除哦 else: env_cmd = 'export AFL_FAST_CAL=1' subprocess.call(env_cmd, shell=True) cmd.extend(["-i", input_dir]) cmd.extend(["-o", output_dir]) cmd.extend(["-V", "{}".format(hours * 3600)]) cmd.extend(["-b", "%d" % cpu]) # bind cpu cmd.extend([master_arg, "fuzzer%d" % cpu]) # master and secondary fuzzers cmd.extend(after_args) # targets: ./readelf -a cmd.extend(["@@"]) # @@ sp = subprocess.Popen(cmd, stdout=f, stderr=f) sp.wait() except: print('When creating fuzzer{}, some errors were encountered!'.format(cpu)) print("CPU %d afl-fuzz instance died" % cpu) if __name__ == '__main__': sys_args: List[str] = sys.argv[1:] after_args = separate(sys_args) input_dir = input_dir(sys_args) output_dir = output_dir(sys_args) num_cpus = 32 hours = 12 print('Next, we will start {} cpus to fuzz {} {} hours!'.format(num_cpus, after_args[0], hours)) assert os.path.exists(input_dir), "Invalid input directory" # judge whether the input directory exists os.path.exists("./logs") or os.mkdir("./logs") if os.path.exists(output_dir): shutil.rmtree(output_dir) # delete recursively existing output_dir os.mkdir(output_dir) # creating output directory # os.environ["AFL_NO_AFFINITY"] = "1" # 此环境变量被设置会禁止实例尝试绑定到Linux系统上的特定CPU 内核。这会减慢速度,但可以让您运行更多的afl-fuzz实例 # os.environ["AFL_NO_ARITH"] = "1" # 此环境变量被设置会导致AFL跳过大多数确定性算术过程,这对于加速基于文件格式为文本的模糊测试很有用 for cpu in range(0, num_cpus): print("creating fuzzer{}".format(cpu)) threading.Thread(target=do_work, args=[cpu, input_dir, output_dir, hours, after_args]).start() # Let master stabilize first if cpu == 0: print("please wait a moment for main fuzzer to start up.") time.sleep(5.0) while threading.active_count() > 1: time.sleep(10) try: subprocess.check_call(["afl-whatsup", "-s", output_dir]) except: pass print("fuzzing over, bye!")
-
使用说明
本程序默认提供"-m none", “-t 5000"参数,不必添加这些参数了,”-i -o"为必选参数,其他参数可以自行添加。使用 “–” 作为分隔符,前面是关于afl-fuzz的参数,后面是待测程序及参数。执行命令示例如下:python multi_fuzz.py -i seeds_in -o seeds_out -- ./readelf -a
考虑到输出种子较多,我们借助
AFL_FAST_CAL
环境变量将校准阶段的速度保持在2.5倍左右(尽管精度较低),这有助于针对慢速目标启动会话。export AFL_FAST_CAL=1
我们可以写一个sh自动化脚本,保存为
run.sh
,一键启动。export AFL_FAST_CAL=1 python multi_fuzz.py -i seeds_in -o seeds_out -- ./readelf -a
如果需要运行,只需要在命令行输入
sh run.sh
即可。 -
实验结果