Merge pull request #1767 from AFLplusplus/mutationnew

Mutationnew
This commit is contained in:
van Hauser 2023-06-12 10:16:45 +03:00 committed by GitHub
commit f1a616406e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 3312 additions and 364 deletions

View File

@ -0,0 +1,10 @@
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
all: aflpp-mutator.so
aflpp-mutator.so: aflpp.c
$(CC) $(CFLAGS) -I../../include -I. -shared -o aflpp-mutator.so aflpp.c ../../src/afl-performance.c
clean:
rm -f *.o *~ *.so core

View File

@ -0,0 +1,8 @@
# custum mutator: AFL++
this is the AFL++ havoc mutator as a custom mutator module for AFL++.
just type `make` to build
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/aflpp/aflpp-mutator.so afl-fuzz ...```

View File

@ -0,0 +1,89 @@
#include "afl-mutations.h"
typedef struct my_mutator {
afl_state_t *afl;
u8 *buf;
u32 buf_size;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)seed;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->buf = malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init alloc");
return NULL;
} else {
data->buf_size = MAX_FILE;
}
data->afl = afl;
return data;
}
/* here we run the AFL++ mutator, which is the best! */
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,
size_t max_size) {
if (max_size > data->buf_size) {
u8 *ptr = realloc(data->buf, max_size);
if (ptr) {
return 0;
} else {
data->buf = ptr;
data->buf_size = max_size;
}
}
u32 havoc_steps = 1 + rand_below(data->afl, 16);
/* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size);
/* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
false, true, add_buf, add_buf_size, max_size);
/* return size of mutated data */
*out_buf = data->buf;
return out_buf_len;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->buf);
free(data);
}

View File

@ -0,0 +1,10 @@
CFLAGS = -O3 -funroll-loops -fPIC
all: aflpp-standalone
aflpp-standalone: aflpp-standalone.c
$(CC) $(CFLAGS) -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c
clean:
rm -f *.o *~ aflpp-standalone core

View File

@ -0,0 +1,10 @@
# AFL++ standalone mutator
this is the AFL++ havoc mutator as a standalone mutator
just type `make` to build.
```
aflpp-standalone inputfile outputfile [splicefile]
```

View File

@ -0,0 +1,165 @@
#include "afl-mutations.h"
s8 interesting_8[] = {INTERESTING_8};
s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
typedef struct my_mutator {
afl_state_t *afl;
u8 *buf;
u32 buf_size;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)seed;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->buf = malloc(1024*1024)) == NULL) {
perror("afl_custom_init alloc");
return NULL;
} else {
data->buf_size = 1024*1024;
}
/* fake AFL++ state */
data->afl = calloc(1, sizeof(afl_state_t));
data->afl->queue_cycle = 1;
data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
rand_set_seed(data->afl, getpid());
return data;
}
/* here we run the AFL++ mutator, which is the best! */
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,
size_t max_size) {
if (max_size > data->buf_size) {
u8 *ptr = realloc(data->buf, max_size);
if (ptr) {
return 0;
} else {
data->buf = ptr;
data->buf_size = max_size;
}
}
u32 havoc_steps = 1 + rand_below(data->afl, 16);
/* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size);
/* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
false, true, add_buf, add_buf_size, max_size);
/* return size of mutated data */
*out_buf = data->buf;
return out_buf_len;
}
int main(int argc, char *argv[]) {
if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
printf("Syntax: %s [-v] [inputfile [outputfile [splicefile]]]\n\n", argv[0]);
printf("Reads a testcase from stdin when no input file (or '-') is specified,\n");
printf("mutates according to AFL++'s mutation engine, and write to stdout when '-' or\n");
printf("no output filename is given. As an optional third parameter you can give a file\n");
printf("for splicing. Maximum input and output length is 1MB.\n");
printf("The -v verbose option prints debug output to stderr.\n");
return 0;
}
FILE *in = stdin, *out = stdout, *splice = NULL;
unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL;
int verbose = 0, splicelen = 0;
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
verbose = 1;
argc--;
argv++;
fprintf(stderr, "Verbose active\n");
}
my_mutator_t *data = afl_custom_init(NULL, 0);
if (argc > 1 && strcmp(argv[1], "-") != 0) {
if ((in = fopen(argv[1], "r")) == NULL) {
perror(argv[1]);
return -1;
}
if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
}
size_t inlen = fread(inbuf, 1, 1024*1024, in);
if (!inlen) {
fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
return -1;
}
if (argc > 2 && strcmp(argv[2], "-") != 0) {
if ((out = fopen(argv[2], "w")) == NULL) {
perror(argv[2]);
return -1;
}
if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
}
if (argc > 3) {
if ((splice = fopen(argv[3], "r")) == NULL) {
perror(argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
splicebuf = malloc(1024*1024);
size_t splicelen = fread(splicebuf, 1, 1024*1024, splice);
if (!splicelen) {
fprintf(stderr, "Error: empty file %s\n", argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
}
if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf, splicelen, 1024*1024);
if (outlen == 0 || !outbuf) {
fprintf(stderr, "Error: no mutation data returned.\n");
return -1;
}
if (verbose) fprintf(stderr, "Mutation output length: %zu\n", outlen);
if (fwrite(outbuf, 1, outlen, out) != outlen) {
fprintf(stderr, "Warning: incomplete write.\n");
return -1;
}
return 0;
}

View File

@ -494,7 +494,8 @@ typedef struct afl_state {
*orig_cmdline, /* Original command line */
*infoexec; /* Command to execute on a new crash */
u32 hang_tmout; /* Timeout used for hang det (ms) */
u32 hang_tmout, /* Timeout used for hang det (ms) */
stats_update_freq; /* Stats update frequency (execs) */
u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */
no_unlink, /* do not unlink cur_input */
@ -503,40 +504,37 @@ typedef struct afl_state {
custom_splice_optout, /* Custom mutator no splice buffer */
is_main_node, /* if this is the main node */
is_secondary_node, /* if this is a secondary instance */
pizza_is_served; /* pizza mode */
u32 stats_update_freq; /* Stats update frequency (execs) */
u8 schedule; /* Power schedule (default: EXPLORE)*/
u8 havoc_max_mult;
u8 skip_deterministic, /* Skip deterministic stages? */
use_splicing, /* Recombine input files? */
non_instrumented_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */
resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */
term_too_small, /* terminal dimensions too small */
no_forkserver, /* Disable forkserver? */
crash_mode, /* Crash mode! Yeah! */
in_place_resume, /* Attempt in-place resume? */
autoresume, /* Resume if afl->out_dir exists? */
auto_changed, /* Auto-generated tokens changed? */
no_cpu_meter_red, /* Feng shui on the status screen */
no_arith, /* Skip most arithmetic ops */
shuffle_queue, /* Shuffle input queue? */
bitmap_changed, /* Time to update bitmap? */
unicorn_mode, /* Running in Unicorn mode? */
use_wine, /* Use WINE with QEMU mode */
skip_requested, /* Skip request, via SIGUSR1 */
run_over10m, /* Run time over 10 minutes? */
persistent_mode, /* Running in persistent mode? */
deferred_mode, /* Deferred forkserver mode? */
fixed_seed, /* do not reseed */
fast_cal, /* Try to calibrate faster? */
disable_trim, /* Never trim in fuzz_one */
shmem_testcase_mode, /* If sharedmem testcases are used */
pizza_is_served, /* pizza mode */
text_input, /* target wants text inputs */
fuzz_mode, /* current mode: coverage/exploration or crash/exploitation */
schedule, /* Power schedule (default: EXPLORE)*/
havoc_max_mult, skip_deterministic, /* Skip deterministic stages? */
use_splicing, /* Recombine input files? */
non_instrumented_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */
resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */
term_too_small, /* terminal dimensions too small */
no_forkserver, /* Disable forkserver? */
crash_mode, /* Crash mode! Yeah! */
in_place_resume, /* Attempt in-place resume? */
autoresume, /* Resume if afl->out_dir exists? */
auto_changed, /* Auto-generated tokens changed? */
no_cpu_meter_red, /* Feng shui on the status screen */
no_arith, /* Skip most arithmetic ops */
shuffle_queue, /* Shuffle input queue? */
bitmap_changed, /* Time to update bitmap? */
unicorn_mode, /* Running in Unicorn mode? */
use_wine, /* Use WINE with QEMU mode */
skip_requested, /* Skip request, via SIGUSR1 */
run_over10m, /* Run time over 10 minutes? */
persistent_mode, /* Running in persistent mode? */
deferred_mode, /* Deferred forkserver mode? */
fixed_seed, /* do not reseed */
fast_cal, /* Try to calibrate faster? */
disable_trim, /* Never trim in fuzz_one */
shmem_testcase_mode, /* If sharedmem testcases are used */
expand_havoc, /* perform expensive havoc after no find */
cycle_schedules, /* cycle power schedules? */
old_seed_selection, /* use vanilla afl seed selection */
@ -597,7 +595,8 @@ typedef struct afl_state {
last_hang_time, /* Time for most recent hang (ms) */
longest_find_time, /* Longest time taken for a find */
exit_on_time, /* Delay to exit if no new paths */
sync_time; /* Sync time (ms) */
sync_time, /* Sync time (ms) */
switch_fuzz_mode; /* auto or fixed fuzz mode */
u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
subseq_tmouts; /* Number of timeouts in a row */
@ -1203,6 +1202,7 @@ u8 check_if_text_buf(u8 *buf, u32 len);
#ifndef AFL_SHOWMAP
void setup_signal_handlers(void);
#endif
char *get_fuzzing_state(afl_state_t *afl);
/* CmpLog */

2202
include/afl-mutations.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,12 @@
Default: 8MB (defined in bytes) */
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
/* Default time until when no more coverage finds are happening afl-fuzz
switches to exploitation mode. It automatically switches back when new
coverage is found.
Default: 300 (seconds) */
#define STRATEGY_SWITCH_TIME 600
/* Default file permission umode when creating files (default: 0600) */
#define DEFAULT_PERMISSION 0600

View File

@ -533,6 +533,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
close(fd);
add_to_queue(afl, queue_fn, len, 0);
if (unlikely(afl->fuzz_mode) && likely(afl->switch_fuzz_mode)) {
if (afl->afl_env.afl_no_ui) {
ACTF("New coverage found, switching back to exploration mode.");
}
afl->fuzz_mode = 0;
}
#ifdef INTROSPECTION
if (afl->custom_mutators_count && afl->current_custom_fuzz) {

File diff suppressed because it is too large Load Diff

View File

@ -612,7 +612,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
if (likely(q->len > 4)) afl->ready_for_splicing_count++;
if (likely(q->len > 4)) { ++afl->ready_for_splicing_count; }
++afl->queued_items;
++afl->active_items;

View File

@ -108,6 +108,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->cmplog_lvl = 2;
afl->min_length = 1;
afl->max_length = MAX_FILE;
afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000;
#ifndef NO_SPLICING
afl->use_splicing = 1;
#endif

View File

@ -27,6 +27,45 @@
#include "envs.h"
#include <limits.h>
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};
char *get_fuzzing_state(afl_state_t *afl) {
u64 cur_ms = get_cur_time();
u64 last_find = cur_ms - afl->last_find_time;
u64 cur_run_time = cur_ms - afl->start_time;
u64 cur_total_run_time = afl->prev_run_time + cur_run_time;
if (unlikely(cur_run_time < 60 * 3 * 1000 ||
cur_total_run_time < 60 * 5 * 1000)) {
return fuzzing_state[0];
} else {
u64 last_find_100 = 100 * last_find;
u64 percent_cur = last_find_100 / cur_run_time;
u64 percent_total = last_find_100 / cur_total_run_time;
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
return fuzzing_state[3];
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
return fuzzing_state[2];
} else {
return fuzzing_state[1];
}
}
}
/* Write fuzzer setup file */
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
@ -1282,7 +1321,11 @@ void show_stats_normal(afl_state_t *afl) {
}
/* Last line */
SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1);
SAYF(SET_G1 "\n" bSTG bLB bH cCYA bSTOP " strategy:" cPIN
" %s " bSTG bH10 cCYA bSTOP " state:" cPIN
" %s " bSTG bH2 bRB bSTOP cRST RESET_G1,
afl->fuzz_mode == 0 ? "explore" : "exploit", get_fuzzing_state(afl));
#undef IB

View File

@ -129,6 +129,13 @@ static void usage(u8 *argv0, int more_help) {
" -o dir - output directory for fuzzer findings\n\n"
"Execution control settings:\n"
" -P strategy - set fix mutation strategy: explore (focus on new "
"coverage),\n"
" exploit (focus on triggering crashes). You can also "
"set a\n"
" number of seconds after without any finds it switches "
"to\n"
" exploit mode, and back on new coverage (default: %u)\n"
" -p schedule - power schedules compute a seed's performance score:\n"
" fast(default), explore, exploit, seek, rare, mmopt, "
"coe, lin\n"
@ -157,6 +164,7 @@ static void usage(u8 *argv0, int more_help) {
"\n"
"Mutator settings:\n"
" -a - target expects ascii text input\n"
" -g minlength - set min length of generated fuzz input (default: 1)\n"
" -G maxlength - set max length of generated fuzz input (default: "
"%lu)\n"
@ -212,7 +220,8 @@ static void usage(u8 *argv0, int more_help) {
" -e ext - file extension for the fuzz test input file (if "
"needed)\n"
"\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
argv0, STRATEGY_SWITCH_TIME, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE,
FOREIGN_SYNCS_MAX);
if (more_help > 1) {
@ -494,14 +503,48 @@ int main(int argc, char **argv_orig, char **envp) {
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
while (
(opt = getopt(
argc, argv,
"+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) >
0) {
// still available: HjJkKqruvwz
while ((opt = getopt(argc, argv,
"+aAb:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
"T:UV:WXx:YZ")) > 0) {
switch (opt) {
case 'a':
afl->text_input = 1;
break;
case 'P':
if (!stricmp(optarg, "explore") || !stricmp(optarg, "exploration")) {
afl->fuzz_mode = 0;
afl->switch_fuzz_mode = 0;
} else if (!stricmp(optarg, "exploit") ||
!stricmp(optarg, "exploitation")) {
afl->fuzz_mode = 1;
afl->switch_fuzz_mode = 0;
} else {
if ((afl->switch_fuzz_mode = (u32)atoi(optarg)) > INT_MAX) {
FATAL(
"Parameter for option -P must be \"explore\", \"exploit\" or a "
"number!");
} else {
afl->switch_fuzz_mode *= 1000;
}
}
break;
case 'g':
afl->min_length = atoi(optarg);
break;
@ -2688,13 +2731,31 @@ int main(int argc, char **argv_orig, char **envp) {
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
u64 cur_time = get_cur_time();
if (likely(afl->switch_fuzz_mode && afl->fuzz_mode == 0) &&
unlikely(cur_time > afl->last_find_time + afl->switch_fuzz_mode)) {
if (afl->afl_env.afl_no_ui) {
ACTF(
"No new coverage found for %llu seconds, switching to exploitation "
"strategy.",
afl->switch_fuzz_mode / 1000);
}
afl->fuzz_mode = 1;
}
if (likely(!afl->stop_soon && afl->sync_id)) {
if (likely(afl->skip_deterministic)) {
if (unlikely(afl->is_main_node)) {
if (unlikely(get_cur_time() >
if (unlikely(cur_time >
(afl->sync_time >> 1) + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
@ -2707,7 +2768,7 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
if (unlikely(get_cur_time() > afl->sync_time + afl->last_sync_time)) {
if (unlikely(cur_time > afl->sync_time + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }