简介
Protocol Buffers是一种序列化数据结构的协议。他是Google的开发的,而且与语言无关,与平台无关的可扩展机制,用于对结构化数据进行序列化(例如XML),但更小,更快,更简单。您定义要一次构造数据的方式,然后可以使用生成的特殊源代码轻松地使用各种语言在各种数据流中写入和读取结构化数据。
下面跟着一个台湾大佬实践了一下,并比较了下普通的libfuzzer
编译
官方得README写的很清楚,首先得装clang,这个直接用ubuntu的apt或者自己下载编译或者直接下载bin文件都可以
下面就粘贴一下官方的编译流程
1 | sudo apt-get update |
之后编译和测试(cmake有修改,加上了-DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON
)
1 | mkdir build |
这个编译有坑,事实并不是编译的时候出错,是最后测试包含在编译里,所以应该不影响使用,但这个问题也可以解决
实际在LibFuzzerExampleTest
中两个测试失败,根据issues:https://github.com/google/libprotobuf-mutator/issues/108
,是编译测试时没开启ASAN,导致测试的样本可能没有崩溃输出,导致测试失败,所以编译失败了
1 | Expected equality of these values: |
所以dende给出了解决方案,再ninja check
即可
https://github.com/google/libprotobuf-mutator/compare/master...dende:master
最后就是安装(ninja其实已经ninja: no work to do.
,check把该做的都做了)
1 | ninja |
Simple protobuf example
protoc程序需要使用libprotobuf-mutator/build/external.protobuf/bin/protoc
编译,如果使用apt安装的进行编译,编译后得文件是不能使用的,会报错
1 | ~/libprotobuf-mutator/build/external.protobuf/protoc ./test.proto --cpp_out=./ |
会生成XXX.pb.cc和XXX.pb.h
,XXX.pb.h
是我们程序include的头文件,XXX.pb.cc
是编译链接的时候使用
作者写了个Makefile,通过执行make,可以看到编译命令是
1 | clang++-9 -o test_proto test_proto.cc test.pb.cc /home/pwn/libprotobuf-mutator/build/external.protobuf/lib/libprotobufd.a -I/home/pwn/libprotobuf-mutator/build/external.protobuf/include |
那么运行
1 | pwn@ubuntu:~/libprotobuf-mutator_fuzzing_learning/1_simple_protobuf/genfiles$ ./test_proto |
通过这个实验,就是我们可以通过Protocol Buffers可以方便地定义数据结构,之后可以用set方法设置结构中的值,当然读取也很简单了
Combine libprotobuf-mutator with libfuzzer
先看harness.cc
,就一个FuzzTEST
函数
这个是先编译harness.cc
成harness.o
1 | clang++-9 -g -fsanitize=fuzzer,address -c -DLLVMFuzzerTestOneInput=FuzzTEST harness.cc |
之后在编译链接lpm_libfuzz.cc
1 | clang++-9 -g -fsanitize=fuzzer,address -o lpm_libfuzz harness.o lpm_libfuzz.cc test.pb.cc /home/pwn/libprotobuf-mutator/build/src/libfuzzer/libprotobuf-mutator-libfuzzer.so /home/pwn/libprotobuf-mutator/build/src/libprotobuf-mutator.so /home/pwn/libprotobuf-mutator/build/external.protobuf/lib/libprotobufd.a -I/home/pwn/libprotobuf-mutator/build/external.protobuf/include -I/home/pwn/libprotobuf-mutator |
运行需要那两个库
1 | pwn@ubuntu:~/libprotobuf-mutator_fuzzing_learning/2_libprotobuf_libfuzzer$ ./lpm_libfuzz |
再运行即可
我通过ida看了下,发现比普通的libfuzzer相比,就是将libfuzzer的data转化为protobuf之后我们对protobuf处理后再传给要fuzz的函数
Combine libprotobuf-mutator with libfuzzer ( custom mutator )
这个例子是自定义变异
比如这个里面,限制了test.b
只能是FUCK或者SHIT
1 | DEFINE_PROTO_FUZZER(const TEST &test_proto) { |
How to combine libprotobuf-mutator and AFL++
这是跟AFL++相结合,因为AFL++可以通过指定so文件去自定义变异的方法
跟着github下载编译afl++
https://github.com/vanhauser-thc/AFLplusplus
作者实现了afl++的自定义编译函数
1 | extern "C" size_t afl_custom_fuzz(uint8_t *buf, size_t buf_size, uint8_t *add_buf,size_t add_buf_size, uint8_t *mutated_out, size_t max_size) { |
这个是通过宏定义进行加载的so文件——AFL_CUSTOM_MUTATOR_LIBRARY
1 | pwn@ubuntu:~/libprotobuf-mutator_fuzzing_learning/4_libprotobuf_aflpp_custom_mutator$ cat run_fuzz.sh |
可以看到运行使用的变异策略是我们自定义的策略
普通libfuzzer与加了libprotobuf-mutator之后的对比
整体还是相同的,顺便看看libfuzzer的大概的原理
首先将LLVMFuzzerTestOneInput
函数传到fuzzer::FuzzerDriver
函数里
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
在fuzzer::FuzzerDriver
函数里面,就是利用LLVMFuzzerTestOneInput
函数初始化Fuzzer,之后尝试读取corpus(语料库)或者Dictionary(字典),最后进行循环地测试
1 | v121 = LLVMFuzzerTestOneInput_addr; |
接下来看看添加了libprotobuf-mutator之后的情况,不同的就是LLVMFuzzerTestOneInput
函数,普通的libfuzzer我们的代码就是自己实现LLVMFuzzerTestOneInput
函数,所以LLVMFuzzerTestOneInput
就是我们的代码
而libprotobuf-mutator是用libfuzzer传入的data参数转化为protobuf——下面的v16
之后将v16传到TestOneProtoInput
函数
1 | libfuzzer_data = v20; |
而TestOneProtoInput
函数就是DEFINE_PROTO_FUZZER
函数的代码
这个从源码也可以看出来https://github.com/google/libprotobuf-mutator/blob/fe76ed648dab1923d9b624b63dc3484fcc10dc76/src/libfuzzer/libfuzzer_macro.h#L28
1 | // Defines custom mutator, crossover and test functions using default |
那么实际DEFINE_PROTO_FUZZER
就是我们实现TestOneProtoInput
函数
而这个TestOneProtoInput
函数是由LLVMFuzzerTestOneInput
调用的,看到这,整个流程的通了
1 | #define DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, Proto) \ |
其实就是写好了LLVMFuzzerTestOneInput,让你自己写TestOneProtoInput
参考
https://github.com/google/libprotobuf-mutator
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning