aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-01-20 01:49:32 +0100
committervan Hauser <vh@thc.org>2021-01-20 01:49:32 +0100
commite7b572af3608e2d097aad17408ad4853befdc02c (patch)
tree4837bfb6e5d88a1b4a9efc6a5081f30fab6a6c15
parent86c567fa3a37e9181b5e692b53b5fae07921cc33 (diff)
downloadafl++-e7b572af3608e2d097aad17408ad4853befdc02c.tar.gz
bugfix and new transform detection feature
-rw-r--r--instrumentation/afl-compiler-rt.o.c14
-rw-r--r--src/afl-fuzz-redqueen.c430
-rw-r--r--src/afl-fuzz.c14
3 files changed, 416 insertions, 42 deletions
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index 0ce96673..a290f110 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -1545,6 +1545,18 @@ static int area_is_mapped(void *ptr, size_t len) {
void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
+ /*
+ u32 i;
+ if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
+ fprintf(stderr, "rtn arg0=");
+ for (i = 0; i < 8; i++)
+ fprintf(stderr, "%02x", ptr1[i]);
+ fprintf(stderr, " arg1=");
+ for (i = 0; i < 8; i++)
+ fprintf(stderr, "%02x", ptr2[i]);
+ fprintf(stderr, "\n");
+ */
+
if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
@@ -1555,7 +1567,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
u32 hits;
- if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
+ if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
hits = 0;
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 1c5b95f6..bf41863e 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -30,18 +30,21 @@
//#define _DEBUG
#define COMBINE
-#define CMPLOG_INTROSPECTION
+//#define CMPLOG_INTROSPECTION
//#define ARITHMETIC_LESSER_GREATER
+//#define TRANSFORM
// CMP attribute enum
enum {
- IS_EQUAL = 1,
- IS_GREATER = 2,
- IS_LESSER = 4,
- IS_FP = 8,
- IS_FP_MOD = 16,
- IS_INT_MOD = 32
+ IS_EQUAL = 1, // arithemtic equal comparison
+ IS_GREATER = 2, // arithmetic greater comparison
+ IS_LESSER = 4, // arithmetic lesser comparison
+ IS_FP = 8, // is a floating point, not an integer
+ /* --- below are internal settings, not from target cmplog */
+ IS_FP_MOD = 16, // arithemtic changed floating point
+ IS_INT_MOD = 32, // arithmetic changed interger
+ IS_TRANSFORM = 64 // transformed integer
};
@@ -466,6 +469,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
+#ifdef TRANSFORM
static int strntoll(const char *str, size_t sz, char **end, int base,
long long *out) {
@@ -513,6 +517,8 @@ static int strntoull(const char *str, size_t sz, char **end, int base,
}
+#endif
+
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 pattern, u64 repl, u64 o_pattern,
u64 changed_val, u8 attr, u32 idx, u32 taint_len,
@@ -553,14 +559,15 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u32 its_len = MIN(len - idx, taint_len);
- u8 * endptr;
- u8 use_num = 0, use_unum = 0;
- unsigned long long unum;
- long long num;
-
+#ifdef TRANSFORM
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (lvl & LVL3) {
+ u8 * endptr;
+ u8 use_num = 0, use_unum = 0;
+ unsigned long long unum;
+ long long num;
+
if (afl->queue_cur->is_ascii) {
endptr = buf_8;
@@ -575,11 +582,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
-#ifdef _DEBUG
+ #ifdef _DEBUG
if (idx == 0)
fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n",
afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern);
-#endif
+ #endif
// num is likely not pattern as atoi("AAA") will be zero...
if (use_num && ((u64)num == pattern || !num)) {
@@ -626,8 +633,201 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
+ // Try to identify transform magic
+ if (pattern != o_pattern && repl == changed_val && attr <= IS_EQUAL) {
+
+ u64 *ptr = (u64 *)&buf[idx];
+ u64 *o_ptr = (u64 *)&orig_buf[idx];
+ u64 b_val, o_b_val, mask;
+
+ switch (SHAPE_BYTES(h->shape)) {
+
+ case 0:
+ case 1:
+ b_val = (u64)(*ptr % 0x100);
+ o_b_val = (u64)(*o_ptr % 0x100);
+ mask = 0xff;
+ break;
+ case 2:
+ case 3:
+ b_val = (u64)(*ptr % 0x10000);
+ o_b_val = (u64)(*o_ptr % 0x10000);
+ mask = 0xffff;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ b_val = (u64)(*ptr % 0x100000000);
+ o_b_val = (u64)(*o_ptr % 0x100000000);
+ mask = 0xffffffff;
+ break;
+ default:
+ b_val = *ptr;
+ o_b_val = *o_ptr;
+ mask = 0xffffffffffffffff;
+
+ }
+
+ // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..."
+ s64 diff = pattern - b_val;
+ s64 o_diff = o_pattern - o_b_val;
+ /*
+ fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
+ h->shape + 1, o_pattern, o_b_val, o_diff);
+ fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
+ b_val, diff);*/
+ if (diff == o_diff && diff) {
+
+ // this could be an arithmetic transformation
+
+ u64 new_repl = (u64)((s64)repl - diff);
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ // test for XOR, eg. "if ((user_val ^ 0xabcd) == 0x1234) ..."
+ if (*status != 1) {
+
+ diff = pattern ^ b_val;
+ s64 o_diff = o_pattern ^ o_b_val;
+
+ /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
+ "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+ if (diff == o_diff && diff) {
+
+ // this could be a XOR transformation
+
+ u64 new_repl = (u64)((s64)repl ^ diff);
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ // test for to lowercase, eg. "new_val = (user_val | 0x2020) ..."
+ if (*status != 1) {
+
+ if ((b_val | (0x2020202020202020 & mask)) == (pattern & mask)) {
+
+ diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ if ((o_b_val | (0x2020202020202020 & mask)) == (o_pattern & mask)) {
+
+ o_diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
+ "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+ if (o_diff && diff) {
+
+ // this could be a lower to upper
+
+ u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask));
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ // test for to uppercase, eg. "new_val = (user_val | 0x5f5f) ..."
+ if (*status != 1) {
+
+ if ((b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (pattern & mask)) {
+
+ diff = 1;
+
+ } else {
+
+ diff = 0;
+
+ }
+
+ if ((o_b_val & (0x5f5f5f5f5f5f5f5f & mask)) == (o_pattern & mask)) {
+
+ o_diff = 1;
+
+ } else {
+
+ o_diff = 0;
+
+ }
+
+ /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n",
+ idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
+ "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+ if (o_diff && diff) {
+
+ // this could be a lower to upper
+
+ u64 new_repl = (repl | (0x2020202020202020 & mask));
+ // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+
+ if (unlikely(cmp_extend_encoding(
+ afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
+ taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) {
+
+ return 1;
+
+ }
+
+ if (*status == 1) { fprintf(stderr, "FOUND!\n"); }
+
+ }
+
+ }
+
+ *status = 0;
+
+ }
+
}
+#endif
+
// we only allow this for ascii2integer (above)
if (unlikely(pattern == o_pattern)) { return 0; }
@@ -783,7 +983,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// in original buffer)
#ifdef ARITHMETIC_LESSER_GREATER
- if (lvl < LVL3) { return 0; }
+ if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; }
// lesser/greater FP comparison
if ((attr & (IS_LESSER + IS_GREATER)) &&
@@ -1374,56 +1574,185 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl,
- u8 *o_pattern, u32 idx, u32 taint_len,
- u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len,
- u8 *status) {
+ u8 *o_pattern, u8 *changed_val, u32 idx,
+ u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u8 lvl, u8 *status) {
#ifndef COMBINE
(void)(cbuf);
#endif
- u32 i;
+ u32 i = 0;
u32 its_len = MIN((u32)32, len - idx);
its_len = MIN(its_len, taint_len);
u8 save[32];
memcpy(save, &buf[idx], its_len);
- for (i = 0; i < its_len; ++i) {
+ if (lvl == LVL1) {
- if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
- *status == 1) {
+ for (i = 0; i < its_len; ++i) {
- break;
+ if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
+ *status == 1) {
+
+ break;
+
+ }
+
+ buf[idx + i] = repl[i];
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+
+#ifdef COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); }
+#endif
}
- buf[idx + i] = repl[i];
+ }
+
+ if (*status == 1) return 0;
+
+ if (lvl & LVL3) {
+
+ u8 toupper = 0, tolower = 0, xor = 0, arith = 0;
+ u8 xor_val[32], arith_val[32];
+ u32 j;
+
+#ifdef _DEBUG
+ fprintf(stderr, "RTN TRANSFORM idx=%u ", idx);
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", o_pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", repl[j]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", changed_val[j]);
+ fprintf(stderr, "\n");
+#endif
+ for (i = 0; i < its_len; ++i) {
+
+ xor_val[i] = pattern[i] ^ buf[idx + i];
+ arith_val[i] = pattern[i] - buf[idx + i];
+
+ if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) {
+
+ ++xor;
+
+ }
+
+ if ((o_pattern[i] - orig_buf[idx + i]) == arith_val[i] && arith_val[i]) {
+
+ ++arith;
+
+ }
+
+ if ((buf[idx + i] | 0x20) == pattern[i] &&
+ (orig_buf[idx + i] | 0x20) == o_pattern[i]) {
+
+ ++tolower;
- if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ }
+
+ if ((buf[idx + i] & 0x5a) == pattern[i] &&
+ (orig_buf[idx + i] & 0x5a) == o_pattern[i]) {
+
+ ++toupper;
+
+ }
+
+#ifdef _DEBUG
+ fprintf(stderr, "RTN loop=%u %u %u %u %u (%u %u)\n", i, xor, arith,
+ tolower, toupper, arith_val[i], xor_val[i]);
+#endif
+
+ if (xor > i) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] ^ xor_val[j];
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT xor %u result %u\n", xor, *status);
+
+ }
+
+ if (arith > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] - arith_val[j];
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status);
+
+ }
+
+ if (toupper > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] | 0x20;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT toupper %u result %u\n", toupper,
+ // *status);
+
+ }
+
+ if (tolower > i && *status != 1) {
+
+ for (j = 0; j <= i; j++)
+ buf[idx + j] = repl[j] & 0x5f;
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT tolower %u result %u\n", tolower,
+ // *status);
+
+ }
#ifdef COMBINE
- if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); }
+ if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); }
#endif
+ if ((i >= xor&&i >= arith &&i >= tolower &&i >= toupper) ||
+ repl[i] != changed_val[i] || *status == 1) {
+
+ break;
+
+ }
+
+ }
+
}
memcpy(&buf[idx], save, i);
+
return 0;
}
static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
- u32 len, struct tainted *taint) {
+ u32 len, u8 lvl, struct tainted *taint) {
struct tainted * t;
struct cmp_header *h = &afl->shm.cmp_map->headers[key];
- u32 i, j, idx, have_taint = 1, taint_len;
+ u32 i, j, idx, have_taint = 1, taint_len, loggeds;
+ u8 status = 0, found_one = 0;
- u32 loggeds = h->hits;
- if (h->hits > CMP_MAP_RTN_H) { loggeds = CMP_MAP_RTN_H; }
+ if (h->hits > CMP_MAP_RTN_H) {
- u8 status = 0;
- u8 found_one = 0;
+ loggeds = CMP_MAP_RTN_H;
+
+ } else {
+
+ loggeds = h->hits;
+
+ }
for (i = 0; i < loggeds; ++i) {
@@ -1445,6 +1774,20 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
+ /*
+ struct cmp_header *hh = &afl->orig_cmp_map->headers[key];
+ fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id,
+ h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x",
+ o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr,
+ "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u
+ o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_o->v0[j]);
+ fprintf(stderr, " o1=");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_o->v1[j]);
+ fprintf(stderr, "\n");
+ */
+
t = taint;
while (t->next) {
@@ -1476,9 +1819,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
status = 0;
- if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, idx,
- taint_len, orig_buf, buf, cbuf, len,
- &status))) {
+ if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0,
+ orig_o->v1, idx, taint_len, orig_buf,
+ buf, cbuf, len, lvl, &status))) {
return 1;
@@ -1493,9 +1836,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
status = 0;
- if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, idx,
- taint_len, orig_buf, buf, cbuf, len,
- &status))) {
+ if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1,
+ orig_o->v0, idx, taint_len, orig_buf,
+ buf, cbuf, len, lvl, &status))) {
return 1;
@@ -1511,7 +1854,7 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
// If failed, add to dictionary
- if (!found_one) {
+ if (!found_one && (lvl & LVL1)) {
if (unlikely(!afl->pass_stats[key].total)) {
@@ -1702,9 +2045,14 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
}
- } else if (lvl & LVL1) {
+ } else if ((lvl & LVL1)
+
+#ifdef TRANSFORM
+ || (lvl & LVL3)
+#endif
+ ) {
- if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, taint))) {
+ if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
goto exit_its;
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 88c40ee8..0f76e8a3 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1515,7 +1515,21 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ u8 *save_env = NULL;
+ if (afl->cmplog_binary) {
+
+ save_env = ck_strdup(getenv(CMPLOG_SHM_ENV_VAR));
+ unsetenv(CMPLOG_SHM_ENV_VAR); // normal forkserver should not have this
+
+ }
+
perform_dry_run(afl);
+ if (save_env) {
+
+ setenv(CMPLOG_SHM_ENV_VAR, save_env, 1); // needed for at_exit()
+ ck_free(save_env);
+
+ }
/*
if (!user_set_cache && afl->q_testcase_max_cache_size) {