mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-13 18:48:08 +00:00
code format
This commit is contained in:
@ -11,29 +11,6 @@ The `./examples` folder contains examples for custom mutators in python and C.
|
|||||||
|
|
||||||
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
|
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
|
||||||
|
|
||||||
## The AFL++ grammar agnostic grammar mutator
|
|
||||||
|
|
||||||
In `./autotokens` you find a token-level fuzzer that does not need to know
|
|
||||||
anything about the grammar of an input as long as it is in ascii and allows
|
|
||||||
whitespace.
|
|
||||||
It is very fast and effective.
|
|
||||||
|
|
||||||
If you are looking for an example of how to effectively create a custom
|
|
||||||
mutator take a look at this one.
|
|
||||||
|
|
||||||
## The AFL++ Grammar Mutator
|
|
||||||
|
|
||||||
If you use git to clone AFL++, then the following will incorporate our
|
|
||||||
excellent grammar custom mutator:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git submodule update --init
|
|
||||||
```
|
|
||||||
|
|
||||||
Read the README in the [Grammar-Mutator] repository on how to use it.
|
|
||||||
|
|
||||||
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
|
||||||
|
|
||||||
## Production-Ready Custom Mutators
|
## Production-Ready Custom Mutators
|
||||||
|
|
||||||
This directory holds ready to use custom mutators.
|
This directory holds ready to use custom mutators.
|
||||||
@ -47,6 +24,42 @@ and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
|
|||||||
|
|
||||||
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
|
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
|
||||||
|
|
||||||
|
### The AFL++ grammar agnostic grammar mutator
|
||||||
|
|
||||||
|
In `./autotokens` you find a token-level fuzzer that does not need to know
|
||||||
|
anything about the grammar of an input as long as it is in ascii and allows
|
||||||
|
whitespace.
|
||||||
|
It is very fast and effective.
|
||||||
|
|
||||||
|
If you are looking for an example of how to effectively create a custom
|
||||||
|
mutator take a look at this one.
|
||||||
|
|
||||||
|
### The AFL++ Grammar Mutator
|
||||||
|
|
||||||
|
If you use git to clone AFL++, then the following will incorporate our
|
||||||
|
excellent grammar custom mutator:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
|
Read the README in the [Grammar-Mutator] repository on how to use it.
|
||||||
|
|
||||||
|
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
||||||
|
|
||||||
|
Note that this custom mutator is not very good though!
|
||||||
|
|
||||||
|
### Other Mutators
|
||||||
|
|
||||||
|
atnwalk and gramatron are grammar custom mutators. Example grammars are
|
||||||
|
provided.
|
||||||
|
|
||||||
|
honggfuzz, libfuzzer and libafl are partial implementations based on the
|
||||||
|
mutator implementations of the respective fuzzers.
|
||||||
|
More for playing than serious usage.
|
||||||
|
|
||||||
|
radamsa is slow and not very good.
|
||||||
|
|
||||||
## 3rd Party Custom Mutators
|
## 3rd Party Custom Mutators
|
||||||
|
|
||||||
### Superion Mutators
|
### Superion Mutators
|
||||||
|
@ -11,10 +11,12 @@
|
|||||||
#define BUF_SIZE_INIT 4096
|
#define BUF_SIZE_INIT 4096
|
||||||
#define SOCKET_NAME "./atnwalk.socket"
|
#define SOCKET_NAME "./atnwalk.socket"
|
||||||
|
|
||||||
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry
|
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
|
||||||
|
// entry
|
||||||
#define ATNWALK_ERRORS_MAX 1
|
#define ATNWALK_ERRORS_MAX 1
|
||||||
|
|
||||||
// how many execution timeouts to tolerate until moving on to the next queue entry
|
// how many execution timeouts to tolerate until moving on to the next queue
|
||||||
|
// entry
|
||||||
#define EXEC_TIMEOUT_MAX 2
|
#define EXEC_TIMEOUT_MAX 2
|
||||||
|
|
||||||
// handshake constants
|
// handshake constants
|
||||||
@ -27,8 +29,8 @@ const uint8_t SERVER_MUTATE_BIT = 0b00000010;
|
|||||||
const uint8_t SERVER_DECODE_BIT = 0b00000100;
|
const uint8_t SERVER_DECODE_BIT = 0b00000100;
|
||||||
const uint8_t SERVER_ENCODE_BIT = 0b00001000;
|
const uint8_t SERVER_ENCODE_BIT = 0b00001000;
|
||||||
|
|
||||||
|
|
||||||
typedef struct atnwalk_mutator {
|
typedef struct atnwalk_mutator {
|
||||||
|
|
||||||
afl_state_t *afl;
|
afl_state_t *afl;
|
||||||
uint8_t atnwalk_error_count;
|
uint8_t atnwalk_error_count;
|
||||||
uint64_t prev_timeouts;
|
uint64_t prev_timeouts;
|
||||||
@ -41,66 +43,73 @@ typedef struct atnwalk_mutator {
|
|||||||
size_t fuzz_size;
|
size_t fuzz_size;
|
||||||
uint8_t *post_process_buf;
|
uint8_t *post_process_buf;
|
||||||
size_t post_process_size;
|
size_t post_process_size;
|
||||||
|
|
||||||
} atnwalk_mutator_t;
|
} atnwalk_mutator_t;
|
||||||
|
|
||||||
|
|
||||||
int read_all(int fd, uint8_t *buf, size_t buf_size) {
|
int read_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||||
|
|
||||||
int n;
|
int n;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
while (offset < buf_size) {
|
while (offset < buf_size) {
|
||||||
n = read(fd, buf + offset, buf_size - offset);
|
|
||||||
if (n == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
offset += n;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
n = read(fd, buf + offset, buf_size - offset);
|
||||||
|
if (n == -1) { return 0; }
|
||||||
|
offset += n;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||||
|
|
||||||
int n;
|
int n;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
while (offset < buf_size) {
|
while (offset < buf_size) {
|
||||||
n = write(fd, buf + offset, buf_size - offset);
|
|
||||||
if (n == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
offset += n;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
n = write(fd, buf + offset, buf_size - offset);
|
||||||
|
if (n == -1) { return 0; }
|
||||||
|
offset += n;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void put_uint32(uint8_t *buf, uint32_t val) {
|
void put_uint32(uint8_t *buf, uint32_t val) {
|
||||||
buf[0] = (uint8_t) (val >> 24);
|
|
||||||
buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16);
|
|
||||||
buf[2] = (uint8_t) ((val & 0x0000ff00) >> 8);
|
|
||||||
buf[3] = (uint8_t) (val & 0x000000ff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
buf[0] = (uint8_t)(val >> 24);
|
||||||
|
buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
|
||||||
|
buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
|
||||||
|
buf[3] = (uint8_t)(val & 0x000000ff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t to_uint32(uint8_t *buf) {
|
uint32_t to_uint32(uint8_t *buf) {
|
||||||
uint32_t val = 0;
|
|
||||||
val |= (((uint32_t) buf[0]) << 24);
|
|
||||||
val |= (((uint32_t) buf[1]) << 16);
|
|
||||||
val |= (((uint32_t) buf[2]) << 8);
|
|
||||||
val |= ((uint32_t) buf[3]);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
uint32_t val = 0;
|
||||||
|
val |= (((uint32_t)buf[0]) << 24);
|
||||||
|
val |= (((uint32_t)buf[1]) << 16);
|
||||||
|
val |= (((uint32_t)buf[2]) << 8);
|
||||||
|
val |= ((uint32_t)buf[3]);
|
||||||
|
return val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void put_uint64(uint8_t *buf, uint64_t val) {
|
void put_uint64(uint8_t *buf, uint64_t val) {
|
||||||
buf[0] = (uint8_t) (val >> 56);
|
|
||||||
buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48);
|
|
||||||
buf[2] = (uint8_t) ((val & 0x0000ff0000000000) >> 40);
|
|
||||||
buf[3] = (uint8_t) ((val & 0x000000ff00000000) >> 32);
|
|
||||||
buf[4] = (uint8_t) ((val & 0x00000000ff000000) >> 24);
|
|
||||||
buf[5] = (uint8_t) ((val & 0x0000000000ff0000) >> 16);
|
|
||||||
buf[6] = (uint8_t) ((val & 0x000000000000ff00) >> 8);
|
|
||||||
buf[7] = (uint8_t) (val & 0x00000000000000ff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
buf[0] = (uint8_t)(val >> 56);
|
||||||
|
buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
|
||||||
|
buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
|
||||||
|
buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
|
||||||
|
buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
|
||||||
|
buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
|
||||||
|
buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
|
||||||
|
buf[7] = (uint8_t)(val & 0x00000000000000ff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this custom mutator
|
* Initialize this custom mutator
|
||||||
@ -114,69 +123,82 @@ void put_uint64(uint8_t *buf, uint64_t val) {
|
|||||||
* Return NULL on error.
|
* Return NULL on error.
|
||||||
*/
|
*/
|
||||||
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||||
|
|
||||||
srand(seed);
|
srand(seed);
|
||||||
atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t));
|
atnwalk_mutator_t *data =
|
||||||
|
(atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|
||||||
perror("afl_custom_init alloc");
|
perror("afl_custom_init alloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->afl = afl;
|
data->afl = afl;
|
||||||
data->prev_hits = 0;
|
data->prev_hits = 0;
|
||||||
data->fuzz_buf = (uint8_t *) malloc(BUF_SIZE_INIT);
|
data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
|
||||||
data->fuzz_size = BUF_SIZE_INIT;
|
data->fuzz_size = BUF_SIZE_INIT;
|
||||||
data->post_process_buf = (uint8_t *) malloc(BUF_SIZE_INIT);
|
data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
|
||||||
data->post_process_size = BUF_SIZE_INIT;
|
data->post_process_size = BUF_SIZE_INIT;
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
|
||||||
|
const unsigned char *buf, size_t buf_size) {
|
||||||
|
|
||||||
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, const unsigned char *buf, size_t buf_size) {
|
// afl_custom_fuzz_count is called exactly once before entering the
|
||||||
// afl_custom_fuzz_count is called exactly once before entering the 'stage-loop' for the current queue entry
|
// 'stage-loop' for the current queue entry thus, we use it to reset the error
|
||||||
// thus, we use it to reset the error count and to initialize stage variables (somewhat not intended by the API,
|
// count and to initialize stage variables (somewhat not intended by the API,
|
||||||
// but still better than rewriting the whole thing to have a custom mutator stage)
|
// but still better than rewriting the whole thing to have a custom mutator
|
||||||
|
// stage)
|
||||||
data->atnwalk_error_count = 0;
|
data->atnwalk_error_count = 0;
|
||||||
data->prev_timeouts = data->afl->total_tmouts;
|
data->prev_timeouts = data->afl->total_tmouts;
|
||||||
|
|
||||||
// it might happen that on the last execution of the splice stage a new path is found
|
// it might happen that on the last execution of the splice stage a new path
|
||||||
// we need to fix that here and count it
|
// is found we need to fix that here and count it
|
||||||
if (data->prev_hits) {
|
if (data->prev_hits) {
|
||||||
data->afl->stage_finds[STAGE_SPLICE] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
|
||||||
|
data->afl->stage_finds[STAGE_SPLICE] +=
|
||||||
|
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
||||||
data->stage_havoc_cur = 0;
|
data->stage_havoc_cur = 0;
|
||||||
data->stage_splice_cur = 0;
|
data->stage_splice_cur = 0;
|
||||||
|
|
||||||
// 50% havoc, 50% splice
|
// 50% havoc, 50% splice
|
||||||
data->stage_havoc_max = data->afl->stage_max >> 1;
|
data->stage_havoc_max = data->afl->stage_max >> 1;
|
||||||
if (data->stage_havoc_max < HAVOC_MIN) {
|
if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
|
||||||
data->stage_havoc_max = HAVOC_MIN;
|
|
||||||
}
|
|
||||||
data->stage_splice_max = data->stage_havoc_max;
|
data->stage_splice_max = data->stage_havoc_max;
|
||||||
return data->stage_havoc_max + data->stage_splice_max;
|
return data->stage_havoc_max + data->stage_splice_max;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
|
size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
|
||||||
if (fd_socket != -1) {
|
|
||||||
close(fd_socket);
|
if (fd_socket != -1) { close(fd_socket); }
|
||||||
}
|
|
||||||
*out_buf = NULL;
|
*out_buf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
|
||||||
|
size_t buf_size, uint8_t **out_buf) {
|
||||||
|
|
||||||
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
|
if (fd_socket != -1) { close(fd_socket); }
|
||||||
if (fd_socket != -1) {
|
|
||||||
close(fd_socket);
|
|
||||||
}
|
|
||||||
data->atnwalk_error_count++;
|
data->atnwalk_error_count++;
|
||||||
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
|
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
|
||||||
|
|
||||||
data->afl->stage_max = data->afl->stage_cur;
|
data->afl->stage_max = data->afl->stage_cur;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_buf = buf;
|
*out_buf = buf;
|
||||||
return buf_size;
|
return buf_size;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform custom mutations on a given input
|
* Perform custom mutations on a given input
|
||||||
@ -194,8 +216,10 @@ size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, siz
|
|||||||
* produce data larger than max_size.
|
* produce data larger than max_size.
|
||||||
* @return Size of the mutated output.
|
* @return Size of the mutated output.
|
||||||
*/
|
*/
|
||||||
size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf,
|
size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||||
uint8_t *add_buf, size_t add_buf_size, size_t max_size) {
|
uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||||
|
size_t max_size) {
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
int fd_socket;
|
int fd_socket;
|
||||||
uint8_t ctrl_buf[8];
|
uint8_t ctrl_buf[8];
|
||||||
@ -203,43 +227,68 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
|
|
||||||
// let's display what's going on in a nice way
|
// let's display what's going on in a nice way
|
||||||
if (data->stage_havoc_cur == 0) {
|
if (data->stage_havoc_cur == 0) {
|
||||||
data->afl->stage_name = (uint8_t *) "atnwalk - havoc";
|
|
||||||
|
data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->stage_havoc_cur == data->stage_havoc_max) {
|
if (data->stage_havoc_cur == data->stage_havoc_max) {
|
||||||
data->afl->stage_name = (uint8_t *) "atnwalk - splice";
|
|
||||||
|
data->afl->stage_name = (uint8_t *)"atnwalk - splice";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase the respective havoc or splice counters
|
// increase the respective havoc or splice counters
|
||||||
if (data->stage_havoc_cur < data->stage_havoc_max) {
|
if (data->stage_havoc_cur < data->stage_havoc_max) {
|
||||||
|
|
||||||
data->stage_havoc_cur++;
|
data->stage_havoc_cur++;
|
||||||
data->afl->stage_cycles[STAGE_HAVOC]++;
|
data->afl->stage_cycles[STAGE_HAVOC]++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// if there is nothing to splice, continue with havoc and skip splicing this time
|
|
||||||
|
// if there is nothing to splice, continue with havoc and skip splicing this
|
||||||
|
// time
|
||||||
if (data->afl->ready_for_splicing_count < 1) {
|
if (data->afl->ready_for_splicing_count < 1) {
|
||||||
|
|
||||||
data->stage_havoc_max = data->afl->stage_max;
|
data->stage_havoc_max = data->afl->stage_max;
|
||||||
data->stage_havoc_cur++;
|
data->stage_havoc_cur++;
|
||||||
data->afl->stage_cycles[STAGE_HAVOC]++;
|
data->afl->stage_cycles[STAGE_HAVOC]++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
data->stage_splice_cur++;
|
data->stage_splice_cur++;
|
||||||
data->afl->stage_cycles[STAGE_SPLICE]++;
|
data->afl->stage_cycles[STAGE_SPLICE]++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep track of found new corpus seeds per stage
|
// keep track of found new corpus seeds per stage
|
||||||
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
|
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
|
||||||
|
|
||||||
if (data->stage_splice_cur <= 1) {
|
if (data->stage_splice_cur <= 1) {
|
||||||
data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
|
||||||
|
data->afl->stage_finds[STAGE_HAVOC] +=
|
||||||
|
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
data->afl->stage_finds[STAGE_SPLICE] +=
|
data->afl->stage_finds[STAGE_SPLICE] +=
|
||||||
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
||||||
|
|
||||||
// check whether this input produces a lot of timeouts, if it does then abandon this queue entry
|
// check whether this input produces a lot of timeouts, if it does then
|
||||||
|
// abandon this queue entry
|
||||||
if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
|
if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
|
||||||
|
|
||||||
data->afl->stage_max = data->afl->stage_cur;
|
data->afl->stage_max = data->afl->stage_cur;
|
||||||
return fail_gracefully(-1, data, buf, buf_size, out_buf);
|
return fail_gracefully(-1, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the socket
|
// initialize the socket
|
||||||
@ -248,98 +297,133 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||||
if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask whether the server is alive
|
// ask whether the server is alive
|
||||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see whether the server replies as expected
|
// see whether the server replies as expected
|
||||||
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
if (!read_all(fd_socket, ctrl_buf, 1) ||
|
||||||
|
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell the server what we want to do
|
// tell the server what we want to do
|
||||||
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
|
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
|
||||||
|
|
||||||
// perform a crossover if we are splicing
|
// perform a crossover if we are splicing
|
||||||
if (data->stage_splice_cur > 0) {
|
if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
|
||||||
wanted |= SERVER_CROSSOVER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tell the server what we want and how much data will be sent
|
// tell the server what we want and how much data will be sent
|
||||||
ctrl_buf[0] = wanted;
|
ctrl_buf[0] = wanted;
|
||||||
put_uint32(ctrl_buf + 1, (uint32_t) buf_size);
|
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
|
||||||
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the data to mutate and encode
|
// send the data to mutate and encode
|
||||||
if (!write_all(fd_socket, buf, buf_size)) {
|
if (!write_all(fd_socket, buf, buf_size)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wanted & SERVER_CROSSOVER_BIT) {
|
if (wanted & SERVER_CROSSOVER_BIT) {
|
||||||
// since we requested crossover, we will first tell how much additional data is to be expected
|
|
||||||
put_uint32(ctrl_buf, (uint32_t) add_buf_size);
|
// since we requested crossover, we will first tell how much additional data
|
||||||
|
// is to be expected
|
||||||
|
put_uint32(ctrl_buf, (uint32_t)add_buf_size);
|
||||||
if (!write_all(fd_socket, ctrl_buf, 4)) {
|
if (!write_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the additional data for crossover
|
// send the additional data for crossover
|
||||||
if (!write_all(fd_socket, add_buf, add_buf_size)) {
|
if (!write_all(fd_socket, add_buf, add_buf_size)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastly, a seed is required for crossover so send one
|
// lastly, a seed is required for crossover so send one
|
||||||
put_uint64(ctrl_buf, (uint64_t) rand());
|
put_uint64(ctrl_buf, (uint64_t)rand());
|
||||||
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// since we requested mutation, we need to provide a seed for that
|
// since we requested mutation, we need to provide a seed for that
|
||||||
put_uint64(ctrl_buf, (uint64_t) rand());
|
put_uint64(ctrl_buf, (uint64_t)rand());
|
||||||
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain the required buffer size for the data that will be returned
|
// obtain the required buffer size for the data that will be returned
|
||||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
size_t new_size = (size_t) to_uint32(ctrl_buf);
|
|
||||||
|
size_t new_size = (size_t)to_uint32(ctrl_buf);
|
||||||
|
|
||||||
// if the data is too large then we ignore this round
|
// if the data is too large then we ignore this round
|
||||||
if (new_size > max_size) {
|
if (new_size > max_size) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_size > buf_size) {
|
if (new_size > buf_size) {
|
||||||
// buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate
|
|
||||||
|
// buf is too small, need to use data->fuzz_buf, let's see whether we need
|
||||||
|
// to reallocate
|
||||||
if (new_size > data->fuzz_size) {
|
if (new_size > data->fuzz_size) {
|
||||||
|
|
||||||
data->fuzz_size = new_size << 1;
|
data->fuzz_size = new_size << 1;
|
||||||
data->fuzz_buf = (uint8_t *) realloc(data->fuzz_buf, data->fuzz_size);
|
data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_buf = data->fuzz_buf;
|
*out_buf = data->fuzz_buf;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// new_size fits into buf, so re-use it
|
// new_size fits into buf, so re-use it
|
||||||
*out_buf = buf;
|
*out_buf = buf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain the encoded data
|
// obtain the encoded data
|
||||||
if (!read_all(fd_socket, *out_buf, new_size)) {
|
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd_socket);
|
close(fd_socket);
|
||||||
return new_size;
|
return new_size;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A post-processing function to use right before AFL writes the test case to
|
* A post-processing function to use right before AFL writes the test case to
|
||||||
@ -357,68 +441,88 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
|||||||
* @return Size of the output buffer after processing or the needed amount.
|
* @return Size of the output buffer after processing or the needed amount.
|
||||||
* A return of 0 indicates an error.
|
* A return of 0 indicates an error.
|
||||||
*/
|
*/
|
||||||
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
|
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
|
||||||
|
size_t buf_size, uint8_t **out_buf) {
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
int fd_socket;
|
int fd_socket;
|
||||||
uint8_t ctrl_buf[8];
|
uint8_t ctrl_buf[8];
|
||||||
|
|
||||||
// initialize the socket
|
// initialize the socket
|
||||||
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (fd_socket == -1) {
|
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
|
||||||
return fail_fatal(fd_socket, out_buf);
|
|
||||||
}
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||||
if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask whether the server is alive
|
// ask whether the server is alive
|
||||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see whether the server replies as expected
|
// see whether the server replies as expected
|
||||||
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
if (!read_all(fd_socket, ctrl_buf, 1) ||
|
||||||
|
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||||
|
|
||||||
return fail_fatal(fd_socket, out_buf);
|
return fail_fatal(fd_socket, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell the server what we want and how much data will be sent
|
// tell the server what we want and how much data will be sent
|
||||||
ctrl_buf[0] = SERVER_DECODE_BIT;
|
ctrl_buf[0] = SERVER_DECODE_BIT;
|
||||||
put_uint32(ctrl_buf + 1, (uint32_t) buf_size);
|
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
|
||||||
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the data to decode
|
// send the data to decode
|
||||||
if (!write_all(fd_socket, buf, buf_size)) {
|
if (!write_all(fd_socket, buf, buf_size)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain the required buffer size for the data that will be returned
|
// obtain the required buffer size for the data that will be returned
|
||||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
size_t new_size = (size_t) to_uint32(ctrl_buf);
|
|
||||||
|
size_t new_size = (size_t)to_uint32(ctrl_buf);
|
||||||
|
|
||||||
// need to use data->post_process_buf, let's see whether we need to reallocate
|
// need to use data->post_process_buf, let's see whether we need to reallocate
|
||||||
if (new_size > data->post_process_size) {
|
if (new_size > data->post_process_size) {
|
||||||
|
|
||||||
data->post_process_size = new_size << 1;
|
data->post_process_size = new_size << 1;
|
||||||
data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size);
|
data->post_process_buf =
|
||||||
|
(uint8_t *)realloc(data->post_process_buf, data->post_process_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_buf = data->post_process_buf;
|
*out_buf = data->post_process_buf;
|
||||||
|
|
||||||
// obtain the decoded data
|
// obtain the decoded data
|
||||||
if (!read_all(fd_socket, *out_buf, new_size)) {
|
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||||
|
|
||||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd_socket);
|
close(fd_socket);
|
||||||
return new_size;
|
return new_size;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deinitialize everything
|
* Deinitialize everything
|
||||||
@ -426,7 +530,10 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf
|
|||||||
* @param data The data ptr from afl_custom_init
|
* @param data The data ptr from afl_custom_init
|
||||||
*/
|
*/
|
||||||
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
||||||
|
|
||||||
free(data->fuzz_buf);
|
free(data->fuzz_buf);
|
||||||
free(data->post_process_buf);
|
free(data->post_process_buf);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,12 @@
|
|||||||
release of the tool. See README.md for the general instruction manual.
|
release of the tool. See README.md for the general instruction manual.
|
||||||
|
|
||||||
### Version ++4.07a (dev)
|
### Version ++4.07a (dev)
|
||||||
|
- afl-fuzz:
|
||||||
|
- new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
|
||||||
|
data before post process on finds
|
||||||
- afl-showmap:
|
- afl-showmap:
|
||||||
- added custom mutator post_process and send support
|
- added custom mutator post_process and send support
|
||||||
|
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
|
||||||
|
|
||||||
|
|
||||||
### Version ++4.06c (release)
|
### Version ++4.06c (release)
|
||||||
|
@ -156,8 +156,8 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((visibility("default"))) void js_api_set_instrument_no_dynamic_load(
|
__attribute__((visibility("default"))) void
|
||||||
void) {
|
js_api_set_instrument_no_dynamic_load(void) {
|
||||||
|
|
||||||
ranges_inst_dynamic_load = FALSE;
|
ranges_inst_dynamic_load = FALSE;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user