├── .github └── ISSUE_TEMPLATE │ └── issue-report.md ├── 1_simple_protobuf ├── .gitignore ├── Makefile ├── README.md ├── test.proto └── test_proto.cc ├── 2_libprotobuf_libfuzzer ├── Makefile ├── README.md ├── harness.cc └── lpm_libfuzz.cc ├── 3_libprotobuf_libfuzzer_custom_mutator ├── Makefile ├── README.md ├── harness.cc └── lpm_libfuzz_custom_mutator.cc ├── 4_libprotobuf_aflpp_custom_mutator ├── .gitignore ├── Makefile ├── README.md ├── in │ ├── ii │ └── iii ├── lpm_aflpp_custom_mutator.cc ├── lpm_aflpp_custom_mutator.h ├── run_fuzz.sh └── vuln.c ├── 5_libprotobuf_aflpp_custom_mutator_input ├── .gitignore ├── Makefile ├── README.md ├── in │ └── ii ├── lpm_aflpp_custom_mutator_input.cc ├── lpm_aflpp_custom_mutator_input.h ├── run_fuzz.sh ├── test_proto_serializer.cc └── vuln.c ├── LICENSE └── README.md /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Issue for libprotobuf-mutator_fuzzing_learning 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Before you report an issue 11 | Please ask yourself the following questions: 12 | - [ ] Did I install the correct version of libraries/tools mentioned in project README ? 13 | - [ ] Did I read and follow all the steps in README while compiling binaries ? 14 | - [ ] Did I check the previous issues and still having problem ? 15 | - [ ] Am I sure that this issue is caused by the code in this repo ? 16 | 17 | # Environment setup 18 | > Please provide the version of OS, clang, AFL++ and libprotobuf-mutator 19 | 20 | # Description 21 | > Please provide details of the issue you ran into 22 | 23 | # Steps to reproduce 24 | > Please provide steps to reproduce the issue 25 | -------------------------------------------------------------------------------- /1_simple_protobuf/.gitignore: -------------------------------------------------------------------------------- 1 | genfiles/ 2 | test_proto 3 | -------------------------------------------------------------------------------- /1_simple_protobuf/Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++-14 2 | PB_SRC_DIR=./genfiles 3 | PB_SRC=$(PB_SRC_DIR)/test.pb.cc 4 | 5 | PROTOBUF_DIR=$(HOME)/libprotobuf-mutator/build/external.protobuf 6 | PROTOC=$(PROTOBUF_DIR)/bin/protoc 7 | PROTOBUF_LIB=$(PROTOBUF_DIR)/lib/libprotobufd.a 8 | INC=-I$(PROTOBUF_DIR)/include 9 | 10 | all: proto test_proto 11 | 12 | proto: test.proto 13 | mkdir -p $(PB_SRC_DIR) 14 | $(PROTOC) $^ --cpp_out=$(PB_SRC_DIR) 15 | 16 | test_proto: test_proto.cc $(PB_SRC) 17 | $(CXX) -I$(PB_SRC_DIR) -o $@ $^ $(PROTOBUF_LIB) $(INC) 18 | 19 | .PHONY: clean 20 | clean: 21 | rm -rf test_proto $(PB_SRC_DIR) 22 | -------------------------------------------------------------------------------- /1_simple_protobuf/README.md: -------------------------------------------------------------------------------- 1 | # Simple protobuf example 2 | 3 | * Create a simple protobuf message structure ( `test.proto` ): 4 | 5 | ``` 6 | syntax = "proto2"; 7 | 8 | message TEST { 9 | required uint32 a = 1; 10 | required string b = 2; 11 | } 12 | ``` 13 | 14 | * Use `make proto` to compile the protobuf. **Make sure there's a `protoc` binary in `libprotobuf-mutator/build/external.protobuf/bin/` before compiling**. 15 | - This will create a directory `genfiles` and generate `test.pb.cc` & `test.pb.h` inside the directory. 16 | 17 | * Write a simple protobuf testing program: 18 | 19 | ```cpp 20 | #include "test.pb.h" 21 | 22 | #include 23 | 24 | using std::cin; 25 | using std::cout; 26 | using std::endl; 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | TEST t; 31 | t.set_a(101); 32 | t.set_b("testtest"); 33 | cout << t.a() << endl; 34 | cout << t.b() << endl; 35 | return 0; 36 | } 37 | ``` 38 | 39 | * Use `make` to compile the program. 40 | 41 | In `Makefile`, you might have to replace `PROTOBUF_DIR` with your own protobuf installation directory ( `libprotobuf-mutator/build/external.protobuf` if you follow the installation instructions in libprotobuf-mutator's README file ). 42 | 43 | * Test it with `./test_proto`, it should print out the member data of the `TEST` protobuf ( `101` and `testtest` ). 44 | 45 | ## Reference 46 | * [Protocol Buffer Basics: C++](https://developers.google.com/protocol-buffers/docs/cpptutorial) 47 | 48 | -------------------------------------------------------------------------------- /1_simple_protobuf/test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | message TEST { 4 | required uint32 a = 1; 5 | required string b = 2; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /1_simple_protobuf/test_proto.cc: -------------------------------------------------------------------------------- 1 | #include "test.pb.h" 2 | 3 | #include 4 | 5 | using std::cin; 6 | using std::cout; 7 | using std::endl; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | TEST t; 12 | t.set_a(101); 13 | t.set_b("testtest"); 14 | cout << t.a() << endl; 15 | cout << t.b() << endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /2_libprotobuf_libfuzzer/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=lpm_libfuzz 2 | PB_SRC_DIR=../1_simple_protobuf/genfiles 3 | PB_SRC=$(PB_SRC_DIR)/test.pb.cc 4 | 5 | CXX=clang++-14 6 | CXXFLAGS=-g -fsanitize=fuzzer,address -I$(PB_SRC_DIR) 7 | 8 | PROTOBUF_DIR=$(HOME)/libprotobuf-mutator/build/external.protobuf 9 | LPM_DIR=$(HOME)/libprotobuf-mutator 10 | PROTOBUF_LIB=$(PROTOBUF_DIR)/lib/libprotobufd.a 11 | LPM_LIB=$(LPM_DIR)/build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a $(LPM_DIR)/build/src/libprotobuf-mutator.a 12 | INC=-I$(PROTOBUF_DIR)/include -I$(LPM_DIR) 13 | DFUZZ=-DLLVMFuzzerTestOneInput=FuzzTEST 14 | 15 | all: $(TARGET) 16 | 17 | # for testing libprotobuf + libfuzzer 18 | # compile harness first 19 | # then link lpm_libfuzz with harness.o & static libraries 20 | harness.o: harness.cc 21 | $(CXX) $(CXXFLAGS) -c $(DFUZZ) $< 22 | 23 | $(TARGET): harness.o $(TARGET).cc 24 | $(CXX) $(CXXFLAGS) -o $@ $^ $(PB_SRC) $(LPM_LIB) $(PROTOBUF_LIB) $(INC) # $(LPM_LIB) must be placed before $(PROTOBUF_LIB) 25 | 26 | .PHONY: clean 27 | clean: 28 | rm $(TARGET) *.o 29 | -------------------------------------------------------------------------------- /2_libprotobuf_libfuzzer/README.md: -------------------------------------------------------------------------------- 1 | # Combine libprotobuf-mutator with libfuzzer 2 | 3 | * `lpm_libfuzz.cc`: Convert protobuf to raw data and feed it to the target function 4 | * `harness.cc`: Our target function 5 | 6 | ## Makefile 7 | * Modify `PROTOBUF_DIR` to your own protobuf installation path 8 | * Modify `LPM_DIR` to the root direcotry of libprotobuf-mutator 9 | * Use `-DLLVMFuzzerTestOneInput=XXX` to set the target fuzzing function name 10 | 11 | ## Test the program 12 | * **!! Make sure you compile the protobuf in `1_simple_protobuf` first ( goto `1_simple_protobuf` and `make proto`) !!**. 13 | * `make` && `./lpm_libfuzz` 14 | * It should generate a crash sample immediately 15 | * The sample contains the crash data in protobuf format 16 | * Set the `PROTO_FUZZER_DUMP_PATH` env to generate the crash sample in raw format 17 | 18 | -------------------------------------------------------------------------------- /2_libprotobuf_libfuzzer/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" int FuzzTEST(const uint8_t *data, size_t size) { 5 | if(data[0] == '\x01') { 6 | __builtin_trap(); 7 | } 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /2_libprotobuf_libfuzzer/lpm_libfuzz.cc: -------------------------------------------------------------------------------- 1 | #include "libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h" 2 | #include "test.pb.h" 3 | 4 | #include 5 | 6 | using std::cin; 7 | using std::cout; 8 | using std::endl; 9 | 10 | std::string ProtoToData(const TEST &test_proto) { 11 | std::stringstream all; 12 | const auto &aa = test_proto.a(); 13 | const auto &bb = test_proto.b(); 14 | all.write((const char*)&aa, sizeof(aa)); 15 | if(bb.size() != 0) { 16 | all.write(bb.c_str(), bb.size()); 17 | } 18 | 19 | std::string res = all.str(); 20 | if (bb.size() != 0 && res.size() != 0) { 21 | // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf 22 | if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { 23 | std::ofstream of(dump_path); 24 | of.write(res.data(), res.size()); 25 | } 26 | } 27 | return res; 28 | } 29 | 30 | extern "C" int FuzzTEST(const uint8_t* data, size_t size); // our customized fuzzing function 31 | 32 | DEFINE_PROTO_FUZZER(const TEST &test_proto) { 33 | auto s = ProtoToData(test_proto); // convert protobuf to raw data 34 | FuzzTEST((const uint8_t*)s.data(), s.size()); // fuzz the function 35 | } 36 | -------------------------------------------------------------------------------- /3_libprotobuf_libfuzzer_custom_mutator/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=lpm_libfuzz_custom_mutator 2 | PB_SRC_DIR=../1_simple_protobuf/genfiles 3 | PB_SRC=$(PB_SRC_DIR)/test.pb.cc 4 | 5 | CXX=clang++-14 6 | CXXFLAGS=-g -fsanitize=fuzzer,address -I$(PB_SRC_DIR) 7 | 8 | PROTOBUF_DIR=$(HOME)/libprotobuf-mutator/build/external.protobuf 9 | LPM_DIR=$(HOME)/libprotobuf-mutator 10 | PROTOBUF_LIB=$(PROTOBUF_DIR)/lib/libprotobufd.a 11 | LPM_LIB=$(LPM_DIR)/build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a $(LPM_DIR)/build/src/libprotobuf-mutator.a 12 | INC=-I$(PROTOBUF_DIR)/include -I$(LPM_DIR) 13 | DFUZZ=-DLLVMFuzzerTestOneInput=FuzzTEST 14 | 15 | all: $(TARGET) 16 | 17 | # for testing libprotobuf + libfuzzer 18 | # compile harness first 19 | # then link lpm_libfuzz with harness.o & static libraries 20 | harness.o: harness.cc 21 | $(CXX) $(CXXFLAGS) -c $(DFUZZ) $< 22 | 23 | $(TARGET): harness.o $(TARGET).cc 24 | $(CXX) $(CXXFLAGS) -o $@ $^ $(PB_SRC) $(LPM_LIB) $(PROTOBUF_LIB) $(INC) # $(LPM_LIB) must be placed before $(PROTOBUF_LIB) 25 | 26 | .PHONY: clean 27 | clean: 28 | rm $(TARGET) *.o 29 | -------------------------------------------------------------------------------- /3_libprotobuf_libfuzzer_custom_mutator/README.md: -------------------------------------------------------------------------------- 1 | # Combine libprotobuf-mutator with libfuzzer ( custom mutator ) 2 | 3 | * `lpm_libfuzz_custom_mutator.cc`: Convert protobuf to raw data and feed it to the target function 4 | - Also register post processor with our custom mutator method 5 | * `harness.cc`: Our target function 6 | 7 | ## Makefile 8 | 9 | * Modify `PROTOBUF_DIR` to your own protobuf installation path 10 | * Modify `LPM_DIR` to the root direcotry of libprotobuf-mutator 11 | * Use `-DLLVMFuzzerTestOneInput=XXX` to set the target fuzzing function name 12 | 13 | ## Test the program 14 | * **!! Make sure you compile the protobuf in `1_simple_protobuf` first ( goto `1_simple_protobuf` and `make proto`) !!**. 15 | * `make` && `./lpm_libfuzz_custom_mutator` 16 | * It should generate a crash sample immediately 17 | * The sample contains the crash data in protobuf format 18 | * Set the `PROTO_FUZZER_DUMP_PATH` env to generate the crash sample in raw format 19 | * `test.b` should always be "FUCK" or "SHIT" in the crash sample 20 | 21 | -------------------------------------------------------------------------------- /3_libprotobuf_libfuzzer_custom_mutator/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" int FuzzTEST(const uint8_t *data, size_t size) { 5 | if(data[0] == '\x01') { 6 | __builtin_trap(); 7 | } 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /3_libprotobuf_libfuzzer_custom_mutator/lpm_libfuzz_custom_mutator.cc: -------------------------------------------------------------------------------- 1 | #include "libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h" 2 | #include "test.pb.h" 3 | 4 | #include 5 | 6 | using std::cin; 7 | using std::cout; 8 | using std::endl; 9 | 10 | std::string ProtoToData(const TEST &test_proto) { 11 | std::stringstream all; 12 | const auto &aa = test_proto.a(); 13 | const auto &bb = test_proto.b(); 14 | all.write((const char*)&aa, sizeof(aa)); 15 | if(bb.size() != 0) { 16 | all.write(bb.c_str(), bb.size()); 17 | } 18 | 19 | std::string res = all.str(); 20 | if (bb.size() != 0 && res.size() != 0) { 21 | // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf 22 | if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { 23 | std::ofstream of(dump_path); 24 | of.write(res.data(), res.size()); 25 | } 26 | } 27 | return res; 28 | } 29 | 30 | extern "C" int FuzzTEST(const uint8_t* data, size_t size); // our customized fuzzing function 31 | bool hasRegister = false; 32 | 33 | DEFINE_PROTO_FUZZER(const TEST &test_proto) { 34 | /* Register post processor with our custom mutator method */ 35 | if(!hasRegister) { 36 | protobuf_mutator::libfuzzer::RegisterPostProcessor( 37 | TEST::descriptor(), 38 | [](google::protobuf::Message* message, unsigned int seed) { 39 | TEST *t = static_cast(message); 40 | /* test.b will only be "FUCK" or "SHIT" */ 41 | if (seed % 2) { 42 | t->set_b("FUCK"); 43 | } 44 | else { 45 | t->set_b("SHIT"); 46 | } 47 | } 48 | ); 49 | hasRegister = true; 50 | return; 51 | } 52 | 53 | auto s = ProtoToData(test_proto); 54 | FuzzTEST((const uint8_t*)s.data(), s.size()); 55 | } 56 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | vuln 4 | out/* 5 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=lpm_aflpp_custom_mutator 2 | PB_SRC_DIR=../1_simple_protobuf/genfiles 3 | PB_SRC=$(PB_SRC_DIR)/test.pb.cc 4 | 5 | CXX=clang++-14 6 | CXXFLAGS=-I$(PB_SRC_DIR) 7 | 8 | AFLCC=$(HOME)/AFLplusplus/afl-gcc 9 | 10 | PROTOBUF_DIR=$(HOME)/libprotobuf-mutator/build/external.protobuf 11 | LPM_DIR=$(HOME)/libprotobuf-mutator 12 | LPM_LIB=$(LPM_DIR)/build/src/libprotobuf-mutator.so 13 | INC=-I$(PROTOBUF_DIR)/include -I$(LPM_DIR) 14 | 15 | all: $(TARGET).so 16 | 17 | $(TARGET).so: $(TARGET).cc $(PB_SRC) 18 | $(CXX) $(CXXFLAGS) -fPIC -c $^ $(INC) 19 | $(CXX) -shared -Wall -O3 -o $@ *.o $(LPM_LIB) 20 | 21 | vuln: vuln.c 22 | $(AFLCC) -o $@ $^ 23 | 24 | .PHONY: clean 25 | clean: 26 | rm *.so *.o vuln 27 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/README.md: -------------------------------------------------------------------------------- 1 | > **2020/04/03 update**: 2 | > It is recommended that reader learn how to combine libprotobuf-mutator and AFL++ with [5_libprotobuf_aflpp_custom_mutator_input](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input). It provides more details and informations about how to handle input in the custom mutator. 3 | 4 | # Combine libprotobuf-mutator with AFL++ 5 | * `lpm_aflpp_custom_mutator.cc`: Shared library for AFL++ 6 | - Custom mutate `TEST` protobuf. 7 | + In fact it just randomly generate a brand new `TEST` protobuf message. 8 | - Convert the protobuf to raw data and return the result to AFL++. 9 | * `lpm_aflpp_custom_mutator.h`: Declare `afl_custom_fuzz` as a friend function so it can use protobuf's mutators. 10 | - Since `MutateString` is a protected function in `protobuf_mutator::Mutator`, `afl_custom_fuzz` has to be a friend function so it can call `mutator.MutateString()`. 11 | * `vuln.c`: Vulnerable C program. 12 | 13 | ## Makefile 14 | * Modify `PROTOBUF_DIR` to your own protobuf installation path. 15 | * Modify `LPM_DIR` to the root direcotry of libprotobuf-mutator. 16 | * Modify `AFLCC` to the path of an AFL++'s compiler. 17 | 18 | ## Test the program 19 | **!! Make sure you compile the protobuf in `1_simple_protobuf` first ( goto `1_simple_protobuf` and `make proto`) !!.** 20 | 21 | This example uses the shared library of `libprotobuf-mutator`. Make sure you have `libprotobuf-mutator.so` compiled. You can refer to the [README](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/README.md) in this repo to learn how to compile the shared library. 22 | 23 | * `make` 24 | - This will create `lpm_aflpp_custom_mutator.so`, the shared library for AFL++ ( for custom mutator's usage ). 25 | * `make vuln` to create the vulnerable binary. 26 | * `run_fuzz.sh` 27 | - Modify the path of `afl-fuzz` before you run the script. 28 | - **To run the script, use the following command: `LD_LIBRARY_PATH=/usr/local/lib ./run_fuzz.sh`** 29 | + Make sure `LD_LIBRARY_PATH` is set to the path that contains the `libprotobuf-mutator.so.0` library. By default it's installed in `/usr/local/lib` when installing libprotobuf-mutator via `sudo ninja install`. 30 | + Somehow we can't write this line in `run_fuzz.sh`, have to specify it in the command line instead. 31 | - `AFL_CUSTOM_MUTATOR_ONLY=1` is optional. However this is recommended since we want to observe the mutation performance ( = how well it generate a sample that crashes the program ) of our custom mutator. 32 | * It should generate the crash samples immediately 33 | - Check `out/crashes/id:000xxxxx.........`. 34 | - The first byte of the crash sample should be `0xe8` or `0x02`. 35 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/in/ii: -------------------------------------------------------------------------------- 1 | a: 7 2 | b: "aaaa" 3 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/in/iii: -------------------------------------------------------------------------------- 1 | a: 100 2 | b: "bbbb" 3 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/lpm_aflpp_custom_mutator.cc: -------------------------------------------------------------------------------- 1 | #include "lpm_aflpp_custom_mutator.h" 2 | 3 | using std::cin; 4 | using std::cout; 5 | using std::endl; 6 | 7 | std::string ProtoToData(const TEST &test_proto) { 8 | std::stringstream all; 9 | const auto &aa = test_proto.a(); 10 | const auto &bb = test_proto.b(); 11 | all.write((const char*)&aa, sizeof(aa)); 12 | if(bb.size() != 0) { 13 | all.write(bb.c_str(), bb.size()); 14 | } 15 | 16 | std::string res = all.str(); 17 | if (bb.size() != 0 && res.size() != 0) { 18 | // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf 19 | if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { 20 | std::ofstream of(dump_path); 21 | of.write(res.data(), res.size()); 22 | } 23 | } 24 | return res; 25 | } 26 | 27 | /** 28 | * Initialize this custom mutator 29 | * 30 | * @param[in] afl a pointer to the internal state object. Can be ignored for 31 | * now. 32 | * @param[in] seed A seed for this mutator - the same seed should always mutate 33 | * in the same way. 34 | * @return Pointer to the data object this custom mutator instance should use. 35 | * There may be multiple instances of this mutator in one afl-fuzz run! 36 | * Return NULL on error. 37 | */ 38 | extern "C" custom_mutator_t *afl_custom_init(void *afl, unsigned int seed) { 39 | custom_mutator_t *data = (custom_mutator_t *)calloc(1, sizeof(custom_mutator_t)); 40 | if (!data) { 41 | perror("[mutator] [afl_custom_init] custom_mutator alloc failed"); 42 | return NULL; 43 | } 44 | 45 | data->seed = seed; 46 | data->mutated_out_buf = (uint8_t*)calloc(1, 64); // Initial mutated_out buffer size is 64 47 | data->mutated_out_buf_size = 64; 48 | 49 | srand(seed); 50 | return data; 51 | } 52 | 53 | /** 54 | * Perform custom mutations on a given input 55 | * 56 | * @param[in] data pointer returned in afl_custom_init for this fuzz case 57 | * @param[in] buf Pointer to input data to be mutated 58 | * @param[in] buf_size Size of input data 59 | * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on 60 | * error. 61 | * @param[in] add_buf Buffer containing the additional test case 62 | * @param[in] add_buf_size Size of the additional test case 63 | * @param[in] max_size Maximum size of the mutated output. The mutation must not 64 | * produce data larger than max_size. 65 | * @return Size of the mutated output. 66 | */ 67 | extern "C" size_t afl_custom_fuzz(custom_mutator_t *data, // custom mutator state 68 | uint8_t *buf, size_t buf_size, // input data to be mutated 69 | uint8_t **out_buf, // output buffer 70 | uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL 71 | size_t max_size) { 72 | 73 | // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" 74 | // A simple test shows that "buf" will be the content of the current test case 75 | // "add_buf" will be the next test case ( from AFL++'s input queue ) 76 | 77 | // Here we implement our own custom mutator 78 | static MyMutator mutator; 79 | TEST input; 80 | // mutate input.a ( integer ) 81 | int id = rand() % 305; 82 | input.set_a(id); 83 | // mutate input.b ( string ) 84 | std::string new_string = mutator.MutateString("", 1000); // use the default protobuf mutator 85 | input.set_b(new_string); 86 | // convert input from TEST to raw data, and copy to mutated_out 87 | const TEST *tmp = &input; 88 | std::string raw = ProtoToData(*tmp); // convert TEST to raw data 89 | 90 | size_t mutated_size = raw.size() <= max_size ? raw.size() : max_size; // check if raw data's size is larger than max_size 91 | // Reallocate mutated_out buffer if needed 92 | if(data->mutated_out_buf_size < mutated_size) { 93 | data->mutated_out_buf = (uint8_t*)realloc(data->mutated_out_buf, mutated_size); 94 | data->mutated_out_buf_size = mutated_size; 95 | } 96 | 97 | // Copy the raw data to output buffer 98 | memcpy(data->mutated_out_buf, raw.c_str(), mutated_size); 99 | *out_buf = data->mutated_out_buf; 100 | 101 | return mutated_size; 102 | } 103 | 104 | /** 105 | * Deinitialize everything 106 | * 107 | * @param data The data ptr from afl_custom_init 108 | */ 109 | extern "C" void afl_custom_deinit(custom_mutator_t *data) { 110 | free(data->mutated_out_buf); 111 | free(data); 112 | return; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/lpm_aflpp_custom_mutator.h: -------------------------------------------------------------------------------- 1 | #include "libprotobuf-mutator/src/mutator.h" 2 | #include "test.pb.h" 3 | 4 | #include 5 | 6 | /** 7 | custom_mutator state structure 8 | Reference: https://github.com/airbus-seclab/AFLplusplus-blogpost/blob/b0cfc7016bd60cf998969d79a78eabd8471c78eb/src/mutator/custom_mutator.cpp#L29 9 | */ 10 | typedef struct custom_mutator { 11 | unsigned int seed; 12 | uint8_t *mutated_out_buf; 13 | size_t mutated_out_buf_size; 14 | } custom_mutator_t; 15 | 16 | extern "C" size_t afl_custom_fuzz(custom_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size); 17 | 18 | class MyMutator : public protobuf_mutator::Mutator { 19 | public: 20 | friend size_t afl_custom_fuzz(custom_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size); 21 | }; 22 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/run_fuzz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | AFL_CUSTOM_MUTATOR_ONLY=1 \ 4 | AFL_CUSTOM_MUTATOR_LIBRARY=$HOME/libprotobuf-mutator_fuzzing_learning/4_libprotobuf_aflpp_custom_mutator/lpm_aflpp_custom_mutator.so \ 5 | AFL_SKIP_CPUFREQ=1 \ 6 | $HOME/AFLplusplus/afl-fuzz -i ./in -o ./out ./vuln 7 | 8 | -------------------------------------------------------------------------------- /4_libprotobuf_aflpp_custom_mutator/vuln.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | char str[100]={}; 10 | read(0, str, 100); 11 | int *ptr = NULL; 12 | if( str[0] == '\x02' || str[0] == '\xe8') { 13 | *ptr = 123; 14 | } 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | vuln 4 | test_proto_serializer 5 | out/* 6 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=lpm_aflpp_custom_mutator_input 2 | PB_SRC_DIR=../1_simple_protobuf/genfiles 3 | PB_SRC=$(PB_SRC_DIR)/test.pb.cc 4 | 5 | CXX=clang++-14 6 | CXXFLAGS=-I$(PB_SRC_DIR) 7 | 8 | AFLCC=$(HOME)/AFLplusplus/afl-gcc 9 | 10 | PROTOBUF_DIR=$(HOME)/libprotobuf-mutator/build/external.protobuf 11 | PROTOBUF_LIB=$(PROTOBUF_DIR)/lib/libprotobufd.a 12 | 13 | LPM_DIR=$(HOME)/libprotobuf-mutator 14 | LPM_LIB=$(LPM_DIR)/build/src/libprotobuf-mutator.a 15 | 16 | INC=-I$(PROTOBUF_DIR)/include -I$(LPM_DIR) 17 | 18 | all: $(TARGET).so 19 | 20 | $(TARGET).so: $(TARGET).cc $(PB_SRC) 21 | $(CXX) $(CXXFLAGS) -fPIC -c $^ $(INC) 22 | $(CXX) -shared -Wall -O3 -o $@ *.o $(LPM_LIB) $(PROTOBUF_LIB) 23 | 24 | vuln: vuln.c 25 | $(AFLCC) -o $@ $^ 26 | 27 | test_proto_serializer: test_proto_serializer.cc $(PB_SRC) 28 | $(CXX) $(CXXFLAGS) -o $@ $^ $(PROTOBUF_LIB) $(INC) 29 | 30 | .PHONY: clean 31 | clean: 32 | rm *.so *.o vuln test_proto_serializer 33 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/README.md: -------------------------------------------------------------------------------- 1 | 2 | > Notice: 3 | > AFL++'s custom mutator might be frequently updated. Make sure to check out its [document](https://github.com/vanhauser-thc/AFLplusplus/blob/master/docs/custom_mutators.md) for the latest changes. 4 | > I'll try my best to follow the latest APIs of its custom mutator. 5 | 6 | # Handling input from AFL++ in our custom mutator 7 | 8 | ## Intro 9 | 10 | In the example of [4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator), you might notice that the custom mutator **doesn't handle the input data at all** -- all it does is randomly generate a new `TEST` protobuf message. This might be inconvenient if we want to fuzz the program with some input samples. 11 | 12 | Here in this example, it'll show you how to process the input data from AFL++, convert it to a `TEST` protobuf and mutate the protobuf with libprotobuf-mutator. It also provide an example of a custom `PostProcessor`, which allow user to process the protobuf message after the mutation. 13 | 14 | ## Source code 15 | * `lpm_aflpp_custom_mutator_input.cc`: Shared library for AFL++ 16 | - Parse the input data and convert it to `TEST` protobuf message. 17 | - Mutate the protobuf with libprotobuf-mutator. 18 | - Register a `PostProcessor` so we can process the result of the mutation. 19 | + The mutator in libprotobuf-mutator is kind of simple, we'll have to use a PostProcessor to optimize its mutation, or else it's pretty hard to trigger the crash in our `vuln` program. 20 | - Convert the protobuf to raw data and return the result to AFL++. 21 | * `lpm_aflpp_custom_mutator.h`: Declare our custom mutator. 22 | * `test_proto_serializer.cc`: A program used for generating the serialized `TEST` protobuf. 23 | - In order to convert the input data to `TEST`, the input data **should be serialized first**. 24 | * `vuln.c`: Vulnerable C program. 25 | 26 | ## Makefile 27 | * Modify `PROTOBUF_DIR` to your own protobuf installation path. 28 | * Modify `LPM_DIR` to the root directory of libprotobuf-mutator. 29 | * Modify `AFLCC` to the path of an AFL++'s compiler. 30 | 31 | ## Test the program 32 | **!! Make sure you compile the protobuf in `1_simple_protobuf` first ( goto `1_simple_protobuf` and `make proto`) !!.** 33 | 34 | Unlike the one in [4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/Makefile), the example uses the static library of `libprotobuf-mutator`. Make sure this library is compiled with `-fPIC` flag. You can use the following `cmake` command to enable the option: 35 | 36 | ```sh 37 | cmake .. -GNinja -DCMAKE_C_COMPILER=clang \ 38 | -DCMAKE_CXX_COMPILER=clang++ \ 39 | -DCMAKE_BUILD_TYPE=Debug \ 40 | -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ 41 | -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" 42 | ``` 43 | 44 | > Reference: [afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator/blob/master/build.sh) 45 | 46 | * `make` 47 | - This will create `lpm_aflpp_custom_mutator_input.so`, the shared library for AFL++ ( for custom mutator's usage ). 48 | * `make vuln` to create the vulnerable binary. 49 | * `make test_proto_serializer` to create the serializer. 50 | - Use this program to generate the input sample in `./in`. 51 | * `run_fuzz.sh` 52 | - Modify the path of `afl-fuzz` before you run the script. 53 | - `AFL_DISABLE_TRIM=1` is required, since we don't want AFL++ trim our data before running into our custom mutator. 54 | - `AFL_CUSTOM_MUTATOR_ONLY=1` is optional. However this is recommended since we want to observe the mutation performance ( = how well it generate a sample that crashes the program ) of our custom mutator. 55 | 56 | * It should generate the crash samples immediately 57 | * Check `out/crashes/id:000xxxxx.........`. 58 | * The first byte of the crash sample should be `0xe8` or `0x02`. 59 | * You can take out the `PostProcessor` to see how "slow" it will generate a crash sample without it. 60 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/in/ii: -------------------------------------------------------------------------------- 1 | daaaa -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/lpm_aflpp_custom_mutator_input.cc: -------------------------------------------------------------------------------- 1 | #include "lpm_aflpp_custom_mutator_input.h" 2 | 3 | using std::cin; 4 | using std::cout; 5 | using std::endl; 6 | 7 | std::string ProtoToData(const TEST &test_proto) { 8 | std::stringstream all; 9 | const auto &aa = test_proto.a(); 10 | const auto &bb = test_proto.b(); 11 | all.write((const char*)&aa, sizeof(aa)); 12 | if(bb.size() != 0) { 13 | all.write(bb.c_str(), bb.size()); 14 | } 15 | 16 | std::string res = all.str(); 17 | if (bb.size() != 0 && res.size() != 0) { 18 | // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf 19 | if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { 20 | std::ofstream of(dump_path); 21 | of.write(res.data(), res.size()); 22 | } 23 | } 24 | return res; 25 | } 26 | 27 | /** 28 | * Initialize this custom mutator 29 | * 30 | * @param[in] afl a pointer to the internal state object. Can be ignored for 31 | * now. 32 | * @param[in] seed A seed for this mutator - the same seed should always mutate 33 | * in the same way. 34 | * @return Pointer to the data object this custom mutator instance should use. 35 | * There may be multiple instances of this mutator in one afl-fuzz run! 36 | * Return NULL on error. 37 | */ 38 | extern "C" custom_mutator_t *afl_custom_init(void *afl, unsigned int seed) { 39 | // Initialize custom mutator structure 40 | custom_mutator_t *data = (custom_mutator_t *)calloc(1, sizeof(custom_mutator_t)); 41 | if (!data) { 42 | perror("[mutator] [afl_custom_init] custom_mutator alloc failed"); 43 | return NULL; 44 | } 45 | 46 | // Initialize seed 47 | data->seed = seed; 48 | srand(seed); 49 | 50 | // Initialize mutated output buffer & size 51 | data->mutated_out_buf = (uint8_t*)calloc(1, 64); // Initial mutated_out buffer size is 64 52 | data->mutated_out_buf_size = 64; 53 | 54 | // Initialize custom mutator 55 | data->mutator = new MyMutator(); 56 | data->mutator->RegisterPostProcessor( 57 | TEST::descriptor(), 58 | [](google::protobuf::Message* message, unsigned int seed) { 59 | // libprotobuf-mutator's built-in mutator is kind of....crappy :P 60 | // Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q 61 | // We register a post processor to apply our dumb fuzz 62 | 63 | TEST *t = static_cast(message); 64 | t->set_a(rand()); 65 | }); 66 | 67 | return data; 68 | } 69 | 70 | /** 71 | * Perform custom mutations on a given input 72 | * 73 | * @param[in] data pointer returned in afl_custom_init for this fuzz case 74 | * @param[in] buf Pointer to input data to be mutated 75 | * @param[in] buf_size Size of input data 76 | * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on 77 | * error. 78 | * @param[in] add_buf Buffer containing the additional test case 79 | * @param[in] add_buf_size Size of the additional test case 80 | * @param[in] max_size Maximum size of the mutated output. The mutation must not 81 | * produce data larger than max_size. 82 | * @return Size of the mutated output. 83 | */ 84 | extern "C" size_t afl_custom_fuzz(custom_mutator_t *data, // return value from afl_custom_init 85 | uint8_t *buf, size_t buf_size, // input data to be mutated 86 | uint8_t **out_buf, // output buffer 87 | uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL 88 | size_t max_size) { 89 | // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" 90 | // A simple test shows that "buf" will be the content of the current test case 91 | // "add_buf" will be the next test case ( from AFL++'s input queue ) 92 | 93 | TEST input; 94 | // parse input data to TEST 95 | // Notice that input data should be a serialized protobuf data 96 | // Check ./in/ii and test_protobuf_serializer for more detail 97 | bool parse_ok = input.ParseFromArray(buf, buf_size); 98 | if(!parse_ok) { 99 | // Invalid serialize protobuf data. Don't mutate. 100 | // Return the dummy buffer. Also mutated_size = 0 101 | *out_buf = dummy; 102 | return 0; 103 | } 104 | // mutate the protobuf 105 | data->mutator->Mutate(&input, max_size); 106 | 107 | // Convert protobuf to raw data 108 | const TEST *tmp = &input; 109 | std::string raw = ProtoToData(*tmp); 110 | 111 | size_t mutated_size = raw.size() <= max_size ? raw.size() : max_size; // check if raw data's size is larger than max_size 112 | // Reallocate mutated_out buffer if needed 113 | if(data->mutated_out_buf_size < mutated_size) { 114 | data->mutated_out_buf = (uint8_t*)realloc(data->mutated_out_buf, mutated_size); 115 | data->mutated_out_buf_size = mutated_size; 116 | } 117 | // Copy the raw data to output buffer 118 | memcpy(data->mutated_out_buf, raw.c_str(), mutated_size); 119 | *out_buf = data->mutated_out_buf; 120 | 121 | return mutated_size; 122 | } 123 | 124 | /** 125 | * Deinitialize everything 126 | * 127 | * @param data The data ptr from afl_custom_init 128 | */ 129 | extern "C" void afl_custom_deinit(custom_mutator_t *data) { 130 | delete data->mutator; 131 | free(data->mutated_out_buf); 132 | free(data); 133 | return; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/lpm_aflpp_custom_mutator_input.h: -------------------------------------------------------------------------------- 1 | #include "libprotobuf-mutator/src/mutator.h" 2 | #include "test.pb.h" 3 | 4 | #include 5 | 6 | class MyMutator : public protobuf_mutator::Mutator { 7 | }; 8 | 9 | /** 10 | custom_mutator state structure 11 | Reference: https://github.com/airbus-seclab/AFLplusplus-blogpost/blob/b0cfc7016bd60cf998969d79a78eabd8471c78eb/src/mutator/custom_mutator.cpp#L29 12 | */ 13 | typedef struct custom_mutator { 14 | MyMutator *mutator; 15 | unsigned int seed; 16 | uint8_t *mutated_out_buf; 17 | size_t mutated_out_buf_size; 18 | } custom_mutator_t; 19 | 20 | uint8_t dummy[10] = {}; // dummy buffer 21 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/run_fuzz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | AFL_DISABLE_TRIM=1 \ 4 | AFL_CUSTOM_MUTATOR_ONLY=1 \ 5 | AFL_CUSTOM_MUTATOR_LIBRARY=$HOME/libprotobuf-mutator_fuzzing_learning/5_libprotobuf_aflpp_custom_mutator_input/lpm_aflpp_custom_mutator_input.so \ 6 | AFL_SKIP_CPUFREQ=1 \ 7 | $HOME/AFLplusplus/afl-fuzz -i ./in -o ./out ./vuln 8 | 9 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/test_proto_serializer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * A simple program to serialize TEST protobuf 3 | * This is useful for generating the input data for our cutomized mutator 4 | * 5 | * */ 6 | 7 | #include "test.pb.h" 8 | #include 9 | 10 | using std::cin; 11 | using std::cout; 12 | using std::endl; 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | TEST t; 17 | t.set_a(100); 18 | t.set_b("aaaa"); 19 | std::string s; 20 | t.SerializeToString(&s); 21 | 22 | std::ofstream out("./in/ii"); 23 | out << s; 24 | out.close(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /5_libprotobuf_aflpp_custom_mutator_input/vuln.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | char str[100]={}; 10 | read(0, str, 100); 11 | int *ptr = NULL; 12 | if( str[0] == '\x02' || str[0] == '\xe8') { 13 | *ptr = 123; 14 | } 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bruce Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libprotobuf-mutator_fuzzing_learning 2 | Learn how to combine libprotobuf-mutator with libfuzzer & AFL++ 3 | 4 | ## Environment Settings 5 | * Ubuntu Linux 22.04 64 bit 6 | * Clang 14.0.0 7 | * libprotobuf-mutator 3.21.7 [(af3bb1)](https://github.com/google/libprotobuf-mutator/tree/af3bb18749db3559dc4968dd85319d05168d4b5e) 8 | > [!IMPORTANT] 9 | > As of 2023/12/01, this repo won't work with the latest libprotobuf-mutator. It is recommended to switch to commit `af3bb1` before compile & installing the libraries ( [reference](https://github.com/google/libprotobuf-mutator/issues/223) ). 10 | * AFL++ 4.09a [(61e27c)](https://github.com/AFLplusplus/AFLplusplus/tree/61e27c6b54f7641a168b6acc6ecffb1754c10918) 11 | 12 | ### Install Clang/LLVM & libfuzzer 13 | * Follow the step in [this article](https://linuxhint.com/install-llvm-ubuntu/) and add the toolchain's apt repository in Ubuntu. 14 | * `sudo apt-get install clang-14 libfuzzer-14-dev` 15 | 16 | ### Install libprotobuf-mutator 17 | Follow the step in [libprotobuf-mutator's readme](https://github.com/google/libprotobuf-mutator/blob/master/README.md) 18 | 19 | #### Install dependencies 20 | ```shell 21 | sudo apt-get update 22 | sudo apt-get install protobuf-compiler libprotobuf-dev binutils cmake \ 23 | ninja-build liblzma-dev libz-dev pkg-config autoconf libtool 24 | ``` 25 | 26 | #### Build the required libraries 27 | 28 | ```shell 29 | cd libprotobuf-mutator 30 | mkdir build 31 | cd build 32 | ( A cmake command, check the below section ) 33 | ninja # build the libraries 34 | sudo ninja install # install the libraries ( optional ) 35 | ``` 36 | About `cmake` command : 37 | * Use the following cmake command to build `libprotobuf-mutator-libfuzzer.so.0` and `libprotobuf-mutator.so.0` shared library : 38 | 39 | ```shell 40 | cmake .. -GNinja -DCMAKE_C_COMPILER=clang-14 \ 41 | -DCMAKE_CXX_COMPILER=clang++-14 \ 42 | -DCMAKE_BUILD_TYPE=Debug \ 43 | -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ 44 | -DBUILD_SHARED_LIBS=ON 45 | ``` 46 | 47 | * To build static libraries ( `libprotobuf-mutator-libfuzzer.a` and `libprotobuf-mutator.a` ), use the following `cmake` command ( **this will generate libraries that can be linked into shared libraries / normal program** ) : 48 | 49 | ```shell 50 | cmake .. -GNinja -DCMAKE_C_COMPILER=clang-14 \ 51 | -DCMAKE_CXX_COMPILER=clang++-14 \ 52 | -DCMAKE_BUILD_TYPE=Debug \ 53 | -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ 54 | -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" 55 | ``` 56 | 57 | After building successfully, you can go to the `build` directory, and use the following command to check if the library is built correctly : 58 | ```shell 59 | # Check if libprotobuf-mutator.so.0 exist 60 | # To check other libraries just change the library name 61 | find . | grep "libprotobuf-mutator.so.0" 62 | ``` 63 | 64 | ## How to upgrade the environment 65 | * Upgrade Clang/LLVM & libfuzzer ( install a new version ) 66 | * Upgrade AFL++ ( git pull & rebuild ) 67 | * Upgrade libprotobuf-mutator ( git pull & rebuild ) 68 | - Rebuild and re-install `libprotobuf-mutator-libfuzzer.so.0` and `libprotobuf-mutator.so.0`. 69 | - Rebuild `libprotobuf-mutator-libfuzzer.a` and `libprotobuf-mutator.a`. 70 | * **Re-compile the protobuf with newer `protoc` and replace those `*.cc` & `*.h` with new ones.** 71 | 72 | ## FAQ 73 | Q : I ran into this error message while building the binary : `This file was generated by an old version of protoc.` 74 | A : If your protoc's version is newer, make sure to re-generate `test.pb.cc` and `test.pb.h` with the original protobuf source code `test.proto` ( source code and steps to generate `*.cc` & `*.h` are all in [1_simple_protobuf](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/1_simple_protobuf) ). 75 | 76 | ## Learning 77 | * [Simple protobuf example](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/1_simple_protobuf) 78 | * [libprotobuf + libfuzzer](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/2_libprotobuf_libfuzzer) 79 | * [libprotobuf + libfuzzer ( custom mutator )](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/3_libprotobuf_libfuzzer_custom_mutator) 80 | * [How to combine libprotobuf-mutator and AFL++](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator) 81 | * [Handling input samples from AFL++ in custom mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input) 82 | 83 | ## Reference 84 | * [libprotobuf-mutator](https://github.com/google/libprotobuf-mutator) 85 | * [Deconstructing LibProtobuf/Mutator Fuzzing](https://bshastry.github.io/2019/01/18/Deconstructing-LPM.html) 86 | * [Custom Proto Mutation](https://bshastry.github.io/2019/12/27/Custom-Proto-Mutation.html) 87 | * [AFL++ custom mutator](https://github.com/vanhauser-thc/AFLplusplus/blob/master/docs/custom_mutators.md) 88 | * [afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator/) 89 | * [Advanced binary fuzzing using AFL++-QEMU and libprotobuf: a practical case of grammar-aware in-memory persistent fuzzing](https://airbus-seclab.github.io/AFLplusplus-blogpost/) 90 | - [ref1](https://github.com/airbus-seclab/AFLplusplus-blogpost/blob/b0cfc7016bd60cf998969d79a78eabd8471c78eb/src/mutator/custom_mutator.cpp) 91 | - [ref2](https://github.com/HexHive/Igor/blob/2f22a20ff7e82f6022c99f0a47c69796e4fd999d/IgorFuzz/utils/custom_mutators/custom_mutator_helpers.h#L304) 92 | - [ref3](https://github.com/HexHive/Igor/blob/2f22a20ff7e82f6022c99f0a47c69796e4fd999d/IgorFuzz/custom_mutators/honggfuzz/custom_mutator_helpers.h) 93 | 94 | ## LICENSE 95 | MIT 96 | --------------------------------------------------------------------------------