https://codeantenna.com/a/QnTmjbAZo5

https://www.freebuf.com/articles/system/203302.html

fuzz是什么?fuzz是模糊测试,模糊测试是什么?模糊测试是一种软件测试技术?软件测试技术是什么……

但是,即使同为fuzz,因为技术不同,fuzz也分几种。

这篇讲afl-fuzz

afl的特点

afl的安装

源码安装

github源码安装

https://github.com/google/AFL.git

安装方法:

make

make install

如果编译时没有报错,输入以下afl-后tab,显示以下内容基本就成功了

1
2
ubuntu@VM-16-2-ubuntu:~$ afl-
afl-analyze afl-clang afl-clang++ afl-cmin afl-fuzz afl-g++ afl-gcc afl-gotcpu afl-plot afl-showmap afl-tmin afl-whatsup

具体

官网源码安装

过程向上看齐

二进制包

在debian软件源里有。apt install afl简单快捷

当然,这样的只能是标准版,要客制化也只能源码编译。

afl的使用

用于验证的样本(看fuzz怎么把它检测出来)

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
#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;
}

fuzz有黑盒和白盒测试,我们这里用白盒。

  • afl-gcc -g -o afl_test test.c编译文件(这里的afl-gcc其实和gcc大致差不多,不过为了打桩,多一层封装,如果C++就afl-g++类似)

  • 需要建立两个文件夹(名字无要求)一个in(装种子),一个out(装结果)。

    就像这样

    1
    afl_test  in  Makefile(可有可无)  out  test.c

    写种子

    1
    2
    touch in/testcase
    echo aaa > in/testcase

开始测试

使用命令

afl-fuzz -i in -o out ./afl_test

有一些可选参数,但有些最好选上-m none内存不限制-t 50005000us的超时

image-20220620041020889

出现这个,说明可以了,等待就行了,具体参数自行阅读

如果crash出现,将以以下形式展示

1
2
3
4
ubuntu@VM-16-2-ubuntu:~/test/out/crashes$ ls
id:000000,sig:06,src:000000,op:havoc,rep:64 id:000003,sig:06,src:000001,op:havoc,rep:64
id:000001,sig:11,src:000002,op:arith8,pos:0,val:-27 id:000004,sig:06,src:000001,op:havoc,rep:128
id:000002,sig:06,src:000002,op:havoc,rep:64 README.txt

xxd可以看到具体的内容

1
2
3
4
5
6
7
8
9
ubuntu@VM-16-2-ubuntu:~/test/out/crashes$ xxd id:000000,sig:06,src:000000,op:havoc,rep:64 
00000000: fefe fe32 3232 3232 3232 3232 327f 0000 ...2222222222...
00000010: 0032 3232 3232 3232 3232 32ff 01fe 3232 .2222222222...22
00000020: 4832 3232 3234 fefe fefe defe fefe 7fff H22224..........
00000030: fefe fefe fef4 16fe 1efe fe62 fd7f 0000 ...........b....
00000040: 000f 7fff ffff 0dfe fefe fefe fefe defe ................
00000050: fefe 7ffe fefe fefe 0cfe fefe fefe fe32 ...............2
00000060: 3232 2afe fe57 fd7f 0000 000f eafe e8fe 22*..W..........
00000070: ee55 .U

当然以上是简单的测试样本,真实情况需要改Makefile,把gcc改成afl-gcc,因为多次插装,无论是编译还是fuzz都会变慢,而且变慢很多

还有无源码的黑盒测试

这个就需要qemu了,之前在kernel中有提到过,还记得吗

相关的脚本也在其中写好了

在afl的根目录,执行以下命令

cd qemu_mode

./build_qemu_support.sh

不出意外,你应该会报错,关于syscall.c的。

1
2
make[1]: *** [/xxxxxxxx/AFL/qemu_mode/qemu-2.10.0/rules.mak:66: linux-user/syscall.o] Error 1
make: *** [Makefile:326: subdir-x86_64-linux-user] Error 2

这个需要打补丁。

以下是补丁syscall.diff

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
--- qemu-2.10.0-clean/linux-user/syscall.c	2020-03-12 18:47:47.898592169 +0100
+++ qemu-2.10.0/linux-user/syscall.c 2020-03-12 19:16:41.563074307 +0100
@@ -34,6 +34,7 @@
#include <sys/resource.h>
#include <sys/swap.h>
#include <linux/capability.h>
+#include <linux/sockios.h> // https://lkml.org/lkml/2019/6/3/988
#include <sched.h>
#include <sys/timex.h>
#ifdef __ia64__
@@ -116,6 +117,8 @@ int __clone2(int (*fn)(void *), void *ch
#include "qemu.h"

+extern unsigned int afl_forksrv_pid;
+
#ifndef CLONE_IO
#define CLONE_IO 0x80000000 /* Clone io context */
#endif

@@ -256,7 +259,9 @@ static type name (type1 arg1,type2 arg2,
#endif

#ifdef __NR_gettid
-_syscall0(int, gettid)
+// taken from https://patchwork.kernel.org/patch/10862231/
+#define __NR_sys_gettid __NR_gettid
+_syscall0(int, sys_gettid)
#else
/* This is a replacement for the host gettid() and must return a host
errno. */
@@ -6219,7 +6224,8 @@ static void *clone_func(void *arg)
cpu = ENV_GET_CPU(env);
thread_cpu = cpu;
ts = (TaskState *)cpu->opaque;
- info->tid = gettid();
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ info->tid = sys_gettid();
task_settid(ts);
if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr);
@@ -6363,9 +6369,11 @@ static int do_fork(CPUArchState *env, un
mapping. We can't repeat the spinlock hack used above because
the child process gets its own copy of the lock. */
if (flags & CLONE_CHILD_SETTID)
- put_user_u32(gettid(), child_tidptr);
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ put_user_u32(sys_gettid(), child_tidptr);
if (flags & CLONE_PARENT_SETTID)
- put_user_u32(gettid(), parent_tidptr);
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ put_user_u32(sys_gettid(), parent_tidptr);
ts = (TaskState *)cpu->opaque;
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
@@ -11402,7 +11410,8 @@ abi_long do_syscall(void *cpu_env, int n
break;
#endif
case TARGET_NR_gettid:
- ret = get_errno(gettid());
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ ret = get_errno(sys_gettid());
break;
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:

补丁找好了,怎么用呢

讲syscall.diff放进/AFL/qemu_mode/patches

然后重新./build_qemu_support.sh

cd ..

make install

具体执行加个-Q

afl-fuzz -i fuzz_in -o fuzz_out -Q ./afl_test

一些tips

2022-06-19

⬆︎TOP