diff options
7 files changed, 184 insertions, 0 deletions
diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp index 11690443..89abc3e9 100644 --- a/custom_mutators/Android.bp +++ b/custom_mutators/Android.bp @@ -109,3 +109,7 @@ cc_library_shared { "libafl_headers", ], } + +subdirs = [ + "libprotobuf-mutator-example", +] diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp new file mode 100644 index 00000000..01f1c23e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/Android.bp @@ -0,0 +1,32 @@ +cc_library_shared { + name: "libprotobuf-mutator-example-afl", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-fPIC", + "-Wall", + ], + + srcs: [ + "lpm_aflpp_custom_mutator_input.cc", + "test.proto", + ], + + shared_libs: [ + "libprotobuf-cpp-full", + "libprotobuf-mutator", + ], +} + +cc_binary { + name: "libprotobuf-mutator-vuln", + vendor_available: true, + host_supported: true, + + srcs: [ + "vuln.c", + ], +} diff --git a/custom_mutators/libprotobuf-mutator-example/README.md b/custom_mutators/libprotobuf-mutator-example/README.md new file mode 100644 index 00000000..5a844c00 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/README.md @@ -0,0 +1 @@ +Ported from [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input) diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc new file mode 100644 index 00000000..e0273849 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc @@ -0,0 +1,118 @@ +#include "lpm_aflpp_custom_mutator_input.h" +#include <iostream> +#include <sstream> +#include <fstream> + +using std::cin; +using std::cout; +using std::endl; + +std::string ProtoToData(const TEST &test_proto) { + std::stringstream all; + const auto &aa = test_proto.a(); + const auto &bb = test_proto.b(); + all.write((const char*)&aa, sizeof(aa)); + if(bb.size() != 0) { + all.write(bb.c_str(), bb.size()); + } + + std::string res = all.str(); + if (bb.size() != 0 && res.size() != 0) { + // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf + if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { + std::ofstream of(dump_path); + of.write(res.data(), res.size()); + } + } + return res; +} + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +extern "C" MyMutator *afl_custom_init(void *afl, unsigned int seed) { + MyMutator *mutator = new MyMutator(); + + mutator->RegisterPostProcessor( + TEST::descriptor(), + [](google::protobuf::Message* message, unsigned int seed) { + // libprotobuf-mutator's built-in mutator is kind of....crappy :P + // Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q + // We register a post processor to apply our dumb fuzz + + TEST *t = static_cast<TEST *>(message); + t->set_a(rand()); + }); + + srand(seed); + return mutator; +} + +/** + * Perform custom mutations on a given input + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +extern "C" size_t afl_custom_fuzz(MyMutator *mutator, // return value from afl_custom_init + uint8_t *buf, size_t buf_size, // input data to be mutated + uint8_t **out_buf, // output buffer + uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" + // A simple test shows that "buf" will be the content of the current test case + // "add_buf" will be the next test case ( from AFL++'s input queue ) + + TEST input; + // parse input data to TEST + // Notice that input data should be a serialized protobuf data + // Check ./in/ii and test_protobuf_serializer for more detail + bool parse_ok = input.ParseFromArray(buf, buf_size); + if(!parse_ok) { + // Invalid serialize protobuf data. Don't mutate. + // Return a dummy buffer. Also mutated_size = 0 + static uint8_t *dummy = new uint8_t[10]; // dummy buffer with no data + *out_buf = dummy; + return 0; + } + // mutate the protobuf + mutator->Mutate(&input, max_size); + + // Convert protobuf to raw data + const TEST *p = &input; + std::string s = ProtoToData(*p); + // Copy to a new buffer ( mutated_out ) + size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size + uint8_t *mutated_out = new uint8_t[mutated_size+1]; + memcpy(mutated_out, s.c_str(), mutated_size); // copy the mutated data + // Assign the mutated data and return mutated_size + *out_buf = mutated_out; + return mutated_size; +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +extern "C" void afl_custom_deinit(void *data) { + // Honestly I don't know what to do with this... + return; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h new file mode 100644 index 00000000..ebd3ca65 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h @@ -0,0 +1,5 @@ +#include <src/mutator.h> +#include "test.pb.h" + +class MyMutator : public protobuf_mutator::Mutator { +}; diff --git a/custom_mutators/libprotobuf-mutator-example/test.proto b/custom_mutators/libprotobuf-mutator-example/test.proto new file mode 100644 index 00000000..e2256c6e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/test.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message TEST { + required uint32 a = 1; + required string b = 2; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/vuln.c b/custom_mutators/libprotobuf-mutator-example/vuln.c new file mode 100644 index 00000000..8ffb7080 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/vuln.c @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + char str[100]={}; + read(0, str, 100); + int *ptr = NULL; + if( str[0] == '\x02' || str[0] == '\xe8') { + *ptr = 123; + } + return 0; +} + |