From 38e7dd2b9efbd9c6cda47774630a82660d3156b3 Mon Sep 17 00:00:00 2001 From: h1994st Date: Wed, 4 Mar 2020 01:09:37 -0500 Subject: Update examples of the custom mutator - Merge `examples/python_mutators` into `examples/custom_mutators` - Remove `examples/python_mutators` - Update existing examples to demonstrate new APIs --- docs/custom_mutator.md | 201 ------------------------------------------------ docs/custom_mutators.md | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/env_variables.md | 2 +- 3 files changed, 202 insertions(+), 202 deletions(-) delete mode 100644 docs/custom_mutator.md create mode 100644 docs/custom_mutators.md (limited to 'docs') diff --git a/docs/custom_mutator.md b/docs/custom_mutator.md deleted file mode 100644 index 4deb07e1..00000000 --- a/docs/custom_mutator.md +++ /dev/null @@ -1,201 +0,0 @@ -# Custom Mutators in AFL++ - -This file describes how you can implement custom mutations to be used in AFL. -For now, we support C/C++ library and Python module, collectivelly named as the -custom mutator. - -Implemented by -- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence () -- Python module: Christian Holler from Mozilla () - -## 1) Introduction - -Custom mutators can be passed to `afl-fuzz` to perform custom mutations on test -cases beyond those available in AFL. For example, to enable structure-aware -fuzzing by using libraries that perform mutations according to a given grammar. - -The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY` -or `AFL_PYTHON_MODULE` environment variable., and must export a fuzz function. -Please see [APIs](#2-apis) and [Usage](#3-usage) for detail. - -The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage). - -Note: If `AFL_CUSTOM_MUTATOR_ONLY` is set, all mutations will solely be -performed with the custom mutator. - -## 2) APIs - -C/C++: -```c -void afl_custom_init(unsigned int seed); -size_t afl_custom_fuzz(u8* buf, size_t buf_size, - u8* add_buf, size_t add_buf_size, - u8* mutated_out, size_t max_size); -size_t afl_custom_pre_save(u8* buf, size_t buf_size, u8** out_buf); -u32 afl_custom_init_trim(u8* buf, size_t buf_size); -void afl_custom_trim(u8** out_buf, size_t* out_buf_size); -u32 afl_custom_post_trim(u8 success); -``` - -Python: -```python -def init(seed): - pass - -def fuzz(buf, add_buf, max_size): - return mutated_out - -def pre_save(buf): - return out_buf - -def init_trim(buf): - return cnt - -def trim(): - return out_buf - -def post_trim(success): - return next_index -``` - -### Custom Mutation - -- `init` (optional): - - This method is called when AFL++ starts up and is used to seed RNG. - -- `fuzz` (required): - - This method performs custom mutations on a given input. It also accepts an - additional test case. - -- `pre_save` (optional): - - For some cases, the format of the mutated data returned from the custom - mutator is not suitable to directly execute the target with this input. - For example, when using libprotobuf-mutator, the data returned is in a - protobuf format which corresponds to a given grammar. In order to execute - the target, the protobuf data must be converted to the plain-text format expected by the target. In such scenarios, the user can define the - `pre_save` function. This function is then transforms the data into the - format expected by the API before executing the target. - - -### Trimming Support - -The generic trimming routines implemented in AFL++ can easily destroy the -structure of complex formats, possibly leading to a point where you have a lot -of test cases in the queue that your Python module cannot process anymore but -your target application still accepts. This is especially the case when your -target can process a part of the input (causing coverage) and then errors out -on the remaining input. - -In such cases, it makes sense to implement a custom trimming routine. The API -consists of multiple methods because after each trimming step, we have to go -back into the C code to check if the coverage bitmap is still the same for the -trimmed input. Here's a quick API description: - -- `init_trim` (optional): - - This method is called at the start of each trimming operation and receives - the initial buffer. It should return the amount of iteration steps possible - on this input (e.g. if your input has n elements and you want to remove them - one by one, return n, if you do a binary search, return log(n), and so on). - - If your trimming algorithm doesn't allow you to determine the amount of - (remaining) steps easily (esp. while running), then you can alternatively - return 1 here and always return 0 in `post_trim` until you are finished and - no steps remain. In that case, returning 1 in `post_trim` will end the - trimming routine. The whole current index/max iterations stuff is only used - to show progress. - -- `trim` (optional) - - This method is called for each trimming operation. It doesn't have any - arguments because we already have the initial buffer from `init_trim` and we - can memorize the current state in global variables. This can also save - reparsing steps for each iteration. It should return the trimmed input - buffer, where the returned data must not exceed the initial input data in - length. Returning anything that is larger than the original data (passed to - `init_trim`) will result in a fatal abort of AFL++. - -- `post_trim` (optional) - - This method is called after each trim operation to inform you if your - trimming step was successful or not (in terms of coverage). If you receive - a failure here, you should reset your input to the last known good state. - In any case, this method must return the next trim iteration index (from 0 - to the maximum amount of steps you returned in `init_trim`). - -Omitting any of three methods will cause the trimming to be disabled and trigger -a fallback to the builtin default trimming routine. - -### Environment Variables - -Optionally, the following environment variables are supported: - -- `AFL_PYTHON_ONLY` - - Disable all other mutation stages. This can prevent broken testcases - (those that your Python module can't work with anymore) to fill up your - queue. Best combined with a custom trimming routine (see below) because - trimming can cause the same test breakage like havoc and splice. - -- `AFL_DEBUG` - - When combined with `AFL_NO_UI`, this causes the C trimming code to emit additional messages about the performance and actions of your custom trimmer. Use this to see if it works :) - -## 3) Usage - -### Prerequisite - -For Python mutator, the python 3 or 2 development package is required. On -Debian/Ubuntu/Kali this can be done: - -```bash -sudo apt install python3-dev -# or -sudo apt install python-dev -``` - -Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects -Python 2 and 3 through `python-config` if it is in the PATH and compiles -`afl-fuzz` with the feature if available. - -Note: for some distributions, you might also need the package `python[23]-apt`. -In case your setup is different, set the necessary variables like this: -`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`. - -### Custom Mutator Preparation - -For C/C++ mutator, the source code must be compiled as a shared object: -```bash -gcc -shared -Wall -O3 example.c -o example.so -``` - -### Run - -C/C++ -```bash -export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so -afl-fuzz /path/to/program -``` - -Python -```bash -export PYTHONPATH=`dirname /full/path/to/example.py` -export AFL_PYTHON_MODULE=example -afl-fuzz /path/to/program -``` - -## 4) Example - -Please see [example.c](../examples/custom_mutators/example.c) and -[example.py](../examples/custom_mutators/example.py) - -## 5) Other Resources - -- AFL libprotobuf mutator - - [bruce30262/libprotobuf-mutator_fuzzing_learning](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator) - - [thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator) -- [XML Fuzzing@NullCon 2017](https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf) - - [A bug detected by AFL + XML-aware mutators](https://bugs.chromium.org/p/chromium/issues/detail?id=930663) diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md new file mode 100644 index 00000000..4deb07e1 --- /dev/null +++ b/docs/custom_mutators.md @@ -0,0 +1,201 @@ +# Custom Mutators in AFL++ + +This file describes how you can implement custom mutations to be used in AFL. +For now, we support C/C++ library and Python module, collectivelly named as the +custom mutator. + +Implemented by +- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence () +- Python module: Christian Holler from Mozilla () + +## 1) Introduction + +Custom mutators can be passed to `afl-fuzz` to perform custom mutations on test +cases beyond those available in AFL. For example, to enable structure-aware +fuzzing by using libraries that perform mutations according to a given grammar. + +The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY` +or `AFL_PYTHON_MODULE` environment variable., and must export a fuzz function. +Please see [APIs](#2-apis) and [Usage](#3-usage) for detail. + +The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage). + +Note: If `AFL_CUSTOM_MUTATOR_ONLY` is set, all mutations will solely be +performed with the custom mutator. + +## 2) APIs + +C/C++: +```c +void afl_custom_init(unsigned int seed); +size_t afl_custom_fuzz(u8* buf, size_t buf_size, + u8* add_buf, size_t add_buf_size, + u8* mutated_out, size_t max_size); +size_t afl_custom_pre_save(u8* buf, size_t buf_size, u8** out_buf); +u32 afl_custom_init_trim(u8* buf, size_t buf_size); +void afl_custom_trim(u8** out_buf, size_t* out_buf_size); +u32 afl_custom_post_trim(u8 success); +``` + +Python: +```python +def init(seed): + pass + +def fuzz(buf, add_buf, max_size): + return mutated_out + +def pre_save(buf): + return out_buf + +def init_trim(buf): + return cnt + +def trim(): + return out_buf + +def post_trim(success): + return next_index +``` + +### Custom Mutation + +- `init` (optional): + + This method is called when AFL++ starts up and is used to seed RNG. + +- `fuzz` (required): + + This method performs custom mutations on a given input. It also accepts an + additional test case. + +- `pre_save` (optional): + + For some cases, the format of the mutated data returned from the custom + mutator is not suitable to directly execute the target with this input. + For example, when using libprotobuf-mutator, the data returned is in a + protobuf format which corresponds to a given grammar. In order to execute + the target, the protobuf data must be converted to the plain-text format expected by the target. In such scenarios, the user can define the + `pre_save` function. This function is then transforms the data into the + format expected by the API before executing the target. + + +### Trimming Support + +The generic trimming routines implemented in AFL++ can easily destroy the +structure of complex formats, possibly leading to a point where you have a lot +of test cases in the queue that your Python module cannot process anymore but +your target application still accepts. This is especially the case when your +target can process a part of the input (causing coverage) and then errors out +on the remaining input. + +In such cases, it makes sense to implement a custom trimming routine. The API +consists of multiple methods because after each trimming step, we have to go +back into the C code to check if the coverage bitmap is still the same for the +trimmed input. Here's a quick API description: + +- `init_trim` (optional): + + This method is called at the start of each trimming operation and receives + the initial buffer. It should return the amount of iteration steps possible + on this input (e.g. if your input has n elements and you want to remove them + one by one, return n, if you do a binary search, return log(n), and so on). + + If your trimming algorithm doesn't allow you to determine the amount of + (remaining) steps easily (esp. while running), then you can alternatively + return 1 here and always return 0 in `post_trim` until you are finished and + no steps remain. In that case, returning 1 in `post_trim` will end the + trimming routine. The whole current index/max iterations stuff is only used + to show progress. + +- `trim` (optional) + + This method is called for each trimming operation. It doesn't have any + arguments because we already have the initial buffer from `init_trim` and we + can memorize the current state in global variables. This can also save + reparsing steps for each iteration. It should return the trimmed input + buffer, where the returned data must not exceed the initial input data in + length. Returning anything that is larger than the original data (passed to + `init_trim`) will result in a fatal abort of AFL++. + +- `post_trim` (optional) + + This method is called after each trim operation to inform you if your + trimming step was successful or not (in terms of coverage). If you receive + a failure here, you should reset your input to the last known good state. + In any case, this method must return the next trim iteration index (from 0 + to the maximum amount of steps you returned in `init_trim`). + +Omitting any of three methods will cause the trimming to be disabled and trigger +a fallback to the builtin default trimming routine. + +### Environment Variables + +Optionally, the following environment variables are supported: + +- `AFL_PYTHON_ONLY` + + Disable all other mutation stages. This can prevent broken testcases + (those that your Python module can't work with anymore) to fill up your + queue. Best combined with a custom trimming routine (see below) because + trimming can cause the same test breakage like havoc and splice. + +- `AFL_DEBUG` + + When combined with `AFL_NO_UI`, this causes the C trimming code to emit additional messages about the performance and actions of your custom trimmer. Use this to see if it works :) + +## 3) Usage + +### Prerequisite + +For Python mutator, the python 3 or 2 development package is required. On +Debian/Ubuntu/Kali this can be done: + +```bash +sudo apt install python3-dev +# or +sudo apt install python-dev +``` + +Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects +Python 2 and 3 through `python-config` if it is in the PATH and compiles +`afl-fuzz` with the feature if available. + +Note: for some distributions, you might also need the package `python[23]-apt`. +In case your setup is different, set the necessary variables like this: +`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`. + +### Custom Mutator Preparation + +For C/C++ mutator, the source code must be compiled as a shared object: +```bash +gcc -shared -Wall -O3 example.c -o example.so +``` + +### Run + +C/C++ +```bash +export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so +afl-fuzz /path/to/program +``` + +Python +```bash +export PYTHONPATH=`dirname /full/path/to/example.py` +export AFL_PYTHON_MODULE=example +afl-fuzz /path/to/program +``` + +## 4) Example + +Please see [example.c](../examples/custom_mutators/example.c) and +[example.py](../examples/custom_mutators/example.py) + +## 5) Other Resources + +- AFL libprotobuf mutator + - [bruce30262/libprotobuf-mutator_fuzzing_learning](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator) + - [thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator) +- [XML Fuzzing@NullCon 2017](https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf) + - [A bug detected by AFL + XML-aware mutators](https://bugs.chromium.org/p/chromium/issues/detail?id=930663) diff --git a/docs/env_variables.md b/docs/env_variables.md index 83f5b7c0..d1cf6977 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,7 +231,7 @@ checks or alter some of the more exotic semantics of the tool: performed with the custom mutator. This feature allows to configure custom mutators which can be very helpful, e.g. fuzzing XML or other highly flexible structured input. - Please see [custom_mutator.md](custom_mutator.md). + Please see [custom_mutators.md](custom_mutators.md). - AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less precise), which can help when starting a session against a slow target. -- cgit 1.4.1