AFL
一、简单测试
1 | int main(int argc, char const *argv[]) |
1.基础尝试
(1)白盒
①基础
首先使用简单的afl-clang-fast
来编译
1 | afl-clang-fast ./test.c -z execstack -fno-stack-protector -no-pie -z norelro -o afl_test |
然后跑起来,速度大约是11.6k
大概跑了6分钟,出现了第一个crash,查看一下,是大小为0x76
然后蒸馏一下afl-tmin -i inputSeed -o outSeed programer
大小变为了0x2d
,减去开始的4个字节,为0x29
,再看看IDA反汇编出来的
可以看到确实距离rbp
为0x28
,多溢出一个字节就可以覆盖到rbp
了。
此外设置的标志int v4
也在buf
上面,而非正常编译的先声明的更靠近栈底。
另外实际gdb
调试的,其main
函数栈不再是通过leave ret
来返回了,而是直接add rsp 0x38
,而rbp
为0
main
函数实际的返回地址距离buf
为0x28
倒是也能说的过去,就是不知道为什么要这么做。
②尝试__AFL_INIT()
在源码中加入__AFL_INIT()
,参考:
sakuraのAFL源码全注释(二)-安全客 - 安全资讯平台 (anquanke.com)
AFL-Training学习记录-安全客 - 安全资讯平台 (anquanke.com)
sakura师傅
介绍说,目的是为了在某些情况下可以减少操作系统、链接与libc内部执行程序的成本
iskindar师傅
介绍说,这是采用Deferred initialization
的方式来提高AFL的性能,大概提高1.5x,最合适的地方是放在read
函数前。也就是下面这几行代码。
1 |
|
放入进去
1 |
|
之后正常编译
1 | afl-clang-fast ./test.c -z execstack -fno-stack-protector -no-pie -z norelro -o afl_test |
也相差无几,可能是程序太小,相关的libc
库调用太少吧
发现crash之后蒸馏得到的和不加__AFL_INIT()
是一样的。
③尝试__AFL_LOOP(1000)
persistent
模式,常常用来fuzz
某些无状态的API
iskindar师傅
介绍说,对于一些无状态的API
库,可以复用进程来测试多个测试样例,从而减少fork系统调用的使用,进而减少OS的开销。
- 状态:指的是交互过程中保存的会话信息,比如
cookie、session
等
那么无状态的API
指的就是在这个API
里没有保存状态了。
先不使用__AFL_LOOP
1 |
|
库如下
1 |
|
编译加FUZZ
1 | afl-clang-fast ./testNoLoopAPI.c ./noStateAPI.c -z execstack -fno-stack-protector -no-pie -z norelro -o afl_API_noLoop_test |
开始运行之后会有(odd, check syntax!)
,但是运行一段时间后就没有了,不太知道为啥
最后大概五六分钟也能得到crash
加入__AFL_LOOP
1 |
|
然后编译FUZZ
1 | afl-clang-fast ./testAPI.c ./noStateAPI.c -z execstack -fno-stack-protector -no-pie -z norelro -o afl_API_test |
但是这个跑一个小时都没出结果,很奇怪,不知道为什么,难道说有read
或者有比对值的代码
1 | if(*flag == 0x1234){ |
就代表是有状态的API
吗
(2)黑盒
此外使用正常的gcc
编译后,采用黑盒测试时
1 | afl-fuzz -Q -i in -o hei_out ./test |
速度下降一大截
不过还是能够发现crash
,大概跑了十五六分钟。
可以看到大小是0x4f
,减去标志的4个字节即为0x4b
,与期待的大概0x39
字节还是相差一点
此外黑盒好像没办法蒸馏