Untitled

mail@pastecode.io avatar
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);
}