Untitled
unknown
plain_text
a year ago
12 kB
4
Indexable
Never
/* New Custom Mutator for AFL++ Written by Khaled Yakdan <yakdan@code-intelligence.de> Andrea Fioraldi <andreafioraldi@gmail.com> Shengtuo Hu <h1994st@gmail.com> Dominik Maier <mail@dmnk.co> */ // You need to use -I /path/to/AFLplusplus/include #include "custom_mutator_helpers.h" #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <stdbool.h> #define DATA_SIZE (100) #define NCOMMAND 50 #define LENCOMMAND 128 char commands[NCOMMAND][LENCOMMAND]; bool debug = false; int counter = 0; int n_commands = 0; typedef struct my_mutator { afl_t *afl; // any additional data here! size_t trim_size_current; int trimmming_steps; int cur_step; // Reused buffers: BUF_VAR(u8, fuzz); BUF_VAR(u8, data); BUF_VAR(u8, havoc); BUF_VAR(u8, trim); BUF_VAR(u8, post_process); } my_mutator_t; bool read_file() { char fname[200]; FILE *fptr = NULL; int i = 0; int tot = 0; fptr = fopen("./traces.txt", "r"); if (!fptr) { printf("Make sure the file traces.txt is in the correct folder!"); return 0; } while (fgets(commands[i], LENCOMMAND, fptr)) { commands[i][strlen(commands[i]) - 1] = '\0'; i++; } n_commands = i; printf("[LOG] Commands read"); return 1; } /** * 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. */ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { srand(seed); // needed also by surgical_havoc_mutate() my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); if (!data) { perror("afl_custom_init alloc"); return NULL; } data->afl = afl; printf("[LOG] I'm here!"); if (!read_file()) { perror("afl_custom_init alloc"); return NULL; } return data; } /** * Perform custom mutations on a given input * * (Optional for now. Required in the future) * * @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. */ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL size_t max_size) { // Make sure that the packet size does not exceed the maximum size expected by // the fuzzer size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; // maybe_grow is optimized to be quick for reused buffers. u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); if (!mutated_out) { *out_buf = NULL; perror("custom mutator allocation (maybe_grow)"); return 0; /* afl-fuzz will very likely error out after this. */ } if (debug == true) { // printf("Counter: %d Message: %s Len:%d\n",counter, printf("Before %s-\n", mutated_out); } // Randomly select a command string to add as a header to the packet // printf("N_COMMANDS: %d", n_commands); char *to_send = commands[rand() % n_commands]; int len_command = strlen(to_send); memcpy(mutated_out, to_send, len_command); // printf("Important %d",mutated_size); // // Mutate the payload of the packet int i; for (i = 0; i < 8; ++i) { // Randomly perform a mutation on the entire packet surgical_havoc_mutate(mutated_out, 0, mutated_size); } mutated_out = strcat(mutated_out, "\n\0"); *out_buf = mutated_out; if (debug == true) { printf("After %s\n", out_buf); } return strlen(mutated_out); } /** * A post-processing function to use right before AFL writes the test case to * disk in order to execute the target. * * (Optional) If this functionality is not needed, simply don't define this * function. * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Buffer containing the test case to be executed * @param[in] buf_size Size of the test case * @param[out] out_buf Pointer to the buffer containing the test case after * processing. External library should allocate memory for out_buf. * The buf pointer may be reused (up to the given buf_size); * @return Size of the output buffer after processing or the needed amount. * A return of 0 indicates an error. */ // size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, // size_t buf_size, uint8_t **out_buf) { // uint8_t *post_process_buf = // maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); // if (!post_process_buf) { // perror("custom mutator realloc failed."); // *out_buf = NULL; // return 0; // } // memcpy(post_process_buf + 5, buf, buf_size); // post_process_buf[0] = 'A'; // post_process_buf[1] = 'F'; // post_process_buf[2] = 'L'; // post_process_buf[3] = '+'; // post_process_buf[4] = '+'; // *out_buf = post_process_buf; // return buf_size + 5; // } /** * This method is called at the start of each trimming operation and receives * the initial buffer. It should return the amount of iteration steps possible * on this input (e.g. if your input has n elements and you want to remove * them one by one, return n, if you do a binary search, return log(n), * and so on...). * * If your trimming algorithm doesn't allow you to determine the amount of * (remaining) steps easily (esp. while running), then you can alternatively * return 1 here and always return 0 in post_trim until you are finished and * no steps remain. In that case, returning 1 in post_trim will end the * trimming routine. The whole current index/max iterations stuff is only used * to show progress. * * (Optional) * * @param data pointer returned in afl_custom_init for this fuzz case * @param buf Buffer containing the test case * @param buf_size Size of the test case * @return The amount of possible iteration steps to trim the input. * negative on error. */ // int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, // size_t buf_size) { // // We simply trim once // data->trimmming_steps = 1; // data->cur_step = 0; // if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { // perror("init_trim grow"); // return -1; // } // memcpy(data->trim_buf, buf, buf_size); // data->trim_size_current = buf_size; // return data->trimmming_steps; // } /** * This method is called for each trimming operation. It doesn't have any * arguments because we already have the initial buffer from init_trim and we * can memorize the current state in *data. This can also save * reparsing steps for each iteration. It should return the trimmed input * buffer, where the returned data must not exceed the initial input data in * length. Returning anything that is larger than the original data (passed * to init_trim) will result in a fatal abort of AFLFuzz. * * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[out] out_buf Pointer to the buffer containing the trimmed test case. * External library should allocate memory for out_buf. * AFL++ will not release the memory after saving the test case. * Keep a ref in *data. * *out_buf = NULL is treated as error. * @return Pointer to the size of the trimmed test case */ // size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { // *out_buf = data->trim_buf; // // Remove the last byte of the trimming input // return data->trim_size_current - 1; // } /** * This method is called after each trim operation to inform you if your * trimming step was successful or not (in terms of coverage). If you receive * a failure here, you should reset your input to the last known good state. * * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param success Indicates if the last trim operation was successful. * @return The next trim iteration index (from 0 to the maximum amount of * steps returned in init_trim). negative ret on failure. */ // int32_t afl_custom_post_trim(my_mutator_t *data, int success) { // if (success) { // ++data->cur_step; // return data->cur_step; // } // return data->trimmming_steps; // } /** * Perform a single custom mutation on a given input. * This mutation is stacked with the other muatations in havoc. * * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of input data * @param[out] out_buf The output buffer. buf can be reused, if the content * fits. *out_buf = NULL is treated as error. * @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. */ // size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t // buf_size, // u8 **out_buf, size_t max_size) { // if (buf_size == 0) { // *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); // if (!*out_buf) { // perror("custom havoc: maybe_grow"); // return 0; // } // **out_buf = rand() % 256; // buf_size = 1; // } else { // // We reuse buf here. It's legal and faster. // *out_buf = buf; // } // size_t victim = rand() % buf_size; // (*out_buf)[victim] += rand() % 10; // return buf_size; // } /** * Return the probability (in percentage) that afl_custom_havoc_mutation * is called in havoc. By default it is 6 %. * * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @return The probability (0-100). */ uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { return 5; // 5 % } /** * Determine whether the fuzzer should fuzz the queue entry or not. * * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param filename File name of the test case in the queue entry * @return Return True(1) if the fuzzer will fuzz the queue entry, and * False(0) otherwise. */ uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { return 1; } /** * Allow for additional analysis (e.g. calling a different tool that does a * different kind of coverage and saves this for the custom mutator). * * (Optional) * * @param data pointer returned in afl_custom_init for this fuzz case * @param filename_new_queue File name of the new queue entry * @param filename_orig_queue File name of the original queue entry * @return if the file contents was modified return 1 (True), 0 (False) * otherwise */ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue) { /* Additional analysis on the original or new test case */ return 0; } /** * Deinitialize everything * * @param data The data ptr from afl_custom_init */ void afl_custom_deinit(my_mutator_t *data) { free(data->post_process_buf); free(data->havoc_buf); free(data->data_buf); free(data->fuzz_buf); free(data->trim_buf); free(data); }