AFL进阶应用
1. afl-cov安装和使用
0)前言
官网:https://github.com/mrash/afl-cov
参看README文档,afl-cov 需要依赖以下环境:
- afl-fuzz
- python
- gcov, lcov, genhtml
gcov:随gcc一起发布,故一般不需要再安装。
lcov:是gcov的图形前端,可以收集多个源文件的gcov数据,并创建包含使用覆盖率信息注释的源代码html页面。需要用 apt 自行安装。
afl-cov:可快速调用gcov和lcov这两个工具来处理afl-fuzz测试用例的代码覆盖率结果。
genhtml:一般也自带,没有的话 apt 安装一下。
1)安装
sudo apt update
apt install lcov
git clone https://github.com/mrash/afl-cov.git
./afl-cov/afl-cov -V
# 不建议用 apt install afl-cov(此版本不支持分支覆盖率统计)
结果:
常见问题:
afl-cov源码是用python2写的,若电脑没有python2,则会报错提示python版本问题。
原因是项目里代码去找python2,而系统里没有python2更没在环境变量里。
注释:
- #!/usr/bin/env python2 表示去环境变量里找python2 ---- 这种写法更规范,代码可移植性好!!!
- #!/xx/anaconda3/bin/python 表执行指定路径下的python
此时可以用conda或python创建python2虚拟环境。
conda create -n py27 python=2
(conda env list # 列出)
(conda remove -n AFL --all # 删除)
接下来有三种方法:
法1. 激活使用
(conda activate py27 # 激活)
法2. 在/usr/bin下创建link软链接(推荐)
ln -s /software/anaconda3/envs/py27/bin/python2 /usr/bin/python2
法3. 改python脚本头解析注释(文件多不推荐)
解压后 afl-cov 项目文件夹下所有文件开头注释都注释成相应的python2。如下:
再执行便不再报错。
附:
# 查看目录结构
tree afl-cov -L 2
2)使用
为了方便使用,可将afl-cov放在环境变量里以方便终端直接调用!
cd XXX # 进入到 afl-cov 的上级目录。
export PATH=$PATH:$PWD/afl-cov
afl-cov -V # 验证
准备测试文件 test.c :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
int AFLTest(char *str)
{
int len = strlen(str);
if(str[0] == 'A' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为A并且长度为6,则异常退出
}
else if(str[0] == 'F' && len == 16)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为16,则异常退出
}
else if(str[0] == 'L' && len == 66)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为66,则异常退出
}
else
{
printf("it is good!\n");
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100]={0};
gets(buf); //存在栈溢出漏洞
printf(buf); //存在格式化字符串漏洞
AFLTest(buf);
return 0;
}
执行:
# 1.使用gcov和afl插桩
afl-gcc -fprofile-arcs -ftest-coverage -g -o test test.c
# 一般 `afl-gcc -g -o test test.c` 就是将test.c插桩编译成test二进制文件。
# -ftest-coverage:编译同时生成.gcno文件(即test.gcno),它包含了重建基本块图和相应的块的源码的行号的信息。
# -fprofile-arcs:编译同时生成.gcda文件(即test.gcda),它包含了弧跳变的次数等信息。
# 2.使用afl-fuzz生成测试用例
mkdir input # 事先建好input目录,存放种子路径
touch testcase # 种子文件
echo "aaa" > testcase # 随便写点啥,作为输入种子
afl-fuzz -i input/ -o output/ -- ./test
# 3.使用afl-cov分析覆盖率
afl-cov -d output/ --coverage-cmd "cat AFL_FILE | ./test -a -b -c" -c . --enable-branch-coverage --overwrite
# --coverage-cmd COVERAGE_CMD 或 -e COVERAGE_CMD:用来设置要执行的程序和参数,其中的AFL_FILE和afl中的”@@”类似,afl-cov会自动将AFL_FILE替换为fuzzer输出结果的文件名(也就是id:0000开头的文件),LD_LIBRARY_PATH则用来指定程序的库文件。
# --code-dir CODE_DIR 或 -c CODE_DIR:用于指定源码目录;
# --enable-branch-coverage:用于开启边缘覆盖率(分支覆盖率)统计;
结果查看:
在 output/cov/web 目录下可查看结果。其中
- index.html 显示了各个目录的覆盖率。
- 最为详细的是test.c.gcov.html文件。
每行代码前的数字代表这行代码被执行的次数,没有执行过的代码会被红色标注出来,如下图:
附:
上面是解析已经执行完毕的afl-fuzz输出结果,我们也可以使用–live参数与afl-fuzz同时运行,实时监控每次测试的覆盖率。命令改为:
afl-cov -d output/ --live --coverage-cmd "cat AFL_FILE | ./test -a -b -c" -c . --enable-branch-coverage --overwrite
其他命令参数:
usage: afl-cov [-h] [-e COVERAGE_CMD] [-d AFL_FUZZING_DIR] [-c CODE_DIR] [-O]
[--disable-cmd-redirection] [--disable-lcov-web]
[--disable-coverage-init] [--coverage-include-lines]
[--enable-branch-coverage] [--live] [--cover-corpus]
[--coverage-at-exit] [--sleep SLEEP] [--gcov-check]
[--gcov-check-bin GCOV_CHECK_BIN] [--background]
[--lcov-web-all] [--disable-lcov-exclude-pattern]
[--lcov-exclude-pattern LCOV_EXCLUDE_PATTERN]
[--func-search FUNC_SEARCH] [--line-search LINE_SEARCH]
[--src-file SRC_FILE] [--afl-queue-id-limit AFL_QUEUE_ID_LIMIT]
[--ignore-core-pattern] [--lcov-path LCOV_PATH]
[--genhtml-path GENHTML_PATH] [--readelf-path READELF_PATH]
[--stop-afl] [--validate-args] [-v] [-V] [-q]
optional arguments:
-h, --help show this help message and exit
-e COVERAGE_CMD, --coverage-cmd COVERAGE_CMD
Set command to exec (including args, and assumes code
coverage support)
-d AFL_FUZZING_DIR, --afl-fuzzing-dir AFL_FUZZING_DIR
top level AFL fuzzing directory
-c CODE_DIR, --code-dir CODE_DIR
Directory where the code lives (compiled with code
coverage support)
-O, --overwrite Overwrite existing coverage results
--disable-cmd-redirection
Disable redirection of command results to /dev/null
--disable-lcov-web Disable generation of all lcov web code coverage
reports
--disable-coverage-init
Disable initialization of code coverage counters at
afl-cov startup
--coverage-include-lines
Include lines in zero-coverage status files
--enable-branch-coverage
Include branch coverage in code coverage reports (may
be slow)
--live Process a live AFL directory, and afl-cov will exit
when it appears afl-fuzz has been stopped
--cover-corpus Measure coverage after running all available tests
instead of individually per queue file
--coverage-at-exit Only calculate coverage just before afl-cov exit.
--sleep SLEEP In --live mode, # of seconds to sleep between checking
for new queue files
--gcov-check Check to see if there is a binary in --coverage-cmd
(or in --gcov-check-bin) has coverage support
--gcov-check-bin GCOV_CHECK_BIN
Test a specific binary for code coverage support
--background Background mode - if also in --live mode, will exit
when the alf-fuzz process is finished
--lcov-web-all Generate lcov web reports for all id:NNNNNN* files
instead of just the last one
--disable-lcov-exclude-pattern
Allow default /usr/include/* pattern to be included in
lcov results
--lcov-exclude-pattern LCOV_EXCLUDE_PATTERN
Set exclude pattern for lcov results
--func-search FUNC_SEARCH
Search for coverage of a specific function
--line-search LINE_SEARCH
Search for coverage of a specific line number
(requires --src-file)
--src-file SRC_FILE Restrict function or line search to a specific source
file
--afl-queue-id-limit AFL_QUEUE_ID_LIMIT
Limit the number of id:NNNNNN* files processed in the
AFL queue/ directory
--ignore-core-pattern
Ignore the /proc/sys/kernel/core_pattern setting in
--live mode
--lcov-path LCOV_PATH
Path to lcov command
--genhtml-path GENHTML_PATH
Path to genhtml command
--readelf-path READELF_PATH
Path to readelf command
--stop-afl Stop all running afl-fuzz instances associated with
--afl-fuzzing-dir <dir>
--validate-args Validate args and exit
-v, --verbose Verbose mode
-V, --version Print version and exit
-q, --quiet Quiet mode