AFL学习记录(二)——一次简单的测试
题目做不出来,先来写这篇记录。
昨天把环境搭建好了,今天就拿来简单的进行一次测试。还是使用昨天的代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
int vuln(char *str)
{
int len = strlen(str);
if(str[0] == 'A' && len == 66)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为A并且长度为66,则异常退出
}
else if(str[0] == 'F' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为6,则异常退出
}
else
{
printf("it is good!\n");
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100]={0};
gets(buf);//存在栈溢出漏洞
printf(buf);//存在格式化字符串漏洞
vuln(buf);
return 0;
}
这个程序有栈溢出,格式化字符串漏洞,并且在输入两种特定格式的字符串时会异常退出,来试一下用 AFL 能不能找出这些漏洞。
AFL 编译好之后是不会自动加入环境变量的,我把它的路径加入到了环境变量里,这样用起来稍微方便一些。
先插桩编译源代码,我使用 afl-clang-fast
来编译,这个是 llvm
模式的,会快许多(据说这是编译级的插桩)。
afl-clang-fast -g -o /path/of/bin /path/of/souce
编译好之后就可以进行 fuzz
了。我的虚拟机分配了多个核心,不一起用到话比较亏,所以我考虑多线程 fuzz
(其实这个程序非常小,fuzz
的很快,不需要多线程,但是先熟悉一下用法也好)。我使用 screen
来实现,免得开很多个终端
screen -S f1 afl-fuzz -i ./testcase -o ./sync_dir -M fuzzer1 afl-test-program
screen -S f2 afl-fuzz -i ./testcase -o ./sync_dir -S fuzzer2 afl-test-program
..
这些输进去就开始 fuzz
了。下面对这些指令进行一些简单的介绍。
这里 screen
后面的 -S
参数是指定这个会话的名字,之后可以用这个名字很方便地访问这个会话。而 afl-fuzz
之后的 -M
-S
两个参数是指定该线程模糊器是主模糊器还是从属模糊器,后面的 fuzzer1
指定模糊器的名字。这些模糊器的输出会放在在 sync_dir
中其名字对应的目录中。

大概就是这样一个结构。
这里简单介绍一下 screen
的基本使用
screen -r name
重启叫 name 的会话,使用 Crtl + A + D
,可以脱离与会话的连接,但不会结束终端中运行的进程,要删除终端,可以用 exit
。
同时 screen -ls
可以列出所有的会话。
关于界面

fuzzing
的时候就是这样的界面,简单说一下各个版块(详细的我也说不出来)
process timing
- 运行时长,距离最近发现的程序执行路径、崩溃、挂起的时间。
overall results
- 总共产出的结果,后三个分别是找到执行路径、崩溃、挂起的数量。第一个比较特别,数字的颜色会从洋红色逐渐变黄最后到绿色,到绿色的时候已经可以认为没有继续
fuzz
的意义了,此时继续fuzz
也难以发现新的 payload 了。
- 总共产出的结果,后三个分别是找到执行路径、崩溃、挂起的数量。第一个比较特别,数字的颜色会从洋红色逐渐变黄最后到绿色,到绿色的时候已经可以认为没有继续
cycle progress
- 本轮的进度。
map coverage
- 目标二进制文件中的插桩代码所观察到覆盖范围的细节。
stage progress
- 模糊器正在执行的文件变异策略、执行次数和执行速度。据说这个执行速度若低于 500 就说明效率太低,需要自己优化模糊器了。
Findings in depth
- 找到的执行路径,异常和挂起数量的信息。
Fuzzing strategy yields
- 关于突变策略产生的最新行为和结果的详细信息。
path geometry
- 模糊器找到的执行路径的信息。
结果
我总共获得了 9 组 payload,有六组触发了栈溢出并且造成了 SIGSEVE,那六组都是乱码,我这里就不放了,然后有下面三组
F9A@A@ //id_000001,sig_11,src_000000,op_havoc,rep_4
A%nA //id_000002,sig_11,src_000000,op_havoc,rep_4
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA A
//id_000003,sig_11,src_000000,op_havoc,rep_4
第一组触发了
else if(str[0] == 'F' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为6,则异常退出
}
第二组中有一个 %n
,触发了格式化字符串漏洞
第三组触发了
if(str[0] == 'A' && len == 66)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为A并且长度为66,则异常退出
}
找出了所有的漏洞。这是一个简单的练手,之后试试 fuzz 开源项目,看看能不能找出来(估计不能)。