AFL-StarterKit

目标程序源代码

首先准备测试的目标程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h> 
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

int vuln(char *str)
{
int len = strlen(str);
//如果输入的字符串的首字符为A并且长度为66,则异常退出
if(str[0] == 'A' && len == 66)
{
raise(SIGSEGV);
}
//如果输入的字符串的首字符为F并且长度为6,则异常退出
else if(str[0] == 'F' && len == 6)
{
raise(SIGSEGV);
}
else
{
printf("\nit is good!\n");
}
return 0;
}

int main(int argc, char *argv[])
{
int i;
char buf[100]={0};
printf( "Enter a value :");
scanf("%d", &i);
if ((i % 2) == 1)
{
getchar();
printf("Odd\nPlease enter a string: ");
gets(buf);//存在栈溢出漏洞
printf(buf);//存在格式化字符串漏洞
vuln(buf);
}
else
{
printf("Even\n");
}
return 0;
}

这里程序会首先判断用户输入数字的奇偶性,然后执行相应操作。

Setup AFL

AFL的安装非常简单

1
2
3
4
5
wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar xvf afl-latest.tgz
cd afl-*
$ make && make install
$ make install

之后使用afl编译目标程序
1
2
3
4
5
6
7
8
9
10
11
root@localhost:~/vlun# afl-gcc -g -o vuln vuln.c

afl-cc 2.52b by <[email protected]>
Origin: afl-gcc -g -o vuln vuln.c
Modified: gcc -g -o vuln vuln.c -B /usr/local/lib/afl -g -O3 -funroll-loops -D__AFL_COMPILER=1 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1

afl-as 2.52b by <[email protected]>
as_origin: /usr/local/lib/afl/as --64 -o /tmp/cc87FEhK.o /tmp/cc6V6Ux0.s
as_modified as --64 -o /tmp/cc87FEhK.o /tmp/.afl-24042-1569464334.s[+] Instrumented 14 locations (64-bit, non-hardened mode, ratio 100%).
/tmp/cc87FEhK.o: In function `main':
/root/vlun/vuln.c:37: warning: the `gets' function is dangerous and should not be used.

结合之前文章的分享,可以看到afl对目标程序进行了插桩。

Run the fuzzer

首先准备一下fuzz需要的testcase,然后就可以执行fuzz。

1
2
3
mkdir fuzz_in fuzz_out
echo "123\nABC" > fuzz_in/testcase
afl-fuzz -i fuzz_in -o fuzz_out ./vuln

fuzz进行之后可以看到如下界面:

  • process timing
    主要包含了afl运行的时间信息。
  • overall results
    包括运行的总周期数、总路径数、崩溃次数、超时次数。
  • map coverage
    其中map density是哈希表的密度,如多目标程序分支很多,会导致map density很大,这种情况会产生碰撞,影响fuzz结果。
  • stage progress
    当前执行的fuzz变异策略、执行的进度、执行的速度
  • findings in depth
    目标程序的路径信息和目标崩溃的统计

Analyze result

在fuzz_out/crashes/下面记录了6个会导致目标程序crash的测试用例:

1
2
3
4
5
6
7
root@localhost:~/vlun# ls fuzz_out/crashes/
id:000000,sig:11,src:000003,op:havoc,rep:4
id:000001,sig:06,src:000000+000003,op:splice,rep:64
id:000002,sig:06,src:000003,op:havoc,rep:8
id:000003,sig:06,src:000003,op:havoc,rep:4
id:000004,sig:06,src:000000,op:havoc,rep:8
id:000005,sig:11,src:000003+000000,op:splice,rep:8

  • id:000000,sig:11,src:000003,op:havoc,rep:4
    1
    2
    root@localhost:~/vlun# xxd fuzz_out/crashes/id:000000,sig:11,src:000003,op:havoc,rep:4
    00000000: 3132 330a 46c2 3939 2a1b 123.F.99*.
    输入到目标程序中的字符串为123.F.99.
    这里首先scanf会读取输入123,之后遇到”.”为非法字符,第一个输入即为123程序判断为奇数。之后读取第二个输入为”F.99
    .”,程序会产生异常信号。
  • id:000001,sig:06,src:000000+000003,op:splice,rep:64

    1
    2
    3
    4
    5
    6
    7
    8
    root@localhost:~/vlun# xxd fuzz_out/crashes/id:000001,sig:06,src:000000+000003,op:splice,rep:64
    00000000: 39cc cccc cccc c7ed edcb f2f2 f274 8787 9............t..
    00000010: 8787 8787 f2f2 f2f2 f2ed eded eded 10ed ................
    00000020: 10fb 3932 3313 031d edfb eded f0ed 0000 ..923...........
    00000030: 0400 eded 1bed 10fb 3932 3313 03ff 801b ........923.....
    00000040: ed0c ee7e e803 0007 eded eded 10ed 10fb ...~............
    00000050: 3932 3313 031d edfb eded f0ed c7ed e8d4 923.............
    00000060: 01f0 eddf ed1f dd00 0002 0011 0d00 ..............

    这里是个溢出的异常。

  • id:000002,sig:06,src:000003,op:havoc,rep:8
    还是溢出导致的异常。

  • id:000003,sig:06,src:000003,op:havoc,rep:4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    root@localhost:~/vlun# xxd fuzz_out/crashes/id:000002,sig:06,src:000003,op:havoc,rep:8
    00000000: 3132 330a 46c2 eeee eeee eeee eeee eeee 123.F...........
    00000010: ffee eeee eeee eeee eeed ffff eeee eeee ................
    00000020: eeee eeee 40ee eeee edee eeff ffee eeee ....@...........
    00000030: eeee eeee eeee eeee eeff ffee eeee eeee ................
    00000040: eeee eeee eeee eeed eeee eeee eeee eeee ................
    00000050: eeee eeee eeee edee eeee eeee eeee eeee ................
    00000060: ffff eeee eeee eeee eeee 40ee eeee edee ..........@.....
    00000070: eeff ffee eeee eeee 430a ........C.
  • id:000004,sig:06,src:000000,op:havoc,rep:8

    1
    2
    root@localhost:~/vlun# xxd fuzz_out/crashes/id:000003,sig:06,src:000003,op:havoc,rep:4
    00000000: 313a 3325 6ec2 430a 1:3%n.C.

    这里是printf的format string漏洞

  • id:000005,sig:11,src:000003+000000,op:splice,rep:8
    1
    2
    3
    4
    5
    6
    root@localhost:~/vlun# xxd fuzz_out/crashes/id:000005,sig:11,src:000003+000000,op:splice,rep:8
    00000000: 330a 41a2 a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 3.A.............
    00000010: a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 ................
    00000020: a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 a2a2 ................
    00000030: a2a2 a2a2 a2a2 a2a2 a2a2 a29e a2a2 8fa2 ................
    00000040: a2a2 a243 0a ...C.
    输入首字母为A并且长度为66,程序则会产生异常信号退出。

插桩分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
gdb-peda$ disassemble main
Dump of assembler code for function main:
... ...
/*main之前插入__afl_maybe_log*/
0x0000000000400976 <+22>: mov rcx,0xfc08
0x000000000040097d <+29>: call 0x400eb0 <__afl_maybe_log>
... ...
0x00000000004009f6 <+150>: je 0x400ace <main+366>
/*main中的分支插入__afl_maybe_log*/
0x0000000000400a12 <+178>: mov rcx,0x8ee
0x0000000000400a19 <+185>: call 0x400eb0 <__afl_maybe_log>


0x0000000000400a34 <+212>: mov edi,0x401370
0x0000000000400a39 <+217>: call 0x400860 <puts@plt>
0x0000000000400a3e <+222>: xchg ax,ax
... ...
0x0000000000400a56 <+246>: mov rcx,0xadb6
0x0000000000400a5d <+253>: call 0x400eb0 <__afl_maybe_log>
... ...
0x0000000000400a7a <+282>: mov rbx,QWORD PTR [rsp+0x78]
0x0000000000400a7f <+287>: xor rbx,QWORD PTR fs:0x28
0x0000000000400a88 <+296>: jne 0x400b4b <main+491>
0x0000000000400a8e <+302>: xchg ax,ax
... ...
End of assembler dump.

AFL对程序出现je,jne的地方进行了插桩,赋值给rcx的随机数用于对代码快进行定位。
mov rcx,0xXXXX

References

  1. Finding bugs using AFL
  2. 初探Fuzz-AFL
  3. Internals of AFL fuzzer - Compile Time Instrumentation