最近在使用go-fuzz
工具进行模糊化测试,记录一下使用过程和理解。
安装
先确认本机有基础的golang环境,在此基础上,运行下列命令下载代码包
$ go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
完成上述下载源码包后已经可以开始fuzz操作了,官方的go-fuzz-corpus
仓库提供了很多的示例可以参考,对fuzz不熟悉可以执行下列操作进行熟悉。
$ go get -d github.com/dvyukov/go-fuzz-corpus
$ cd $GOPATH/src/github.com/dvyukov/go-fuzz-corpus
$ cd png
$ go-fuzz-build
上述是进入一个png示例库,执行go-fuzz-build
生成对应的zip文件。文件生成完成后就可以直接执行go-fuzz
操作,不过建议先执行go-fuzz -h
查看具体命令行参数,限制下cpu之类的,防止机器cpu拉满,风扇转的飞起。
$ go-fuzz
项目组织
上一节中有看到png库里的示例,或者其他示例,目录下一般有gen
文件夹与corpus
文件夹,以及一个fuzz.go
文件。
corpus
文件夹里用来收集输入语料库,可以放入初始语料,例如单元测试时的测试用例,也可以使用gen
中写程序来生成。
gen
文件夹中写个main.go
文件,主要用来生成语料库,示例可以看示例库的文件,写完后执行。
$ go run main.go -out ../corpus/
执行fuzz
go-fuzz
执行需要一个函数来作为入口,即:
func Fuzz(data []byte) int
示例,本文用iprange库进行测试。
package iprange
func Fuzz(data []byte)int{
_,err := ParseList(string(data))
if err != nil{
return 0
}
return 1
}
返回的int,有三种,1代表会提高此类输入的优先级,-1代表此类输入不会加入语料,0就是其他情况。
run起来后,注意,go-fuzz
是无限循环,所以需要自己手动停止,如果产生了crash,那么在当前目录下的crashers
会有三个输出文件,一个无后缀,一个后缀为.output
,一个后缀为.quoted
。
$ ls
17ee301be06245aa20945bc3ff3c4838abe13b52
17ee301be06245aa20945bc3ff3c4838abe13b52.output
17ee301be06245aa20945bc3ff3c4838abe13b52.quted
分别查看下三个文件内容:
$ cat 17ee301be06245aa20945bc3ff3c4838abe13b52
0.0.0.0/40%
上述可见是导致crash的输入内容。
$ cat 17ee301be06245aa20945bc3ff3c4838abe13b52.output
panic: runtime error: index out of range [3] with length 0
goroutine 1 [running]:
encoding/binary.bigEndian.Uint32(...)
/usr/local/go/src/encoding/binary/binary.go:112
_/***/iprange.(*ipParserImpl).Parse(0xc000093200, 0x11301e0, 0xc000115400,
...
exit status 2%
output文件是详细的错误追踪记录。
$ cat 17ee301be06245aa20945bc3ff3c4838abe13b52.quoted
"0.0.0.0/40"
quoted文件也是倒置crash的输入内容。