afl_custom_fuzz_send added

This commit is contained in:
vanhauser-thc
2022-11-11 10:46:45 +01:00
parent b2f12c3712
commit c5f8869778
7 changed files with 124 additions and 7 deletions

View File

@ -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.05a (dev) ### Version ++4.05a (dev)
- your PR? :) - afl-fuzz:
- added afl_custom_fuzz_send custom mutator feature. Now your can
send fuzz data to the target as you need, e.g. via IPC.
- afl-showmap/afl-cmin
- -t none now translates to -t 120000 (120 seconds)
- unicorn_mode updated
### Version ++4.04c (release) ### Version ++4.04c (release)
- fix gramatron and grammar_mutator build scripts - fix gramatron and grammar_mutator build scripts

View File

@ -57,6 +57,7 @@ int afl_custom_post_trim(void *data, unsigned char success);
size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size); size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size);
unsigned char afl_custom_havoc_mutation_probability(void *data); unsigned char afl_custom_havoc_mutation_probability(void *data);
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename); unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue); u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
const char* afl_custom_introspection(my_mutator_t *data); const char* afl_custom_introspection(my_mutator_t *data);
void afl_custom_deinit(void *data); void afl_custom_deinit(void *data);
@ -98,6 +99,9 @@ def havoc_mutation_probability():
def queue_get(filename): def queue_get(filename):
return True return True
def fuzz_send(buf):
pass
def queue_new_entry(filename_new_queue, filename_orig_queue): def queue_new_entry(filename_new_queue, filename_orig_queue):
return False return False
@ -168,6 +172,12 @@ def deinit(): # optional for Python
to the target, e.g. if it is too short, too corrupted, etc. If so, to the target, e.g. if it is too short, too corrupted, etc. If so,
return a NULL buffer and zero length (or a 0 length string in Python). return a NULL buffer and zero length (or a 0 length string in Python).
- `fuzz_send` (optional):
This method can be used if you want to send data to the target yourself,
e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
that you start the target with afl-fuzz.
- `queue_new_entry` (optional): - `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue. If the This methods is called after adding a new test case to the queue. If the

View File

@ -968,6 +968,19 @@ struct custom_mutator {
*/ */
u8 (*afl_custom_queue_get)(void *data, const u8 *filename); u8 (*afl_custom_queue_get)(void *data, const u8 *filename);
/**
* This method can be used if you want to send data to the target yourself,
* e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
* that you start the target with afl-fuzz.
*
* (Optional)
*
* @param data pointer returned in afl_custom_init by this custom mutator
* @param buf Buffer containing the test case
* @param buf_size Size of the test case
*/
void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
/** /**
* Allow for additional analysis (e.g. calling a different tool that does a * Allow for additional analysis (e.g. calling a different tool that does a
* different kind of coverage and saves this for the custom mutator). * different kind of coverage and saves this for the custom mutator).

View File

@ -314,6 +314,14 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
} }
/* "afl_custom_fuzz_send", optional */
mutator->afl_custom_fuzz_send = dlsym(dh, "afl_custom_fuzz_send");
if (!mutator->afl_custom_fuzz_send) {
ACTF("optional symbol 'afl_custom_fuzz_send' not found.");
}
/* "afl_custom_queue_new_entry", optional */ /* "afl_custom_queue_new_entry", optional */
mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry"); mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
if (!mutator->afl_custom_queue_new_entry) { if (!mutator->afl_custom_queue_new_entry) {

View File

@ -246,6 +246,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "havoc_mutation_probability"); PyObject_GetAttrString(py_module, "havoc_mutation_probability");
py_functions[PY_FUNC_QUEUE_GET] = py_functions[PY_FUNC_QUEUE_GET] =
PyObject_GetAttrString(py_module, "queue_get"); PyObject_GetAttrString(py_module, "queue_get");
py_functions[PY_FUNC_FUZZ_SEND] =
PyObject_GetAttrString(py_module, "fuzz_send");
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] = py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
PyObject_GetAttrString(py_module, "queue_new_entry"); PyObject_GetAttrString(py_module, "queue_new_entry");
py_functions[PY_FUNC_INTROSPECTION] = py_functions[PY_FUNC_INTROSPECTION] =
@ -466,6 +468,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
} }
if (py_functions[PY_FUNC_FUZZ_SEND]) {
mutator->afl_custom_fuzz_send = fuzz_send_py;
}
if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) { if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) {
mutator->afl_custom_queue_new_entry = queue_new_entry_py; mutator->afl_custom_queue_new_entry = queue_new_entry_py;
@ -893,6 +901,43 @@ u8 queue_get_py(void *py_mutator, const u8 *filename) {
} }
void fuzz_send_py(void *py_mutator, const u8 *buf, size_t buf_size) {
PyObject *py_args, *py_value;
py_args = PyTuple_New(1);
py_value = PyByteArray_FromStringAndSize(buf, buf_size);
if (!py_value) {
Py_DECREF(py_args);
FATAL("Failed to convert arguments");
}
PyTuple_SetItem(py_args, 0, py_value);
py_value = PyObject_CallObject(
((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ_SEND], py_args);
Py_DECREF(py_args);
if (py_value != NULL) {
#if PY_MAJOR_VERSION >= 3
u32 retcnt = (u32)PyLong_AsLong(py_value);
#else
u32 retcnt = PyInt_AsLong(py_value);
#endif
Py_DECREF(py_value);
} else {
PyErr_Print();
FATAL("Call failed");
}
}
u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue, u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
const u8 *filename_orig_queue) { const u8 *filename_orig_queue) {

View File

@ -133,9 +133,25 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
if (new_mem != *mem) { *mem = new_mem; } if (new_mem != *mem) { *mem = new_mem; }
/* everything as planned. use the potentially new data. */ if (unlikely(afl->custom_mutators_count)) {
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
len = new_size; LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz_send) {
el->afl_custom_fuzz_send(el->data, *mem, new_size);
}
});
} else {
/* everything as planned. use the potentially new data. */
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
len = new_size;
}
} else { } else {
@ -149,8 +165,24 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
} }
/* boring uncustom. */ if (unlikely(afl->custom_mutators_count)) {
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz_send) {
el->afl_custom_fuzz_send(el->data, *mem, len);
}
});
} else {
/* boring uncustom. */
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
}
} }

View File

@ -7,3 +7,8 @@ You only need to change the while() loop of the main() to send the
data of buf[] with length len to the target and write the coverage data of buf[] with length len to the target and write the coverage
information to __afl_area_ptr[__afl_map_size] information to __afl_area_ptr[__afl_map_size]
UPDATE: you can also use [custom mutators](../../docs/custom_mutators.md) with
afl_custom_fuzz_send to send data to a target, which is much more efficient!
But you can only use this feature if you start the target via afl-fuzz and
a forkserver is active (e.g. via -Q qemu_mode or source compiled).