From b29d91edf5fb600c5daf5d61634c8719147d591c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Aug 2020 11:17:05 +0200 Subject: add stub directory --- qemu_taint/README.md | 36 ++++++++++++++++++++++++++++++++++++ qemu_taint/build.sh | 6 ++++++ qemu_taint/clean.sh | 3 +++ 3 files changed, 45 insertions(+) create mode 100644 qemu_taint/README.md create mode 100755 qemu_taint/build.sh create mode 100755 qemu_taint/clean.sh (limited to 'qemu_taint') diff --git a/qemu_taint/README.md b/qemu_taint/README.md new file mode 100644 index 00000000..e78e918d --- /dev/null +++ b/qemu_taint/README.md @@ -0,0 +1,36 @@ +# qemu_taint +First level taint implementation with qemu for linux user mode + +**THIS IS NOT WORKING YET** **WIP** + +## What is this for +On new queue entries (newly discovered paths into the target) this tainter +is run with the new input and the data gathered which bytes in the input +file are actually touched. + +Only touched bytes are then fuzzed by afl-fuzz + +## How to build +./build_qemu_taint.sh + +## How to use +Add the -T flag to afl-fuzz + +## Caveats +For some targets this is amazing and improves fuzzing a lot, but if a target +copies all input bytes first (e.g. for creating a crc checksum or just to +safely work with the data), then this is not helping at all. + +## Future +Two fuzz modes for a queue entry which will be switched back and forth: + + 1. fuzz all touched bytes + 2. fuzz only bytes that are newly touched (compared to the one this queue + entry is based on) + +## TODO + + * Direct trim: trim to highest touched byte, that is all we need to do + * add 5-25% dummy bytes to the queue entries? (maybe create a 2nd one?) + * Disable trim? + diff --git a/qemu_taint/build.sh b/qemu_taint/build.sh new file mode 100755 index 00000000..c3fbe198 --- /dev/null +++ b/qemu_taint/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 +cd qemu || exit 1 +test -d .git || { git stash ; git pull ; } +./build.sh +cp -f ./afl-qemu-taint ../.. diff --git a/qemu_taint/clean.sh b/qemu_taint/clean.sh new file mode 100755 index 00000000..0046c6c0 --- /dev/null +++ b/qemu_taint/clean.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -f afl-qemu-taint +test -d qemu && rm -f qemu -- cgit 1.4.1 From a19b31bf826c4d501ceb871824e12ad75ce64446 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Aug 2020 12:53:39 +0200 Subject: cp inc --- qemu_taint/build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qemu_taint') diff --git a/qemu_taint/build.sh b/qemu_taint/build.sh index c3fbe198..cf6e7236 100755 --- a/qemu_taint/build.sh +++ b/qemu_taint/build.sh @@ -2,5 +2,6 @@ test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 cd qemu || exit 1 test -d .git || { git stash ; git pull ; } +cp -fv ../../include/config.h . ./build.sh -cp -f ./afl-qemu-taint ../.. +cp -fv ./afl-qemu-taint ../.. -- cgit 1.4.1 From ebc6f528683c47b92ab08b469fc0b235ecce1062 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Aug 2020 12:55:35 +0200 Subject: cp inc --- qemu_taint/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qemu_taint') diff --git a/qemu_taint/build.sh b/qemu_taint/build.sh index cf6e7236..461ead68 100755 --- a/qemu_taint/build.sh +++ b/qemu_taint/build.sh @@ -2,6 +2,6 @@ test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 cd qemu || exit 1 test -d .git || { git stash ; git pull ; } -cp -fv ../../include/config.h . +cp -fv ../../include/config.h ../../include/types.h . ./build.sh cp -fv ./afl-qemu-taint ../.. -- cgit 1.4.1 From d8f5502d83ec530bcc1ad15b2d23b2660cd6ce58 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Aug 2020 20:29:56 +0200 Subject: initial integration --- GNUmakefile | 3 +++ include/envs.h | 1 + qemu_taint/README.md | 6 ++++++ qemu_taint/build.sh | 7 ------- qemu_taint/build_qemu_taint.sh | 7 +++++++ qemu_taint/clean.sh | 4 ++-- 6 files changed, 19 insertions(+), 9 deletions(-) delete mode 100755 qemu_taint/build.sh create mode 100755 qemu_taint/build_qemu_taint.sh (limited to 'qemu_taint') diff --git a/GNUmakefile b/GNUmakefile index 4a0fcdb6..9b064eb6 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -513,6 +513,7 @@ clean: $(MAKE) -C examples/argv_fuzzing clean $(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/libcompcov clean + test -d qemu_taint/qemu && { cd qemu_taint ; ./clean.sh ; } rm -rf qemu_mode/qemu-3.1.1 ifeq "$(IN_REPO)" "1" test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true @@ -523,6 +524,7 @@ endif deepclean: clean rm -rf qemu_mode/qemu-3.1.1.tar.xz + rm -rf qemu_taint/qemu rm -rf unicorn_mode/unicornafl git reset --hard >/dev/null 2>&1 || true @@ -580,6 +582,7 @@ install: all $(MANPAGES) install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH) rm -f $${DESTDIR}$(BIN_PATH)/afl-as if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi + if [ -f afl-qemu-taint ]; then install -m 755 afl-qemu-taint $${DESTDIR}$(BIN_PATH); fi if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/include/envs.h b/include/envs.h index 96ae91ba..bd97b9cd 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,6 +123,7 @@ static char *afl_environment_variables[] = { "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", "AFL_SKIP_CRASHES", + "AFL_TAINT_INPUT", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/qemu_taint/README.md b/qemu_taint/README.md index e78e918d..c842da0e 100644 --- a/qemu_taint/README.md +++ b/qemu_taint/README.md @@ -1,9 +1,11 @@ # qemu_taint + First level taint implementation with qemu for linux user mode **THIS IS NOT WORKING YET** **WIP** ## What is this for + On new queue entries (newly discovered paths into the target) this tainter is run with the new input and the data gathered which bytes in the input file are actually touched. @@ -11,17 +13,21 @@ file are actually touched. Only touched bytes are then fuzzed by afl-fuzz ## How to build + ./build_qemu_taint.sh ## How to use + Add the -T flag to afl-fuzz ## Caveats + For some targets this is amazing and improves fuzzing a lot, but if a target copies all input bytes first (e.g. for creating a crc checksum or just to safely work with the data), then this is not helping at all. ## Future + Two fuzz modes for a queue entry which will be switched back and forth: 1. fuzz all touched bytes diff --git a/qemu_taint/build.sh b/qemu_taint/build.sh deleted file mode 100755 index 461ead68..00000000 --- a/qemu_taint/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 -cd qemu || exit 1 -test -d .git || { git stash ; git pull ; } -cp -fv ../../include/config.h ../../include/types.h . -./build.sh -cp -fv ./afl-qemu-taint ../.. diff --git a/qemu_taint/build_qemu_taint.sh b/qemu_taint/build_qemu_taint.sh new file mode 100755 index 00000000..b54c3e04 --- /dev/null +++ b/qemu_taint/build_qemu_taint.sh @@ -0,0 +1,7 @@ +#!/bin/bash +test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 +cd qemu || exit 1 +test -d .git && { git stash ; git pull ; } +cp -fv ../../include/config.h ../../include/types.h . || exit 1 +./build.sh || exit 1 +cp -fv ./afl-qemu-taint ../.. diff --git a/qemu_taint/clean.sh b/qemu_taint/clean.sh index 0046c6c0..10c44cac 100755 --- a/qemu_taint/clean.sh +++ b/qemu_taint/clean.sh @@ -1,3 +1,3 @@ #!/bin/sh -rm -f afl-qemu-taint -test -d qemu && rm -f qemu +rm -f afl-qemu-taint qemu/afl-qemu-taint ../afl-qemu-taint +test -d qemu && { cd qemu ; ./clean.sh ; } -- cgit 1.4.1 From e4a0237cbc745552a5b21a2450d7ab55ee98759d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 00:35:12 +0200 Subject: step 1 --- GNUmakefile | 2 +- include/afl-fuzz.h | 6 ++++++ include/forkserver.h | 2 ++ qemu_taint/README.md | 2 +- src/afl-common.c | 1 + src/afl-forkserver.c | 15 +++++++++++++-- src/afl-fuzz-bitmap.c | 32 ++++++++++++++++++++++++++++++++ src/afl-fuzz-run.c | 13 +++++++++++++ src/afl-fuzz.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 9 files changed, 116 insertions(+), 8 deletions(-) (limited to 'qemu_taint') diff --git a/GNUmakefile b/GNUmakefile index 9b064eb6..4d0c434e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -98,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64" endif CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) -override CFLAGS += -Wall -Wextra -Werror -g -Wno-pointer-sign \ +override CFLAGS += -g -Wno-pointer-sign \ -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index bb1bb314..eb7f8ca5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -371,6 +371,8 @@ typedef struct afl_state { afl_env_vars_t afl_env; char **argv; /* argv if needed */ + + char **argv_taint; /* argv for taint mode */ /* MOpt: Lots of globals, but mostly for the status UI and other things where it @@ -581,6 +583,9 @@ typedef struct afl_state { char * cmplog_binary; afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ + /* Taint mode */ + afl_forkserver_t taint_fsrv; /* taint mode has its own little forkserver */ + /* Custom mutators */ struct custom_mutator *mutator; @@ -889,6 +894,7 @@ u32 calculate_score(afl_state_t *, struct queue_entry *); void write_bitmap(afl_state_t *); u32 count_bits(afl_state_t *, u8 *); +u32 count_bits_len(afl_state_t *, u8 *, u32); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 diff --git a/include/forkserver.h b/include/forkserver.h index 717493db..a5fca30e 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ u8 qemu_mode; /* if running in qemu mode or not */ + + u8 taint_mode; /* if running taint analysis or not */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */ diff --git a/qemu_taint/README.md b/qemu_taint/README.md index c842da0e..6a7d19af 100644 --- a/qemu_taint/README.md +++ b/qemu_taint/README.md @@ -18,7 +18,7 @@ Only touched bytes are then fuzzed by afl-fuzz ## How to use -Add the -T flag to afl-fuzz +Add the -A flag to afl-fuzz ## Caveats diff --git a/src/afl-common.c b/src/afl-common.c index 367dec72..134d3180 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -138,6 +138,7 @@ void argv_cpy_free(char **argv) { } + /* Rewrite argv for QEMU. */ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 752641d7..b4f92e5b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -481,6 +481,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 0); +fprintf(stderr, "init %p\n", fsrv->init_child_func); fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -496,10 +497,20 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, char pid_buf[16]; sprintf(pid_buf, "%d", fsrv->fsrv_pid); - if (fsrv->cmplog_binary) + + if (fsrv->qemu_mode == 2) { + + setenv("__AFL_TARGET_PID3", pid_buf, 1); + + } else if (fsrv->cmplog_binary) { + setenv("__AFL_TARGET_PID2", pid_buf, 1); - else + + } else { + setenv("__AFL_TARGET_PID1", pid_buf, 1); + + } /* Close the unneeded endpoints. */ diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index aa8d5a18..9cb1b83f 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -177,6 +177,38 @@ u32 count_bits(afl_state_t *afl, u8 *mem) { } +u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) { + + u32 *ptr = (u32 *)mem; + u32 i = (len >> 2); + u32 ret = 0; + + if (len % 4) i++; + + while (i--) { + + u32 v = *(ptr++); + + /* This gets called on the inverse, virgin bitmap; optimize for sparse + data. */ + + if (v == 0xffffffff) { + + ret += 32; + continue; + + } + + v -= ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24; + + } + + return ret; + +} + /* Count the number of bytes set in the bitmap. Called fairly sporadically, mostly to update the status screen or calibrate and examine confirmed new paths. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 8d652155..207b3046 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -471,6 +471,19 @@ abort_calibration: afl->stage_cur = old_sc; afl->stage_max = old_sm; + /* if taint mode was selected, run the taint */ + + if (afl->fsrv.taint_mode) { + write_to_testcase(afl, use_mem, q->len); + if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == 0) { + u32 len = q->len / 8; + if (q->len % 8) len++; + u32 bits = count_bits_len(afl, afl->taint_fsrv.trace_bits, len); + if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bits); + + } + } + if (!first_run) { show_stats(afl); } return fault; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 031c4049..bc780b55 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -53,6 +53,9 @@ static void at_exit() { ptr = getenv("__AFL_TARGET_PID2"); if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); + ptr = getenv("__AFL_TARGET_PID3"); + if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); + i = 0; while (list[i] != NULL) { @@ -89,6 +92,7 @@ static void usage(u8 *argv0, int more_help) { " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" + " -A - use first level taint analysis (see qemu_taint/README.md)\n" " -p schedule - power schedules compute a seed's performance score. " " 0) { + "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) { switch (opt) { + case 'A': + afl->fsrv.taint_mode = 1; + if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; } + break; + case 'I': afl->infoexec = optarg; break; @@ -485,7 +494,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!optarg) { FATAL("Wrong usage of -m"); } - if (!strcmp(optarg, "none")) { + if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) { afl->fsrv.mem_limit = 0; break; @@ -815,6 +824,14 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->fsrv.taint_mode && afl->fsrv.map_size < (MAX_FILE / 8) + 1) { + + afl->shm.map_size = (MAX_FILE / 8); + if (MAX_FILE % 8) afl->shm.map_size++; + afl->fsrv.map_size = afl->shm.map_size; + + } + if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " @@ -869,6 +886,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); } + if (afl->fsrv.taint_mode) { FATAL("-A and -n are mutually exclusive"); } } @@ -969,7 +987,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_preload) { - if (afl->fsrv.qemu_mode) { + if (afl->fsrv.qemu_mode || afl->fsrv.taint_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -1220,7 +1238,6 @@ int main(int argc, char **argv_orig, char **envp) { ACTF("Spawning cmplog forkserver"); afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv); - // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; @@ -1230,6 +1247,29 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Cmplog forkserver successfully started"); } + + if (afl->fsrv.taint_mode) { + + ACTF("Spawning qemu_taint forkserver"); + afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv); + afl->taint_fsrv.qemu_mode = 2; + afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; + ck_free(afl->taint_fsrv.target_path); + afl->taint_fsrv.target_path = ck_strdup(afl->fsrv.target_path); + afl->argv_taint = get_qemu_argv(argv[0], &afl->taint_fsrv.target_path, + argc - optind, argv + optind); + u32 len = strlen(afl->taint_fsrv.target_path); + strcpy(afl->taint_fsrv.target_path + len - 5, "taint"); + strcpy((afl->argv_taint[0]) + len - 5, "taint"); + if (afl->fsrv.use_stdin) + unsetenv("AFL_TAINT_INPUT"); + else + setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1); + afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + OKF("Taint forkserver successfully started"); + + } perform_dry_run(afl); @@ -1493,8 +1533,11 @@ stop_fuzzing: } + if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv); + if (afl->fsrv.taint_mode) afl_fsrv_deinit(&afl->taint_fsrv); afl_fsrv_deinit(&afl->fsrv); if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } + if (afl->argv_taint) { ck_free(afl->argv_taint); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); ck_free(afl->sync_id); -- cgit 1.4.1