android: Add libprotobuf aflpp custom_mutator example
MODIFY
custom_mutators/Android.bp
custom_mutators/Android.bp
@@ -109,3 +109,7 @@ cc_library_shared {
"libafl_headers",
],
}
+
+subdirs = [
+ "libprotobuf-mutator-example",
+]

ADD
custom_mutators/libprotobuf-mutator-example/Android.bp
+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",
+ ],
+}

ADD
custom_mutators/libprotobuf-mutator-example/README.md
+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)

ADD
custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc
+#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;
+}
+

ADD
custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h
+#include <src/mutator.h>
+#include "test.pb.h"
+
+class MyMutator : public protobuf_mutator::Mutator {
+};

ADD
custom_mutators/libprotobuf-mutator-example/test.proto
+syntax = "proto2";
+
+message TEST {
+ required uint32 a = 1;
+ required string b = 2;
+}
+

ADD
custom_mutators/libprotobuf-mutator-example/vuln.c
+#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;
+}
+

android: Add libprotobuf aflpp custom_mutator example