github: https://github.com/jwilk/python-afl
入门:
- Taking a look at python-afl by Jussi Judin
- Introduction to Fuzzing in Python with AFL by Alex Gaynor
需要在/etc/environment
中添加
1 | export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 |
保证正常使用, 第一个是啥忘记了, 第二个是确认开启使用持久模式. (第一个想起来了!是要执行sudo bash -c 'echo core >/proc/sys/kernel/core_pattern'
)
最简单的用法是py-afl-fuzz -i input_dir/ -o results_dir/ -- python3 script.py
.
使用-C
选项就可以实现不用生成种子输入开始随机fuzzing了,不过需要在input_dir/
下生成一个只有一个空格的文件input0.txt
.
其中, inputs_dir
目录中给定的输入用例集合要尽可能小, 而且有趣, 这里有趣是指每个输入都应该能代表一类输入, 而非类似.
results_dir
目录结构如下:
results/
├── crashes/
├── fuzz_bitmap
├── fuzzer_stats
├── hangs/
├── plot_data
└── queue/
crashes
目录保存fuzz so far得到的所有craches.
plot_data
文件中保存fuzz过程中探索到的路径, unique crash的个数和最大深度的变化.
给个例子, 文件hack.py
中有如下代码:
1 | def hack(a, b): |
我们想通过fuzz使其抛出异常, 即找到输入为a=234, b=102
的情况.
1 | import afl, os, sys, hack |
inputs/
中预给的输入文件input0.txt
如下:
1 | 1 2 |
发现两个能引发异常的输入, 分别是\B1 2
和q 2
, 没有找到a=234, b=102
. 在有限时间内找到这个corner case很困难, 所以可以在字典中一些常用的可能引发错误的输入, 例如创建一个目录dicts
, 创建dict0.dict
, 内容为:
1 | 234 102 |
很快就引发了第三个unique crash.
接下来使用同样的方法对pydantic.datetime_parse
下的from_unix_seconds
方法进行fuzz, 很快找出三个unique crash, 分别是\B1
, q
, -11111111111111111111
. 10分钟后发现第四个unique crash: 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
.
1 | import afl, os, sys, pydantic |
还有一种使用afl.loop(N)
的用法,N
表示每轮测试用例个数, 称为持久模式. 这种用法不用在import
后写afl.init()
, 最快的持久模式不应该包含可能被之前执行影响而改变的全局的状态. 这种用法可以用于将之前的执行结果重用在当前状态的场景下.