mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-14 02:58:08 +00:00
Merge branch 'dev' into text_inputs
This commit is contained in:
@ -1,5 +1,7 @@
|
|||||||
# How to submit a Pull Request to AFLplusplus
|
# How to submit a Pull Request to AFLplusplus
|
||||||
|
|
||||||
|
All contributions (pull requests) must be made against our `dev` branch.
|
||||||
|
|
||||||
Each modified source file, before merging, must be formatted.
|
Each modified source file, before merging, must be formatted.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -18,5 +20,5 @@ No camel case at all and use the AFL's macros wherever possible
|
|||||||
(e.g. WARNF, FATAL, MAP_SIZE, ...).
|
(e.g. WARNF, FATAL, MAP_SIZE, ...).
|
||||||
|
|
||||||
Remember that AFLplusplus has to build and run on many platforms, so
|
Remember that AFLplusplus has to build and run on many platforms, so
|
||||||
generalize your Makefiles (or your patches to our pre-existing Makefiles)
|
generalize your Makefiles/GNUmakefile (or your patches to our pre-existing
|
||||||
to be as much generic as possible.
|
Makefiles) to be as much generic as possible.
|
||||||
|
@ -56,8 +56,10 @@ endif
|
|||||||
|
|
||||||
ifneq "$(shell uname)" "Darwin"
|
ifneq "$(shell uname)" "Darwin"
|
||||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
|
ifndef SOURCE_DATE_EPOCH
|
||||||
#CFLAGS_OPT += -march=native
|
#CFLAGS_OPT += -march=native
|
||||||
SPECIAL_PERFORMANCE += -march=native
|
SPECIAL_PERFORMANCE += -march=native
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
# OS X does not like _FORTIFY_SOURCE=2
|
# OS X does not like _FORTIFY_SOURCE=2
|
||||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||||
@ -96,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64"
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||||
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
|
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations -Wno-unused-result \
|
||||||
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||||
|
|
||||||
@ -458,7 +460,7 @@ code-format:
|
|||||||
@#./.custom-format.py -i gcc_plugin/*.h
|
@#./.custom-format.py -i gcc_plugin/*.h
|
||||||
./.custom-format.py -i gcc_plugin/*.cc
|
./.custom-format.py -i gcc_plugin/*.cc
|
||||||
./.custom-format.py -i custom_mutators/*/*.c
|
./.custom-format.py -i custom_mutators/*/*.c
|
||||||
./.custom-format.py -i custom_mutators/*/*.h
|
@#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-(
|
||||||
./.custom-format.py -i examples/*/*.c
|
./.custom-format.py -i examples/*/*.c
|
||||||
./.custom-format.py -i examples/*/*.h
|
./.custom-format.py -i examples/*/*.h
|
||||||
./.custom-format.py -i test/*.c
|
./.custom-format.py -i test/*.c
|
||||||
|
826
README.md
826
README.md
@ -1,4 +1,4 @@
|
|||||||
# american fuzzy lop plus plus (afl++)
|
# American Fuzzy Lop plus plus (afl++)
|
||||||
|
|
||||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||||
|
|
||||||
@ -8,61 +8,36 @@
|
|||||||
|
|
||||||
Github Version: 2.66d
|
Github Version: 2.66d
|
||||||
|
|
||||||
includes all necessary/interesting changes from Google's afl 2.56b
|
|
||||||
|
|
||||||
Originally developed by Michal "lcamtuf" Zalewski.
|
|
||||||
|
|
||||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||||
|
|
||||||
afl++ is maintained by:
|
afl++ is maintained by:
|
||||||
* Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
|
||||||
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>,
|
|
||||||
* Andrea Fioraldi <andreafioraldi@gmail.com> and
|
|
||||||
* Dominik Maier <mail@dmnk.co>.
|
|
||||||
|
|
||||||
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
|
* Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
||||||
it is unlikely to receive any notable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
|
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||||
|
* Andrea Fioraldi <andreafioraldi@gmail.com> and
|
||||||
|
* Dominik Maier <mail@dmnk.co>.
|
||||||
|
|
||||||
## The enhancements compared to the original stock afl
|
Originally developed by Michal "lcamtuf" Zalewski.
|
||||||
|
|
||||||
Many improvements were made over the official afl release - which did not
|
afl++ is a superiour fork to Google's afl - more speed, more and better
|
||||||
get any feature improvements since November 2017.
|
mutations, more and better instrumentation, custom module support, etc.
|
||||||
|
|
||||||
Among other changes afl++ has a more performant llvm_mode, supports
|
## Contents
|
||||||
llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU,
|
|
||||||
better *BSD and Android support and much, much more.
|
|
||||||
|
|
||||||
Additionally the following features and patches have been integrated:
|
1. [Features](#important-features-of-afl)
|
||||||
|
2. [How to compile and install afl++](#building-and-installing-afl)
|
||||||
|
3. [How to fuzz a target](#how-to-fuzz-with-afl)
|
||||||
|
4. [Fuzzing binary-only targets](#fuzzing-binary-only-targets)
|
||||||
|
5. [Good examples and writeups of afl++ usages](#good-examples-and-writeups)
|
||||||
|
6. [Branches](#branches)
|
||||||
|
7. [Want to help?](#help-wanted)
|
||||||
|
8. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
|
||||||
|
|
||||||
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
|
## Important features of afl++
|
||||||
|
|
||||||
* The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
|
afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 3.1
|
||||||
|
with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and
|
||||||
* InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
|
Android support and much, much, much more.
|
||||||
|
|
||||||
* C. Holler's afl-fuzz Python mutator module and llvm_mode instrument file support: [https://github.com/choller/afl](https://github.com/choller/afl)
|
|
||||||
|
|
||||||
* Custom mutator by a library (instead of Python) by kyakdan
|
|
||||||
|
|
||||||
* Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
|
||||||
|
|
||||||
* LAF-Intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
|
|
||||||
|
|
||||||
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
|
||||||
|
|
||||||
* Persistent mode and deferred forkserver for qemu_mode
|
|
||||||
|
|
||||||
* Win32 PE binary-only fuzzing with QEMU and Wine
|
|
||||||
|
|
||||||
* Radamsa mutator (as a custom mutator).
|
|
||||||
|
|
||||||
* QBDI mode to fuzz android native libraries via QBDI framework
|
|
||||||
|
|
||||||
* The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
|
|
||||||
|
|
||||||
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
|
|
||||||
|
|
||||||
A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
|
|
||||||
|
|
||||||
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
|
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
|
||||||
| ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
|
| ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
|
||||||
@ -75,23 +50,37 @@
|
|||||||
| InsTrim | | x | | | |
|
| InsTrim | | x | | | |
|
||||||
| Ngram prev_loc coverage | | x(6) | | | |
|
| Ngram prev_loc coverage | | x(6) | | | |
|
||||||
| Context coverage | | x | | | |
|
| Context coverage | | x | | | |
|
||||||
|
| Auto dictionary | | x(7) | | | |
|
||||||
| Snapshot LKM support | | x | | (x)(5) | |
|
| Snapshot LKM support | | x | | (x)(5) | |
|
||||||
|
|
||||||
neverZero:
|
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
|
||||||
|
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
|
||||||
|
3. partially via AFL_CODE_START/AFL_CODE_END
|
||||||
|
4. with pcguard mode and LTO mode for LLVM >= 11
|
||||||
|
5. upcoming, development in the branch
|
||||||
|
6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
|
||||||
|
7. only in LTO mode with LLVM >= 11
|
||||||
|
|
||||||
(1) default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
|
Among others, the following features and patches have been integrated:
|
||||||
|
|
||||||
(2) GCC creates non-performant code, hence it is disabled in gcc_plugin
|
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
||||||
|
* Persistent mode and deferred forkserver for qemu_mode
|
||||||
|
* Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
||||||
|
* The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
|
||||||
|
* Win32 PE binary-only fuzzing with QEMU and Wine
|
||||||
|
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
|
||||||
|
* The MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
|
||||||
|
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
|
||||||
|
* InsTrim, an effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
|
||||||
|
* C. Holler's afl-fuzz Python mutator module and llvm_mode instrument file support: [https://github.com/choller/afl](https://github.com/choller/afl)
|
||||||
|
* Custom mutator by a library (instead of Python) by kyakdan
|
||||||
|
* LAF-Intel/CompCov support for llvm_mode, qemu_mode and unicorn_mode (with enhanced capabilities)
|
||||||
|
* Radamsa and hongfuzz mutators (as custom mutators).
|
||||||
|
* QBDI mode to fuzz android native libraries via QBDI framework
|
||||||
|
|
||||||
(3) partially via AFL_CODE_START/AFL_CODE_END
|
A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
|
||||||
|
|
||||||
(4) Only for LLVM >= 11 and not all targets compile
|
So all in all this is the best-of afl that is out there :-)
|
||||||
|
|
||||||
(5) upcoming, development in the branch
|
|
||||||
|
|
||||||
(6) not compatible with LTO instrumentation and needs at least LLVM >= 4.1
|
|
||||||
|
|
||||||
So all in all this is the best-of afl that is currently out there :-)
|
|
||||||
|
|
||||||
For new versions and additional information, check out:
|
For new versions and additional information, check out:
|
||||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||||
@ -106,7 +95,7 @@
|
|||||||
|
|
||||||
The following branches exist:
|
The following branches exist:
|
||||||
|
|
||||||
* [master/trunk](https://github.com/AFLplusplus/AFLplusplus/) : stable state of afl++ - it is synced from dev from time to
|
* [stable/trunk](https://github.com/AFLplusplus/AFLplusplus/) : stable state of afl++ - it is synced from dev from time to
|
||||||
time when we are satisfied with it's stability
|
time when we are satisfied with it's stability
|
||||||
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
|
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
|
||||||
checkout which does not compile or has a bug. *We only accept PRs in dev!!*
|
checkout which does not compile or has a bug. *We only accept PRs in dev!!*
|
||||||
@ -115,7 +104,7 @@
|
|||||||
|
|
||||||
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
|
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
|
||||||
|
|
||||||
## Google Summer of Code 2020 (and any other students and enthusiast developers)
|
## Help wanted
|
||||||
|
|
||||||
We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
|
We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
|
||||||
|
|
||||||
@ -140,7 +129,7 @@ hence afl-clang-lto is available!) or just pull directly from the docker hub:
|
|||||||
docker pull aflplusplus/aflplusplus
|
docker pull aflplusplus/aflplusplus
|
||||||
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
|
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
|
||||||
```
|
```
|
||||||
This container is automatically generated when a push to master happens.
|
This image is automatically generated when a push to master happens.
|
||||||
You will find your target source code in /src in the container.
|
You will find your target source code in /src in the container.
|
||||||
|
|
||||||
If you want to build afl++ yourself you have many options.
|
If you want to build afl++ yourself you have many options.
|
||||||
@ -151,11 +140,11 @@ sudo apt install build-essential libtool-bin python3-dev automake flex bison lib
|
|||||||
make distrib
|
make distrib
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
It is recommended to install the newest available gcc and clang and llvm-dev
|
It is recommended to install the newest available gcc, clang and llvm-dev
|
||||||
possible in your distribution!
|
possible in your distribution!
|
||||||
|
|
||||||
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
|
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
|
||||||
more. If you just want plain afl then do "make all", however compiling and
|
more. If you just want plain afl++ then do "make all", however compiling and
|
||||||
using at least llvm_mode is highly recommended for much better results -
|
using at least llvm_mode is highly recommended for much better results -
|
||||||
hence in this case
|
hence in this case
|
||||||
|
|
||||||
@ -197,6 +186,472 @@ These build options exist:
|
|||||||
|
|
||||||
e.g.: make ASAN_BUILD=1
|
e.g.: make ASAN_BUILD=1
|
||||||
|
|
||||||
|
## Good examples and writeups
|
||||||
|
|
||||||
|
Here are some good writeups to show how to effectively use AFL++:
|
||||||
|
|
||||||
|
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
|
||||||
|
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
|
||||||
|
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
|
||||||
|
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
|
||||||
|
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
|
||||||
|
|
||||||
|
If you are interested in fuzzing structured data (where you define what the
|
||||||
|
structure is), these links have you covered:
|
||||||
|
* Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
|
||||||
|
* libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
||||||
|
* libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
||||||
|
|
||||||
|
If you find other good ones, please send them to us :-)
|
||||||
|
|
||||||
|
## How to fuzz with afl++
|
||||||
|
|
||||||
|
The following describes how to fuzz with a target if source code is available.
|
||||||
|
If you have a binary-only target please skip to [#Instrumenting binary-only apps](#Instrumenting binary-only apps)
|
||||||
|
|
||||||
|
Fuzzing source code is a two step process.
|
||||||
|
|
||||||
|
1. compile the target with a special compiler that prepares the target to be
|
||||||
|
fuzzed efficiently. This step is called "instrumenting a target".
|
||||||
|
2. Prepare the fuzzing by selecting and optimizing the input corpus for the
|
||||||
|
target.
|
||||||
|
3. perform the fuzzing of the target by randomly mutating input and assessing
|
||||||
|
if a generated input was processed in a new path in the target binary
|
||||||
|
|
||||||
|
### 1. Instrumenting that target
|
||||||
|
|
||||||
|
#### a) Selecting the best afl++ compiler for instrumenting the target
|
||||||
|
|
||||||
|
afl++ comes with different compilers and instrumentation options.
|
||||||
|
The following evaluation flow will help you to select the best possible.
|
||||||
|
|
||||||
|
It is highly recommended to have the newest llvm version possible installed,
|
||||||
|
anything below 9 is not recommended.
|
||||||
|
|
||||||
|
```
|
||||||
|
+--------------------------------+
|
||||||
|
| clang/clang++ 11+ is available | --> use afl-clang-lto and afl-clang-lto++
|
||||||
|
+--------------------------------+ see [llvm/README.lto.md](llvm/README.lto.md)
|
||||||
|
|
|
||||||
|
| if not, or if the target fails with with afl-clang-lto/++
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+---------------------------------+
|
||||||
|
| clang/clang++ 3.3+ is available | --> use afl-clang-fast and afl-clang-fast++
|
||||||
|
+---------------------------------+ see [llvm/README.md](llvm/README.md)
|
||||||
|
|
|
||||||
|
| if not, or if the target fails with afl-clang-fast/++
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+--------------------------------+
|
||||||
|
| if you want to instrument only | -> use afl-gcc-fast and afl-gcc-fast++
|
||||||
|
| parts of the target | see [gcc_plugin/README.md](gcc_plugin/README.md) and
|
||||||
|
+--------------------------------+ [gcc_plugin/README.instrument_file.md](gcc_plugin/README.instrument_file.md)
|
||||||
|
|
|
||||||
|
| if not, or if you do not have a gcc with plugin support
|
||||||
|
|
|
||||||
|
v
|
||||||
|
use afl-gcc and afl-g++
|
||||||
|
```
|
||||||
|
|
||||||
|
Clickable README links for the chosen compiler:
|
||||||
|
|
||||||
|
* [afl-clang-lto](llvm/README.lto.md)
|
||||||
|
* [afl-clang-fast](llvm/README.md)
|
||||||
|
* [afl-gcc-fast](gcc_plugin/README.md)
|
||||||
|
* afl-gcc has no README as it has no features
|
||||||
|
|
||||||
|
#### b) Selecting instrumentation options
|
||||||
|
|
||||||
|
The following options are available when you instrument with afl-clang-fast or
|
||||||
|
afl-clang-lto:
|
||||||
|
|
||||||
|
* Splitting integer, string, float and switch compares so afl++ can easier
|
||||||
|
solve these. This is an important option if you do not have a very good
|
||||||
|
good and large input corpus. This technique is called laf-intel or COMPCOV.
|
||||||
|
To use this set the following environment variable before compiling the
|
||||||
|
target: `export AFL_LLVM_LAF_ALL=1`
|
||||||
|
You can read more about this in [llvm/README.laf-intel.md](llvm/README.laf-intel.md)
|
||||||
|
* A different technique is to instrument the target so that any compare values
|
||||||
|
in the target are sent to afl++ which then tries to put this value into the
|
||||||
|
fuzzing data at different locations. This technique is very fast and good -
|
||||||
|
if the target does not transform input data before comparison. Therefore
|
||||||
|
technique is called `input to state` or `redqueen`.
|
||||||
|
If you want to use this technique, then you have to compile the target
|
||||||
|
twice, once specifically with/for this mode.
|
||||||
|
You can read more about this in [llvm_mode/README.cmplog.md](llvm_mode/README.cmplog.md)
|
||||||
|
|
||||||
|
If you use afl-clang-fast, afl-clang-lto or afl-gcc-fast you have the option to
|
||||||
|
selectivly only instrument parts of the target that you are interested in:
|
||||||
|
|
||||||
|
* To instrument only those parts of the target that you are interested in
|
||||||
|
create a file with all the filenames of the source code that should be
|
||||||
|
instrumented.
|
||||||
|
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if either the clang
|
||||||
|
version is < 7 or the CLASSIC instrumentation is used - just put one
|
||||||
|
filename per line, no directory information necessary, and set
|
||||||
|
`export AFL_LLVM_INSTRUMENT_FILE=yourfile.txt`
|
||||||
|
see [llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md)
|
||||||
|
For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the
|
||||||
|
llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html)
|
||||||
|
|
||||||
|
There are many more options and modes available however these are most of the
|
||||||
|
time less effective. See:
|
||||||
|
* [llvm_mode/README.ctx.md](llvm_mode/README.ctx.md)
|
||||||
|
* [llvm_mode/README.ngram.md](llvm_mode/README.ngram.md)
|
||||||
|
* [llvm_mode/README.instrim.md](llvm_mode/README.instrim.md)
|
||||||
|
* [llvm_mode/README.neverzero.md](llvm_mode/README.neverzero.md)
|
||||||
|
|
||||||
|
#### c) Modify the target
|
||||||
|
|
||||||
|
If the target has features that makes fuzzing more difficult, e.g.
|
||||||
|
checksums, HMAC etc. then modify the source code so that this is
|
||||||
|
removed.
|
||||||
|
This can even be done for productional source code be eliminating
|
||||||
|
these checks within this specific defines:
|
||||||
|
|
||||||
|
```
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
// say that the checksum or HMAC was fine - or whatever is required
|
||||||
|
// to eliminate the need for the fuzzer to guess the right checksum
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
#### d) Instrument the target
|
||||||
|
|
||||||
|
In this step the target source code is compiled so that it can be fuzzed.
|
||||||
|
|
||||||
|
Basically you have to tell the target build system that the selected afl++
|
||||||
|
compiler is used. Also - if possible - you should always configure the
|
||||||
|
build system that the target is compiled statically and not dynamically.
|
||||||
|
How to do this is described below.
|
||||||
|
|
||||||
|
Then build the target. (Usually with `make`)
|
||||||
|
|
||||||
|
##### configure
|
||||||
|
|
||||||
|
For `configure` build systems this is usually done by:
|
||||||
|
`CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared`
|
||||||
|
|
||||||
|
Note that if you using the (better) afl-clang-lto compiler you also have to
|
||||||
|
AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
|
||||||
|
described in [llvm/README.lto.md](llvm/README.lto.md)
|
||||||
|
|
||||||
|
##### cmake
|
||||||
|
|
||||||
|
For `configure` build systems this is usually done by:
|
||||||
|
`mkdir build; cd build; CC=afl-clang-fast CXX=afl-clang-fast++ cmake ..`
|
||||||
|
|
||||||
|
Some cmake scripts require something like `-DCMAKE_CC=... -DCMAKE_CXX=...`
|
||||||
|
or `-DCMAKE_C_COMPILER=... DCMAKE_CPP_COMPILER=...` instead.
|
||||||
|
|
||||||
|
Note that if you using the (better) afl-clang-lto compiler you also have to
|
||||||
|
AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
|
||||||
|
described in [llvm/README.lto.md](llvm/README.lto.md)
|
||||||
|
|
||||||
|
##### other build systems or if configure/cmake didn't work
|
||||||
|
|
||||||
|
Sometimes cmake and configure do not pick up the afl++ compiler, or the
|
||||||
|
ranlib/ar that is needed - because this was just not foreseen by the developer
|
||||||
|
of the target. Or they have non-standard options. Figure out if there is a
|
||||||
|
non-standard way to set this, otherwise set the build normally and edit the
|
||||||
|
generated build environment afterwards by hand to point to the right compiler
|
||||||
|
(and/or ranlib and ar).
|
||||||
|
|
||||||
|
#### d) Better instrumentation
|
||||||
|
|
||||||
|
If you just fuzz a target program as-is you are wasting a great opportunity for
|
||||||
|
much more fuzzing speed.
|
||||||
|
|
||||||
|
This requires the usage of afl-clang-lto or afl-clang-fast
|
||||||
|
|
||||||
|
This is the so-called `persistent mode`, which is much, much faster but
|
||||||
|
requires that you code a source file that is specifically calling the target
|
||||||
|
functions that you want to fuzz, plus a few specific afl++ functions around
|
||||||
|
it. See [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) for details.
|
||||||
|
|
||||||
|
Basically if you do not fuzz a target in persistent mode then you are just
|
||||||
|
doing it for a hobby and not professionally :-)
|
||||||
|
|
||||||
|
### 2. Preparing the fuzzing
|
||||||
|
|
||||||
|
As you fuzz the target with mutated input, having as diverse inputs for the
|
||||||
|
target as possible improves the efficiency a lot.
|
||||||
|
|
||||||
|
#### a) Collect inputs
|
||||||
|
Try to gather valid inputs for the target from wherever you can. E.g. if it
|
||||||
|
the PNG picture format try to find as many png files as possible, e.g. from
|
||||||
|
reported bugs, test suites, random downloads from the internet, unit test
|
||||||
|
case data - from all kind of PNG software.
|
||||||
|
|
||||||
|
If the input is not known files, you can also modify a target program to write
|
||||||
|
away normal data it receives and processes to a file and use these.
|
||||||
|
|
||||||
|
#### b) Making the input corpus unique
|
||||||
|
|
||||||
|
Use the afl++ tool `afl-cmin` to remove inputs from the corpus that do not
|
||||||
|
use a different paths in the target.
|
||||||
|
Put all files from step a) into one directory, e.g. INPUTS.
|
||||||
|
|
||||||
|
Put all the files from step a)
|
||||||
|
|
||||||
|
If the target program is to be called by fuzzing as `bin/target -d INPUTFILE`
|
||||||
|
the run afl-cmin like this:
|
||||||
|
`afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -d @@`
|
||||||
|
Note that the INPUTFILE that the target program would read has to be set as `@@`.
|
||||||
|
|
||||||
|
If the target reads from stdin instead, just omit the `@@` as this is the
|
||||||
|
default.
|
||||||
|
|
||||||
|
#### b) Minimizing all corpus files
|
||||||
|
|
||||||
|
The shorter the input files are so that they still traverse the same path
|
||||||
|
within the target, the better the fuzzing will be. This is done with `afl-tmin`
|
||||||
|
however it is a long processes as this has to be done for every file:
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir input
|
||||||
|
cd INPUTS_UNIQUE
|
||||||
|
for i in *; do
|
||||||
|
afl-tmin -i "$i" -o "../input/$i" -- bin/target -d @@
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be parallelized, e.g. with `parallel`
|
||||||
|
|
||||||
|
#### c) done!
|
||||||
|
|
||||||
|
The INPUTS_UNIQUE/ directory from step a) - or even better if you minimized the
|
||||||
|
corpus in step b) then the files in input/ is then the input corpus directory
|
||||||
|
to be used in fuzzing! :-)
|
||||||
|
|
||||||
|
### Fuzzing the target
|
||||||
|
|
||||||
|
In this final step we fuzz the target.
|
||||||
|
There are not that many useful options to run the target - unless you want to
|
||||||
|
use many CPU cores/threads for the fuzzing, which will make the fuzzing much
|
||||||
|
more useful.
|
||||||
|
|
||||||
|
If you just use one CPU for fuzzing, then you are fuzzing just for fun and not
|
||||||
|
seriously :-)
|
||||||
|
|
||||||
|
#### a) running afl-fuzz
|
||||||
|
|
||||||
|
Before to do even a test run of afl-fuzz execute `sudo afl-system-config` (on
|
||||||
|
the host if you execute afl-fuzz in a docker container). This reconfigured the
|
||||||
|
system for optimal speed - which afl-fuzz checks and bails otherwise.
|
||||||
|
Set `export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this if you cannot run
|
||||||
|
afl-system-config with root privileges on the host for whatever reason.
|
||||||
|
|
||||||
|
If you have an input corpus from step 2 then specify this directory with the `-i`
|
||||||
|
option. Otherwise create a new directory and create a file with any content
|
||||||
|
in there.
|
||||||
|
|
||||||
|
If you do not want anything special, the defaults are already the usual best,
|
||||||
|
hence all you need (from the example in 2a):
|
||||||
|
`afl-fuzz -i input -o output -- bin/target -d @@`
|
||||||
|
Note that the directory specified with -o will be created if it does not exist.
|
||||||
|
|
||||||
|
If you need to stop and re-start the fuzzing, use the same command line option
|
||||||
|
and switch the input directory with a dash (`-`):
|
||||||
|
`afl-fuzz -i - -o output -- bin/target -d @@`
|
||||||
|
|
||||||
|
Note that afl-fuzz enforces memory limits to prevent the system to run out
|
||||||
|
of memory. By default this is 50MB for a process. If this is too little for
|
||||||
|
the target (which can can usually see that afl-fuzz bails with the message
|
||||||
|
that it could not connect to the forkserver), then you can increase this
|
||||||
|
with the `-m` option, the value is in MB. To disable any memory limits
|
||||||
|
(beware!) set `-m 0` - which is usually required for ASAN compiled targets.
|
||||||
|
|
||||||
|
Adding a dictionary helpful. See the [dictionaries/](dictionaries/) if
|
||||||
|
something is already included for your data format, and tell afl-fuzz to load
|
||||||
|
that dictionary by adding `-x dicationaries/FORMAT.dict`. With afl-clang-lto
|
||||||
|
you have an autodictionary generation for which you need to do nothing except
|
||||||
|
to use afl-clang-lto as the compiler. You also have the option to generate
|
||||||
|
a dictionary yourself, see [libtokencap/README.md](libtokencap/README.md)
|
||||||
|
|
||||||
|
afl-fuzz has a variety of options that help to workaround target quirks like
|
||||||
|
specific locations for the input file (`-f`), not performing deterministic
|
||||||
|
fuzzing (`-d`) and many more. Check out `afl-fuzz -h`.
|
||||||
|
|
||||||
|
afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C.
|
||||||
|
|
||||||
|
When you start afl-fuzz you will see a user interface that shows what the status
|
||||||
|
is:
|
||||||
|

|
||||||
|
|
||||||
|
All labels are explained in [docs/status_screen.md](docs/status_screen.md)
|
||||||
|
|
||||||
|
#### b) Using multiple cores/threads
|
||||||
|
|
||||||
|
If you want to seriously fuzz then use as many cores/threads as possible to
|
||||||
|
fuzz your target.
|
||||||
|
|
||||||
|
On the same machine - due to the nature how afl++ works - there is a maximum
|
||||||
|
number of CPU cores/threads that are useful, more and the overall performance
|
||||||
|
degrades instead. This value depends on the target and the limit is between 48
|
||||||
|
and 96 cores/threads per machine.
|
||||||
|
|
||||||
|
There should be one main fuzzer (`-M main` option) and as many secondary
|
||||||
|
fuzzers (eg `-S variant1`) as you cores that you use.
|
||||||
|
Every -M/-S entry needs a unique name (that can be whatever), however the same
|
||||||
|
-o output directory location has to be used for all.
|
||||||
|
|
||||||
|
For every secondary there should be a variation, e.g.:
|
||||||
|
* one should fuzz the target that was compiled differently: with sanitizers
|
||||||
|
activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
|
||||||
|
export AFL_USE_CFISAN=1 ; `
|
||||||
|
* one should fuzz the target with CMPLOG/redqueen (see above)
|
||||||
|
* At 1-2 should fuzz a target compiled with laf-intel/COMPCOV (see above).
|
||||||
|
|
||||||
|
All other secondaries should be:
|
||||||
|
* 1/2 with MOpt option enabled: `-L 0`
|
||||||
|
* run with a different power schedule, available are:
|
||||||
|
`explore (default), fast, coe, lin, quad, exploit, mmopt, rare, seek`
|
||||||
|
which you can set with e.g. `-p seek`
|
||||||
|
|
||||||
|
You can also use different fuzzers.
|
||||||
|
If you are using afl spinoffs or afl conforming fuzzers, then just use the
|
||||||
|
same -o directory and give it a unique `-S` name.
|
||||||
|
Examples are e.g.:
|
||||||
|
* [Angora](https://github.com/AngoraFuzzer/Angora)
|
||||||
|
* [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
|
||||||
|
* [AFLsmart](https://github.com/aflsmart/aflsmart)
|
||||||
|
* [FairFuzz](https://github.com/carolemieux/afl-rb)
|
||||||
|
* [Neuzz](https://github.com/Dongdongshe/neuzz)
|
||||||
|
|
||||||
|
A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL)
|
||||||
|
|
||||||
|
However you can also sync afl++ with honggfuzz, libfuzzer, entropic, etc.
|
||||||
|
Just show the main fuzzer (-M) with the `-F` option where the queue
|
||||||
|
directory of these other fuzzers are, e.g. `-F /src/target/honggfuzz`
|
||||||
|
|
||||||
|
#### c) The status of the fuzz campaign
|
||||||
|
|
||||||
|
afl++ comes with the `afl-whatsup` script to show the status of fuzzing
|
||||||
|
campaign.
|
||||||
|
|
||||||
|
Just supply the directory that afl-fuzz is given with the -o option and
|
||||||
|
you will see a detailed status of every fuzzer in that campaign plus
|
||||||
|
a summary.
|
||||||
|
|
||||||
|
To have only the summary use the `-s` switch e.g.: `afl-whatsup -s output/`
|
||||||
|
|
||||||
|
#### d) Checking the coverage of the fuzzing
|
||||||
|
|
||||||
|
The `paths found` value is a bad indicator how good the coverage is.
|
||||||
|
It is better to check out the exact lines of code that have been reached -
|
||||||
|
and which have not been found so far.
|
||||||
|
|
||||||
|
An "easy" helper script for this is [https://github.com/vanhauser-thc/afl-cov](https://github.com/vanhauser-thc/afl-cov),
|
||||||
|
just follow the README of that seperate project.
|
||||||
|
|
||||||
|
If you see that an important area or a feature has not been covered so far then
|
||||||
|
try to find an input that is able to reach that and start a new secondary in
|
||||||
|
that fuzzing campaign with that seed as input, let it run for a few minutes,
|
||||||
|
then terminate it. The main node will pick it up and make it available to the
|
||||||
|
other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
|
||||||
|
free core.
|
||||||
|
|
||||||
|
#### e) How long to fuzz a target?
|
||||||
|
|
||||||
|
This is a difficult question.
|
||||||
|
Basically if no new path is found for a long time (e.g. for a day or a week)
|
||||||
|
then you can expect that your fuzzing won't be fruitful anymore.
|
||||||
|
However often this just means that you should switch out secondaries for
|
||||||
|
others, e.g. custom mutator modules, sync to very different fuzzers, etc.
|
||||||
|
|
||||||
|
### The End
|
||||||
|
|
||||||
|
Check out the [docs/FAQ](docs/FAQ.md) if it maybe answers your question (that
|
||||||
|
you might not even have known you had ;-) ).
|
||||||
|
|
||||||
|
This is basically all you need to know to professionally run fuzzing campaigns.
|
||||||
|
If you want to know more, the rest of this README and the tons of texts in
|
||||||
|
[docs/](docs/) will have you covered.
|
||||||
|
|
||||||
|
Note that there are also a lot of tools out there that help fuzzing with afl++
|
||||||
|
(some might be deprecated or unsupported):
|
||||||
|
|
||||||
|
Minimization of test cases:
|
||||||
|
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin that tries to speed up the process of the minimization of test case by using many CPU cores.
|
||||||
|
* [afl-ddmin-mod](https://github.com/MarkusTeufelberger/afl-ddmin-mod) - a variation of afl-tmin based on the ddmin algorithm.
|
||||||
|
* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast utility for minimizing test cases by Tavis Ormandy based on parallelization.
|
||||||
|
|
||||||
|
Distributed execution:
|
||||||
|
* [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing for AFL.
|
||||||
|
* [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing framework.
|
||||||
|
* [afl-launch](https://github.com/bnagy/afl-launch) - a tool for the execution of many AFL instances.
|
||||||
|
* [afl-mothership](https://github.com/afl-mothership/afl-mothership) - management and execution of many synchronized AFL fuzzers on AWS cloud.
|
||||||
|
* [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another script for running AFL in AWS.
|
||||||
|
|
||||||
|
Deployment, management, monitoring, reporting
|
||||||
|
* [afl-other-arch](https://github.com/shellphish/afl-other-arch) - is a set of patches and scripts for easily adding support for various non-x86 architectures for AFL.
|
||||||
|
* [afl-trivia](https://github.com/bnagy/afl-trivia) - a few small scripts to simplify the management of AFL.
|
||||||
|
* [afl-monitor](https://github.com/reflare/afl-monitor) - a script for monitoring AFL.
|
||||||
|
* [afl-manager](https://github.com/zx1340/afl-manager) - a web server on Python for managing multi-afl.
|
||||||
|
* [afl-remote](https://github.com/block8437/afl-remote) - a web server for the remote management of AFL instances.
|
||||||
|
|
||||||
|
Crash processing
|
||||||
|
* [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for automatic processing/analysis of crashes and reducing the number of test cases.
|
||||||
|
* [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) - another crash analyzer for AFL.
|
||||||
|
* [fuzzer-utils](https://github.com/ThePatrickStar/fuzzer-utils) - a set of scripts for the analysis of results.
|
||||||
|
* [atriage](https://github.com/Ayrx/atriage) - a simple triage tool.
|
||||||
|
* [afl-kit](https://github.com/kcwu/afl-kit) - afl-cmin on Python.
|
||||||
|
* [AFLize](https://github.com/d33tah/aflize) - a tool that automatically generates builds of debian packages suitable for AFL.
|
||||||
|
* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for working with input data.
|
||||||
|
|
||||||
|
## Fuzzing binary-only targets
|
||||||
|
|
||||||
|
When source code is *NOT* available, afl++ offers various support for fast,
|
||||||
|
on-the-fly instrumentation of black-box binaries.
|
||||||
|
|
||||||
|
### QEMU
|
||||||
|
|
||||||
|
For linux programs and it's libraries this is accomplished with a version of
|
||||||
|
QEMU running in the lesser-known "user space emulation" mode.
|
||||||
|
QEMU is a project separate from AFL, but you can conveniently build the
|
||||||
|
feature by doing:
|
||||||
|
```shell
|
||||||
|
cd qemu_mode
|
||||||
|
./build_qemu_support.sh
|
||||||
|
```
|
||||||
|
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
||||||
|
If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
|
||||||
|
The mode is approximately 2-5x slower than compile-time instrumentation, and is
|
||||||
|
less conducive to parallelization.
|
||||||
|
|
||||||
|
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
|
||||||
|
your binary, then you can use afl-fuzz normally and it will have twice
|
||||||
|
the speed compared to qemu_mode (but slower than persistent mode).
|
||||||
|
|
||||||
|
### Unicorn
|
||||||
|
|
||||||
|
For non-Linux binaries you can use afl++'s unicorn mode which can emulate
|
||||||
|
anything you want - for the price of speed and the user writing scripts.
|
||||||
|
See [unicorn_mode](unicorn_mode/README.md).
|
||||||
|
|
||||||
|
It can be easily build by:
|
||||||
|
```shell
|
||||||
|
cd unicorn_mode
|
||||||
|
./build_unicorn_support.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shared libraries
|
||||||
|
|
||||||
|
If the goal is to fuzz a dynamic library then there are two options available.
|
||||||
|
For both you need to write a small hardness that loads and calls the library.
|
||||||
|
Faster is the frida solution: [examples/afl_frida/README.md](examples/afl_frida/README.md)
|
||||||
|
|
||||||
|
Another, less precise and slower option is using ptrace with debugger interrupt
|
||||||
|
instrumentation: [examples/afl_untracer/README.md](examples/afl_untracer/README.md)
|
||||||
|
|
||||||
|
### More
|
||||||
|
|
||||||
|
A more comprehensive description of these and other options can be found in
|
||||||
|
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
|
||||||
|
|
||||||
## Challenges of guided fuzzing
|
## Challenges of guided fuzzing
|
||||||
|
|
||||||
Fuzzing is one of the most powerful and proven strategies for identifying
|
Fuzzing is one of the most powerful and proven strategies for identifying
|
||||||
@ -223,8 +678,7 @@ All these methods are extremely promising in experimental settings, but tend
|
|||||||
to suffer from reliability and performance problems in practical uses - and
|
to suffer from reliability and performance problems in practical uses - and
|
||||||
currently do not offer a viable alternative to "dumb" fuzzing techniques.
|
currently do not offer a viable alternative to "dumb" fuzzing techniques.
|
||||||
|
|
||||||
|
## Background: The afl-fuzz approach
|
||||||
## The afl-fuzz approach
|
|
||||||
|
|
||||||
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
|
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
|
||||||
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
|
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
|
||||||
@ -262,141 +716,7 @@ closed-source tools.
|
|||||||
The fuzzer is thoroughly tested to deliver out-of-the-box performance far
|
The fuzzer is thoroughly tested to deliver out-of-the-box performance far
|
||||||
superior to blind fuzzing or coverage-only tools.
|
superior to blind fuzzing or coverage-only tools.
|
||||||
|
|
||||||
|
## Help: Choosing initial test cases
|
||||||
## Instrumenting programs for use with AFL
|
|
||||||
|
|
||||||
PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
|
|
||||||
instead of afl-gcc/afl-g++ is much faster and has many cool features.
|
|
||||||
See llvm_mode/ - however few code does not compile with llvm.
|
|
||||||
We support llvm versions 3.4 to 11.
|
|
||||||
|
|
||||||
When source code is available, instrumentation can be injected by a companion
|
|
||||||
tool that works as a drop-in replacement for gcc or clang in any standard build
|
|
||||||
process for third-party code.
|
|
||||||
|
|
||||||
The instrumentation has a fairly modest performance impact; in conjunction with
|
|
||||||
other optimizations implemented by afl-fuzz, most programs can be fuzzed as fast
|
|
||||||
or even faster than possible with traditional tools.
|
|
||||||
|
|
||||||
The correct way to recompile the target program may vary depending on the
|
|
||||||
specifics of the build process, but a nearly-universal approach would be:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
CC=/path/to/afl/afl-gcc ./configure
|
|
||||||
make clean all
|
|
||||||
```
|
|
||||||
|
|
||||||
For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.
|
|
||||||
|
|
||||||
The clang wrappers (afl-clang and afl-clang++) can be used in the same way;
|
|
||||||
clang users may also opt to leverage a higher-performance instrumentation mode,
|
|
||||||
as described in [llvm_mode/README.md](llvm_mode/README.md).
|
|
||||||
Clang/LLVM has a much better performance and works with LLVM version 3.4 to 11.
|
|
||||||
|
|
||||||
Using the LAF Intel performance enhancements are also recommended, see
|
|
||||||
[llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md)
|
|
||||||
|
|
||||||
Using partial instrumentation is also recommended, see
|
|
||||||
[llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md)
|
|
||||||
|
|
||||||
When testing libraries, you need to find or write a simple program that reads
|
|
||||||
data from stdin or from a file and passes it to the tested library. In such a
|
|
||||||
case, it is essential to link this executable against a static version of the
|
|
||||||
instrumented library or to make sure that the correct .so file is loaded at
|
|
||||||
runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static
|
|
||||||
build, usually possible via:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
CC=/path/to/afl/afl-gcc ./configure --disable-shared
|
|
||||||
```
|
|
||||||
|
|
||||||
Setting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to
|
|
||||||
automatically enable code hardening options that make it easier to detect
|
|
||||||
simple memory bugs. Libdislocator, a helper library included with AFL (see
|
|
||||||
[libdislocator/README.md](libdislocator/README.md)) can help uncover heap corruption issues, too.
|
|
||||||
|
|
||||||
PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md)
|
|
||||||
file for important caveats.
|
|
||||||
|
|
||||||
|
|
||||||
## Instrumenting binary-only apps
|
|
||||||
|
|
||||||
When source code is *NOT* available, the fuzzer offers experimental support for
|
|
||||||
fast, on-the-fly instrumentation of black-box binaries. This is accomplished
|
|
||||||
with a version of QEMU running in the lesser-known "user space emulation" mode.
|
|
||||||
|
|
||||||
QEMU is a project separate from AFL, but you can conveniently build the
|
|
||||||
feature by doing:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd qemu_mode
|
|
||||||
./build_qemu_support.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
|
||||||
|
|
||||||
If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
|
|
||||||
|
|
||||||
The mode is approximately 2-5x slower than compile-time instrumentation, is
|
|
||||||
less conducive to parallelization, and may have some other quirks.
|
|
||||||
|
|
||||||
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
|
|
||||||
your binary, then you can use afl-fuzz normally and it will have twice
|
|
||||||
the speed compared to qemu_mode.
|
|
||||||
|
|
||||||
A more comprehensive description of these and other options can be found in
|
|
||||||
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
|
|
||||||
|
|
||||||
## Good examples and writeups
|
|
||||||
|
|
||||||
Here are some good writeups to show how to effectively use AFL++:
|
|
||||||
|
|
||||||
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
|
|
||||||
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
|
|
||||||
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
|
|
||||||
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
|
|
||||||
|
|
||||||
If you are interested in fuzzing structured data (where you define what the
|
|
||||||
structure is), these links have you covered:
|
|
||||||
* Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
|
|
||||||
* libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
|
||||||
* libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
|
||||||
|
|
||||||
If you find other good ones, please send them to us :-)
|
|
||||||
|
|
||||||
## Power schedules
|
|
||||||
|
|
||||||
The power schedules were copied from Marcel Böhme's excellent AFLfast
|
|
||||||
implementation and expand on the ability to discover new paths and
|
|
||||||
therefore may increase the code coverage.
|
|
||||||
|
|
||||||
The available schedules are:
|
|
||||||
|
|
||||||
- explore (default, original AFL)
|
|
||||||
- exploit (original AFL)
|
|
||||||
- fast (AFLfast)
|
|
||||||
- coe (AFLfast)
|
|
||||||
- quad (AFLfast)
|
|
||||||
- lin (AFLfast)
|
|
||||||
- rare (afl++ experimental)
|
|
||||||
- mmopt (afl++ experimental)
|
|
||||||
- seek (afl++ experimental)
|
|
||||||
|
|
||||||
In parallel mode (-M/-S, several instances with the shared queue), we suggest to
|
|
||||||
run the main node using the explore or fast schedule (-p explore) and the secondary
|
|
||||||
nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast),
|
|
||||||
explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does
|
|
||||||
not perform well for a target, restart the secondary nodes with a different schedule.
|
|
||||||
|
|
||||||
In single mode, using -p fast is usually slightly more beneficial than the
|
|
||||||
default explore mode.
|
|
||||||
(We don't want to change the default behavior of afl, so "fast" has not been
|
|
||||||
made the default mode).
|
|
||||||
|
|
||||||
More details can be found in the paper published at the 23rd ACM Conference on
|
|
||||||
Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
|
|
||||||
|
|
||||||
## Choosing initial test cases
|
|
||||||
|
|
||||||
To operate correctly, the fuzzer requires one or more starting file that
|
To operate correctly, the fuzzer requires one or more starting file that
|
||||||
contains a good example of the input data normally expected by the targeted
|
contains a good example of the input data normally expected by the targeted
|
||||||
@ -416,45 +736,7 @@ PS. If a large corpus of data is available for screening, you may want to use
|
|||||||
the afl-cmin utility to identify a subset of functionally distinct files that
|
the afl-cmin utility to identify a subset of functionally distinct files that
|
||||||
exercise different code paths in the target binary.
|
exercise different code paths in the target binary.
|
||||||
|
|
||||||
|
## Help: Interpreting output
|
||||||
## Fuzzing binaries
|
|
||||||
|
|
||||||
The fuzzing process itself is carried out by the afl-fuzz utility. This program
|
|
||||||
requires a read-only directory with initial test cases, a separate place to
|
|
||||||
store its findings, plus a path to the binary to test.
|
|
||||||
|
|
||||||
For target binaries that accept input directly from stdin, the usual syntax is:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
|
|
||||||
```
|
|
||||||
|
|
||||||
For programs that take input from a file, use '@@' to mark the location in
|
|
||||||
the target's command line where the input file name should be placed. The
|
|
||||||
fuzzer will substitute this for you:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also use the -f option to have the mutated data written to a specific
|
|
||||||
file. This is useful if the program expects a particular file extension or so.
|
|
||||||
|
|
||||||
Non-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command
|
|
||||||
line) or in a traditional, blind-fuzzer mode (specify -n).
|
|
||||||
|
|
||||||
You can use -t and -m to override the default timeout and memory limit for the
|
|
||||||
executed process; rare examples of targets that may need these settings touched
|
|
||||||
include compilers and video decoders.
|
|
||||||
|
|
||||||
Tips for optimizing fuzzing performance are discussed in [perf_tips.md](docs/perf_tips.md).
|
|
||||||
|
|
||||||
Note that afl-fuzz starts by performing an array of deterministic fuzzing
|
|
||||||
steps, which can take several days, but tend to produce neat test cases. If you
|
|
||||||
want quick & dirty results right away - akin to zzuf and other traditional
|
|
||||||
fuzzers - add the -d option to the command line.
|
|
||||||
|
|
||||||
## Interpreting output
|
|
||||||
|
|
||||||
See the [docs/status_screen.md](docs/status_screen.md) file for information on
|
See the [docs/status_screen.md](docs/status_screen.md) file for information on
|
||||||
how to interpret the displayed stats and monitor the health of the process. Be
|
how to interpret the displayed stats and monitor the health of the process. Be
|
||||||
@ -514,53 +796,7 @@ If you have gnuplot installed, you can also generate some pretty graphs for any
|
|||||||
active fuzzing task using afl-plot. For an example of how this looks like,
|
active fuzzing task using afl-plot. For an example of how this looks like,
|
||||||
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
|
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
|
||||||
|
|
||||||
## Parallelized fuzzing
|
## Help: Crash triage
|
||||||
|
|
||||||
Every instance of afl-fuzz takes up roughly one core. This means that on
|
|
||||||
multi-core systems, parallelization is necessary to fully utilize the hardware.
|
|
||||||
For tips on how to fuzz a common target on multiple cores or multiple networked
|
|
||||||
machines, please refer to [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md).
|
|
||||||
|
|
||||||
The parallel fuzzing mode also offers a simple way for interfacing AFL to other
|
|
||||||
fuzzers, to symbolic or concolic execution engines, and so forth; again, see the
|
|
||||||
last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips.
|
|
||||||
|
|
||||||
## Fuzzer dictionaries
|
|
||||||
|
|
||||||
By default, afl-fuzz mutation engine is optimized for compact data formats -
|
|
||||||
say, images, multimedia, compressed data, regular expression syntax, or shell
|
|
||||||
scripts. It is somewhat less suited for languages with particularly verbose and
|
|
||||||
redundant verbiage - notably including HTML, SQL, or JavaScript.
|
|
||||||
|
|
||||||
To avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to
|
|
||||||
seed the fuzzing process with an optional dictionary of language keywords,
|
|
||||||
magic headers, or other special tokens associated with the targeted data type
|
|
||||||
-- and use that to reconstruct the underlying grammar on the go:
|
|
||||||
|
|
||||||
[http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)
|
|
||||||
|
|
||||||
To use this feature, you first need to create a dictionary in one of the two
|
|
||||||
formats discussed in [dictionaries/README.md](dictionaries/README.md);
|
|
||||||
and then point the fuzzer to it via the -x option in the command line.
|
|
||||||
|
|
||||||
(Several common dictionaries are already provided in that subdirectory, too.)
|
|
||||||
|
|
||||||
There is no way to provide more structured descriptions of the underlying
|
|
||||||
syntax, but the fuzzer will likely figure out some of this based on the
|
|
||||||
instrumentation feedback alone. This actually works in practice, say:
|
|
||||||
|
|
||||||
[http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)
|
|
||||||
|
|
||||||
PS. Even when no explicit dictionary is given, afl-fuzz will try to extract
|
|
||||||
existing syntax tokens in the input corpus by watching the instrumentation
|
|
||||||
very closely during deterministic byte flips. This works for some types of
|
|
||||||
parsers and grammars but isn't nearly as good as the -x mode.
|
|
||||||
|
|
||||||
If a dictionary is really hard to come by, another option is to let AFL run
|
|
||||||
for a while and then use the token capture library that comes as a companion
|
|
||||||
utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md).
|
|
||||||
|
|
||||||
## Crash triage
|
|
||||||
|
|
||||||
The coverage-based grouping of crashes usually produces a small data set that
|
The coverage-based grouping of crashes usually produces a small data set that
|
||||||
can be quickly triaged manually or with a very simple GDB or Valgrind script.
|
can be quickly triaged manually or with a very simple GDB or Valgrind script.
|
||||||
@ -594,13 +830,13 @@ can be operated in a very simple way:
|
|||||||
|
|
||||||
The tool works with crashing and non-crashing test cases alike. In the crash
|
The tool works with crashing and non-crashing test cases alike. In the crash
|
||||||
mode, it will happily accept instrumented and non-instrumented binaries. In the
|
mode, it will happily accept instrumented and non-instrumented binaries. In the
|
||||||
non-crashing mode, the minimizer relies on standard AFL instrumentation to make
|
non-crashing mode, the minimizer relies on standard afl++ instrumentation to make
|
||||||
the file simpler without altering the execution path.
|
the file simpler without altering the execution path.
|
||||||
|
|
||||||
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
|
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
|
||||||
afl-fuzz.
|
afl-fuzz.
|
||||||
|
|
||||||
Another recent addition to AFL is the afl-analyze tool. It takes an input
|
Another tool in afl++ is the afl-analyze tool. It takes an input
|
||||||
file, attempts to sequentially flip bytes, and observes the behavior of the
|
file, attempts to sequentially flip bytes, and observes the behavior of the
|
||||||
tested program. It then color-codes the input based on which sections appear to
|
tested program. It then color-codes the input based on which sections appear to
|
||||||
be critical, and which are not; while not bulletproof, it can often offer quick
|
be critical, and which are not; while not bulletproof, it can often offer quick
|
||||||
@ -628,7 +864,8 @@ found by modifying the target programs to call abort() when say:
|
|||||||
Implementing these or similar sanity checks usually takes very little time;
|
Implementing these or similar sanity checks usually takes very little time;
|
||||||
if you are the maintainer of a particular package, you can make this code
|
if you are the maintainer of a particular package, you can make this code
|
||||||
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
|
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
|
||||||
shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).
|
shared with libfuzzer and honggfuzz) or `#ifdef __AFL_COMPILER` (this one is
|
||||||
|
just for AFL).
|
||||||
|
|
||||||
## Common-sense risks
|
## Common-sense risks
|
||||||
|
|
||||||
@ -642,7 +879,7 @@ tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
|
|||||||
for something to blow up.
|
for something to blow up.
|
||||||
|
|
||||||
- Targeted programs may end up erratically grabbing gigabytes of memory or
|
- Targeted programs may end up erratically grabbing gigabytes of memory or
|
||||||
filling up disk space with junk files. AFL tries to enforce basic memory
|
filling up disk space with junk files. afl++ tries to enforce basic memory
|
||||||
limits, but can't prevent each and every possible mishap. The bottom line
|
limits, but can't prevent each and every possible mishap. The bottom line
|
||||||
is that you shouldn't be fuzzing on systems where the prospect of data loss
|
is that you shouldn't be fuzzing on systems where the prospect of data loss
|
||||||
is not an acceptable risk.
|
is not an acceptable risk.
|
||||||
@ -663,7 +900,7 @@ tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
|
|||||||
|
|
||||||
Here are some of the most important caveats for AFL:
|
Here are some of the most important caveats for AFL:
|
||||||
|
|
||||||
- AFL detects faults by checking for the first spawned process dying due to
|
- afl++ detects faults by checking for the first spawned process dying due to
|
||||||
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
|
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
|
||||||
these signals may need to have the relevant code commented out. In the same
|
these signals may need to have the relevant code commented out. In the same
|
||||||
vein, faults in child processes spawned by the fuzzed target may evade
|
vein, faults in child processes spawned by the fuzzed target may evade
|
||||||
@ -692,9 +929,6 @@ Here are some of the most important caveats for AFL:
|
|||||||
Some useful tips for modifying network-based services can be also found at:
|
Some useful tips for modifying network-based services can be also found at:
|
||||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||||
|
|
||||||
- AFL doesn't output human-readable coverage data. If you want to monitor
|
|
||||||
coverage, use afl-cov from Michael Rash: [https://github.com/mrash/afl-cov](https://github.com/mrash/afl-cov)
|
|
||||||
|
|
||||||
- Occasionally, sentient machines rise against their creators. If this
|
- Occasionally, sentient machines rise against their creators. If this
|
||||||
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
|
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
|
||||||
|
|
||||||
@ -759,6 +993,6 @@ Thank you!
|
|||||||
Questions? Concerns? Bug reports? The contributors can be reached via
|
Questions? Concerns? Bug reports? The contributors can be reached via
|
||||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||||
|
|
||||||
There is also a mailing list for the afl project; to join, send a mail to
|
There is also a mailing list for the afl/afl++ project; to join, send a mail to
|
||||||
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse
|
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse archives
|
||||||
archives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users)
|
first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users)
|
||||||
|
5
TODO.md
5
TODO.md
@ -2,16 +2,13 @@
|
|||||||
|
|
||||||
## Roadmap 2.67+
|
## Roadmap 2.67+
|
||||||
|
|
||||||
- allow to sync against honggfuzz and libfuzzer
|
- expand on AFL_LLVM_INSTRUMENT_FILE to also support sancov allowlist format
|
||||||
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
|
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
|
||||||
- namespace for targets? e.g. network
|
|
||||||
- learn from honggfuzz (mutations, maybe ptrace?)
|
|
||||||
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||||
|
|
||||||
## Further down the road
|
## Further down the road
|
||||||
|
|
||||||
afl-fuzz:
|
afl-fuzz:
|
||||||
- ascii_only mode for mutation output - or use a custom mutator for this?
|
|
||||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||||
|
|
||||||
llvm_mode:
|
llvm_mode:
|
||||||
|
@ -68,7 +68,12 @@ else:
|
|||||||
argv = sys.argv[1:]
|
argv = sys.argv[1:]
|
||||||
for i in range(len(argv)):
|
for i in range(len(argv)):
|
||||||
if ".cur_input" in argv[i]:
|
if ".cur_input" in argv[i]:
|
||||||
argv[i] = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
|
# Get the Wine translated path using the winepath tool
|
||||||
|
arg_translated = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
|
||||||
|
# Remove the spurious LF at the end of the path
|
||||||
|
if len(arg_translated) > 0 and arg_translated[-1] == '\n':
|
||||||
|
arg_translated = arg_translated[:-1]
|
||||||
|
argv[i] = arg_translated
|
||||||
break
|
break
|
||||||
|
|
||||||
print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))
|
print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))
|
||||||
|
15
custom_mutators/honggfuzz/Makefile
Normal file
15
custom_mutators/honggfuzz/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
|
||||||
|
|
||||||
|
all: honggfuzz.so
|
||||||
|
|
||||||
|
honggfuzz.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c
|
||||||
|
$(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz.so honggfuzz.c mangle.c ../../src/afl-performance.c
|
||||||
|
|
||||||
|
update:
|
||||||
|
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.c
|
||||||
|
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.h
|
||||||
|
wget --unlink https://github.com/google/honggfuzz/raw/master/honggfuzz.h
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *~ *.so core
|
12
custom_mutators/honggfuzz/README.md
Normal file
12
custom_mutators/honggfuzz/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# custum mutator: honggfuzz mangle
|
||||||
|
|
||||||
|
this is the very good honggfuzz mutator in mangle.c as a custom mutator
|
||||||
|
module for afl++. It is the original mangle.c, mangle.h and honggfuzz.h
|
||||||
|
with a lot of mocking around it :-)
|
||||||
|
|
||||||
|
just type `make` to build
|
||||||
|
|
||||||
|
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/honggfuzz/honggfuzz.so afl-fuzz ...```
|
||||||
|
|
||||||
|
> Original repository: https://github.com/google/honggfuzz
|
||||||
|
> Source commit: d0fbcb0373c32436b8fb922e6937da93b17291f5
|
0
custom_mutators/honggfuzz/common.h
Normal file
0
custom_mutators/honggfuzz/common.h
Normal file
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||||
|
#define CUSTOM_MUTATOR_HELPERS
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "afl-fuzz.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define INITIAL_GROWTH_SIZE (64)
|
||||||
|
|
||||||
|
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||||
|
#define BUF_VAR(type, name) \
|
||||||
|
type * name##_buf; \
|
||||||
|
size_t name##_size;
|
||||||
|
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
|
||||||
|
#define BUF_PARAMS(struct, name) \
|
||||||
|
(void **)&struct->name##_buf, &struct->name##_size
|
||||||
|
|
||||||
|
#undef INITIAL_GROWTH_SIZE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
143
custom_mutators/honggfuzz/honggfuzz.c
Normal file
143
custom_mutators/honggfuzz/honggfuzz.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "custom_mutator_helpers.h"
|
||||||
|
#include "mangle.h"
|
||||||
|
|
||||||
|
#define NUMBER_OF_MUTATIONS 5
|
||||||
|
|
||||||
|
uint8_t * queue_input;
|
||||||
|
size_t queue_input_size;
|
||||||
|
afl_state_t * afl_struct;
|
||||||
|
run_t run;
|
||||||
|
honggfuzz_t global;
|
||||||
|
struct _dynfile_t dynfile;
|
||||||
|
|
||||||
|
typedef struct my_mutator {
|
||||||
|
|
||||||
|
afl_state_t *afl;
|
||||||
|
run_t * run;
|
||||||
|
u8 * mutator_buf;
|
||||||
|
unsigned int seed;
|
||||||
|
unsigned int extras_cnt, a_extras_cnt;
|
||||||
|
|
||||||
|
} my_mutator_t;
|
||||||
|
|
||||||
|
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||||
|
|
||||||
|
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||||
|
if (!data) {
|
||||||
|
|
||||||
|
perror("afl_custom_init alloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
|
||||||
|
|
||||||
|
perror("mutator_buf alloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
run.dynfile = &dynfile;
|
||||||
|
run.global = &global;
|
||||||
|
data->afl = afl;
|
||||||
|
data->seed = seed;
|
||||||
|
data->run = &run;
|
||||||
|
afl_struct = afl;
|
||||||
|
|
||||||
|
run.global->mutate.maxInputSz = MAX_FILE;
|
||||||
|
run.global->mutate.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||||
|
run.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||||
|
run.global->timing.lastCovUpdate = 6;
|
||||||
|
|
||||||
|
// global->feedback.cmpFeedback
|
||||||
|
// global->feedback.cmpFeedbackMap
|
||||||
|
|
||||||
|
return data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When a new queue entry is added we check if there are new dictionary
|
||||||
|
entries to add to honggfuzz structure */
|
||||||
|
|
||||||
|
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||||
|
const uint8_t *filename_new_queue,
|
||||||
|
const uint8_t *filename_orig_queue) {
|
||||||
|
|
||||||
|
if (run.global->mutate.dictionaryCnt >= 1024) return;
|
||||||
|
|
||||||
|
while (data->extras_cnt < data->afl->extras_cnt &&
|
||||||
|
run.global->mutate.dictionaryCnt < 1024) {
|
||||||
|
|
||||||
|
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||||
|
data->afl->extras[data->extras_cnt].data,
|
||||||
|
data->afl->extras[data->extras_cnt].len);
|
||||||
|
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||||
|
data->afl->extras[data->extras_cnt].len;
|
||||||
|
run.global->mutate.dictionaryCnt++;
|
||||||
|
data->extras_cnt++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while (data->a_extras_cnt < data->afl->a_extras_cnt &&
|
||||||
|
run.global->mutate.dictionaryCnt < 1024) {
|
||||||
|
|
||||||
|
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||||
|
data->afl->a_extras[data->a_extras_cnt].data,
|
||||||
|
data->afl->a_extras[data->a_extras_cnt].len);
|
||||||
|
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||||
|
data->afl->a_extras[data->a_extras_cnt].len;
|
||||||
|
run.global->mutate.dictionaryCnt++;
|
||||||
|
data->a_extras_cnt++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we could set only_printable if is_ascii is set ... let's see
|
||||||
|
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) {
|
||||||
|
|
||||||
|
//run.global->cfg.only_printable = ...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* here we run the honggfuzz mutator, which is really good */
|
||||||
|
|
||||||
|
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||||
|
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||||
|
size_t max_size) {
|
||||||
|
|
||||||
|
/* set everything up, costly ... :( */
|
||||||
|
memcpy(data->mutator_buf, buf, buf_size);
|
||||||
|
queue_input = data->mutator_buf;
|
||||||
|
run.dynfile->data = data->mutator_buf;
|
||||||
|
queue_input_size = buf_size;
|
||||||
|
run.dynfile->size = buf_size;
|
||||||
|
*out_buf = data->mutator_buf;
|
||||||
|
|
||||||
|
/* the mutation */
|
||||||
|
mangle_mangleContent(&run, NUMBER_OF_MUTATIONS);
|
||||||
|
|
||||||
|
/* return size of mutated data */
|
||||||
|
return run.dynfile->size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deinitialize everything
|
||||||
|
*
|
||||||
|
* @param data The data ptr from afl_custom_init
|
||||||
|
*/
|
||||||
|
void afl_custom_deinit(my_mutator_t *data) {
|
||||||
|
|
||||||
|
free(data->mutator_buf);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
460
custom_mutators/honggfuzz/honggfuzz.h
Normal file
460
custom_mutators/honggfuzz/honggfuzz.h
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* honggfuzz - core structures and macros
|
||||||
|
* -----------------------------------------
|
||||||
|
*
|
||||||
|
* Author: Robert Swiecki <swiecki@google.com>
|
||||||
|
*
|
||||||
|
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HF_HONGGFUZZ_H_
|
||||||
|
#define _HF_HONGGFUZZ_H_
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "libhfcommon/util.h"
|
||||||
|
|
||||||
|
#define PROG_NAME "honggfuzz"
|
||||||
|
#define PROG_VERSION "2.2"
|
||||||
|
|
||||||
|
/* Name of the template which will be replaced with the proper name of the file
|
||||||
|
*/
|
||||||
|
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||||
|
|
||||||
|
/* Default name of the report created with some architectures */
|
||||||
|
#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
|
||||||
|
|
||||||
|
/* Default stack-size of created threads. */
|
||||||
|
#define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */
|
||||||
|
|
||||||
|
/* Name of envvar which indicates sequential number of fuzzer */
|
||||||
|
#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
|
||||||
|
|
||||||
|
/* Name of envvar which indicates that the netDriver should be used */
|
||||||
|
#define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
|
||||||
|
|
||||||
|
/* Name of envvar which indicates honggfuzz's log level in use */
|
||||||
|
#define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
|
||||||
|
|
||||||
|
/* Number of crash verifier iterations before tag crash as stable */
|
||||||
|
#define _HF_VERIFIER_ITER 5
|
||||||
|
|
||||||
|
/* Size (in bytes) for report data to be stored in stack before written to file
|
||||||
|
*/
|
||||||
|
#define _HF_REPORT_SIZE 32768
|
||||||
|
|
||||||
|
/* Perf bitmap size */
|
||||||
|
#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
|
||||||
|
#define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
|
||||||
|
/* Maximum number of PC guards (=trace-pc-guard) we support */
|
||||||
|
#define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
|
||||||
|
|
||||||
|
/* Maximum size of the input file in bytes (1 MiB) */
|
||||||
|
#define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL)
|
||||||
|
|
||||||
|
/* Default maximum size of produced inputs */
|
||||||
|
#define _HF_INPUT_DEFAULT_SIZE (1024ULL * 8)
|
||||||
|
|
||||||
|
/* Per-thread bitmap */
|
||||||
|
#define _HF_PERTHREAD_BITMAP_FD 1018
|
||||||
|
/* FD used to report back used int/str constants from the fuzzed process */
|
||||||
|
#define _HF_CMP_BITMAP_FD 1019
|
||||||
|
/* FD used to log inside the child process */
|
||||||
|
#define _HF_LOG_FD 1020
|
||||||
|
/* FD used to represent the input file */
|
||||||
|
#define _HF_INPUT_FD 1021
|
||||||
|
/* FD used to pass coverage feedback from the fuzzed process */
|
||||||
|
#define _HF_COV_BITMAP_FD 1022
|
||||||
|
#define _HF_BITMAP_FD _HF_COV_BITMAP_FD /* Old name for _HF_COV_BITMAP_FD */
|
||||||
|
/* FD used to pass data to a persistent process */
|
||||||
|
#define _HF_PERSISTENT_FD 1023
|
||||||
|
|
||||||
|
/* Input file as a string */
|
||||||
|
#define _HF_INPUT_FILE_PATH "/dev/fd/" HF_XSTR(_HF_INPUT_FD)
|
||||||
|
|
||||||
|
/* Maximum number of supported execve() args */
|
||||||
|
#define _HF_ARGS_MAX 2048
|
||||||
|
|
||||||
|
/* Message indicating that the fuzzed process is ready for new data */
|
||||||
|
static const uint8_t HFReadyTag = 'R';
|
||||||
|
|
||||||
|
/* Maximum number of active fuzzing threads */
|
||||||
|
#define _HF_THREAD_MAX 1024U
|
||||||
|
|
||||||
|
/* Persistent-binary signature - if found within file, it means it's a
|
||||||
|
* persistent mode binary */
|
||||||
|
#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
|
||||||
|
/* HF NetDriver signature - if found within file, it means it's a
|
||||||
|
* NetDriver-based binary */
|
||||||
|
#define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
|
||||||
|
|
||||||
|
/* printf() nonmonetary separator. According to MacOSX's man it's supported
|
||||||
|
* there as well */
|
||||||
|
#define _HF_NONMON_SEP "'"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
_HF_DYNFILE_NONE = 0x0,
|
||||||
|
_HF_DYNFILE_INSTR_COUNT = 0x1,
|
||||||
|
_HF_DYNFILE_BRANCH_COUNT = 0x2,
|
||||||
|
_HF_DYNFILE_BTS_EDGE = 0x10,
|
||||||
|
_HF_DYNFILE_IPT_BLOCK = 0x20,
|
||||||
|
_HF_DYNFILE_SOFT = 0x40,
|
||||||
|
|
||||||
|
} dynFileMethod_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
uint64_t cpuInstrCnt;
|
||||||
|
uint64_t cpuBranchCnt;
|
||||||
|
uint64_t bbCnt;
|
||||||
|
uint64_t newBBCnt;
|
||||||
|
uint64_t softCntPc;
|
||||||
|
uint64_t softCntEdge;
|
||||||
|
uint64_t softCntCmp;
|
||||||
|
|
||||||
|
} hwcnt_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
_HF_STATE_UNSET = 0,
|
||||||
|
_HF_STATE_STATIC,
|
||||||
|
_HF_STATE_DYNAMIC_DRY_RUN,
|
||||||
|
_HF_STATE_DYNAMIC_MAIN,
|
||||||
|
_HF_STATE_DYNAMIC_MINIMIZE,
|
||||||
|
|
||||||
|
} fuzzState_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HF_MAYBE = -1,
|
||||||
|
HF_NO = 0,
|
||||||
|
HF_YES = 1,
|
||||||
|
|
||||||
|
} tristate_t;
|
||||||
|
|
||||||
|
struct _dynfile_t {
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
uint64_t cov[4];
|
||||||
|
size_t idx;
|
||||||
|
int fd;
|
||||||
|
uint64_t timeExecUSecs;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
struct _dynfile_t *src;
|
||||||
|
uint32_t refs;
|
||||||
|
uint8_t * data;
|
||||||
|
TAILQ_ENTRY(_dynfile_t) pointers;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _dynfile_t dynfile_t;
|
||||||
|
|
||||||
|
struct strings_t {
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
TAILQ_ENTRY(strings_t) pointers;
|
||||||
|
char s[];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
uint8_t pcGuardMap[_HF_PC_GUARD_MAX];
|
||||||
|
uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
|
||||||
|
uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
|
||||||
|
uint64_t pidNewPC[_HF_THREAD_MAX];
|
||||||
|
uint64_t pidNewEdge[_HF_THREAD_MAX];
|
||||||
|
uint64_t pidNewCmp[_HF_THREAD_MAX];
|
||||||
|
uint64_t guardNb;
|
||||||
|
uint64_t pidTotalPC[_HF_THREAD_MAX];
|
||||||
|
uint64_t pidTotalEdge[_HF_THREAD_MAX];
|
||||||
|
uint64_t pidTotalCmp[_HF_THREAD_MAX];
|
||||||
|
|
||||||
|
} feedback_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
uint32_t cnt;
|
||||||
|
struct {
|
||||||
|
|
||||||
|
uint8_t val[32];
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
} valArr[1024 * 16];
|
||||||
|
|
||||||
|
} cmpfeedback_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
size_t threadsMax;
|
||||||
|
size_t threadsFinished;
|
||||||
|
uint32_t threadsActiveCnt;
|
||||||
|
pthread_t mainThread;
|
||||||
|
pid_t mainPid;
|
||||||
|
pthread_t threads[_HF_THREAD_MAX];
|
||||||
|
|
||||||
|
} threads;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
const char *inputDir;
|
||||||
|
const char *outputDir;
|
||||||
|
DIR * inputDirPtr;
|
||||||
|
size_t fileCnt;
|
||||||
|
size_t testedFileCnt;
|
||||||
|
const char *fileExtn;
|
||||||
|
size_t maxFileSz;
|
||||||
|
size_t newUnitsAdded;
|
||||||
|
char workDir[PATH_MAX];
|
||||||
|
const char *crashDir;
|
||||||
|
const char *covDirNew;
|
||||||
|
bool saveUnique;
|
||||||
|
size_t dynfileqMaxSz;
|
||||||
|
size_t dynfileqCnt;
|
||||||
|
dynfile_t * dynfileqCurrent;
|
||||||
|
dynfile_t * dynfileq2Current;
|
||||||
|
TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq;
|
||||||
|
bool exportFeedback;
|
||||||
|
|
||||||
|
} io;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
const char *const *cmdline;
|
||||||
|
bool nullifyStdio;
|
||||||
|
bool fuzzStdin;
|
||||||
|
const char * externalCommand;
|
||||||
|
const char * postExternalCommand;
|
||||||
|
const char * feedbackMutateCommand;
|
||||||
|
bool netDriver;
|
||||||
|
bool persistent;
|
||||||
|
uint64_t asLimit;
|
||||||
|
uint64_t rssLimit;
|
||||||
|
uint64_t dataLimit;
|
||||||
|
uint64_t coreLimit;
|
||||||
|
uint64_t stackLimit;
|
||||||
|
bool clearEnv;
|
||||||
|
char * env_ptrs[128];
|
||||||
|
char env_vals[128][4096];
|
||||||
|
sigset_t waitSigSet;
|
||||||
|
|
||||||
|
} exe;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
time_t timeStart;
|
||||||
|
time_t runEndTime;
|
||||||
|
time_t tmOut;
|
||||||
|
time_t lastCovUpdate;
|
||||||
|
int64_t timeOfLongestUnitUSecs;
|
||||||
|
bool tmoutVTALRM;
|
||||||
|
|
||||||
|
} timing;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
uint8_t val[256];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
} dictionary[1024];
|
||||||
|
|
||||||
|
size_t dictionaryCnt;
|
||||||
|
const char *dictionaryFile;
|
||||||
|
size_t mutationsMax;
|
||||||
|
unsigned mutationsPerRun;
|
||||||
|
size_t maxInputSz;
|
||||||
|
|
||||||
|
} mutate;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
bool useScreen;
|
||||||
|
char cmdline_txt[65];
|
||||||
|
int64_t lastDisplayUSecs;
|
||||||
|
|
||||||
|
} display;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
bool useVerifier;
|
||||||
|
bool exitUponCrash;
|
||||||
|
const char *reportFile;
|
||||||
|
size_t dynFileIterExpire;
|
||||||
|
bool only_printable;
|
||||||
|
bool minimize;
|
||||||
|
bool switchingToFDM;
|
||||||
|
|
||||||
|
} cfg;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
bool del_report;
|
||||||
|
|
||||||
|
} sanitizer;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
fuzzState_t state;
|
||||||
|
feedback_t * covFeedbackMap;
|
||||||
|
int covFeedbackFd;
|
||||||
|
cmpfeedback_t * cmpFeedbackMap;
|
||||||
|
int cmpFeedbackFd;
|
||||||
|
bool cmpFeedback;
|
||||||
|
const char * blacklistFile;
|
||||||
|
uint64_t * blacklist;
|
||||||
|
size_t blacklistCnt;
|
||||||
|
bool skipFeedbackOnTimeout;
|
||||||
|
uint64_t maxCov[4];
|
||||||
|
dynFileMethod_t dynFileMethod;
|
||||||
|
hwcnt_t hwCnts;
|
||||||
|
|
||||||
|
} feedback;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
size_t mutationsCnt;
|
||||||
|
size_t crashesCnt;
|
||||||
|
size_t uniqueCrashesCnt;
|
||||||
|
size_t verifiedCrashesCnt;
|
||||||
|
size_t blCrashesCnt;
|
||||||
|
size_t timeoutedCnt;
|
||||||
|
|
||||||
|
} cnts;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
int serverSocket;
|
||||||
|
int clientSocket;
|
||||||
|
|
||||||
|
} socketFuzzer;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
pthread_rwlock_t dynfileq;
|
||||||
|
pthread_mutex_t feedback;
|
||||||
|
pthread_mutex_t report;
|
||||||
|
pthread_mutex_t state;
|
||||||
|
pthread_mutex_t input;
|
||||||
|
pthread_mutex_t timing;
|
||||||
|
|
||||||
|
} mutex;
|
||||||
|
|
||||||
|
/* For the Linux code */
|
||||||
|
struct {
|
||||||
|
|
||||||
|
int exeFd;
|
||||||
|
uint64_t dynamicCutOffAddr;
|
||||||
|
bool disableRandomization;
|
||||||
|
void * ignoreAddr;
|
||||||
|
const char *symsBlFile;
|
||||||
|
char ** symsBl;
|
||||||
|
size_t symsBlCnt;
|
||||||
|
const char *symsWlFile;
|
||||||
|
char ** symsWl;
|
||||||
|
size_t symsWlCnt;
|
||||||
|
uintptr_t cloneFlags;
|
||||||
|
tristate_t useNetNs;
|
||||||
|
bool kernelOnly;
|
||||||
|
bool useClone;
|
||||||
|
|
||||||
|
} arch_linux;
|
||||||
|
|
||||||
|
/* For the NetBSD code */
|
||||||
|
struct {
|
||||||
|
|
||||||
|
void * ignoreAddr;
|
||||||
|
const char *symsBlFile;
|
||||||
|
char ** symsBl;
|
||||||
|
size_t symsBlCnt;
|
||||||
|
const char *symsWlFile;
|
||||||
|
char ** symsWl;
|
||||||
|
size_t symsWlCnt;
|
||||||
|
|
||||||
|
} arch_netbsd;
|
||||||
|
|
||||||
|
} honggfuzz_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
_HF_RS_UNKNOWN = 0,
|
||||||
|
_HF_RS_WAITING_FOR_INITIAL_READY = 1,
|
||||||
|
_HF_RS_WAITING_FOR_READY = 2,
|
||||||
|
_HF_RS_SEND_DATA = 3,
|
||||||
|
|
||||||
|
} runState_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
honggfuzz_t *global;
|
||||||
|
pid_t pid;
|
||||||
|
int64_t timeStartedUSecs;
|
||||||
|
char crashFileName[PATH_MAX];
|
||||||
|
uint64_t pc;
|
||||||
|
uint64_t backtrace;
|
||||||
|
uint64_t access;
|
||||||
|
int exception;
|
||||||
|
char report[_HF_REPORT_SIZE];
|
||||||
|
bool mainWorker;
|
||||||
|
unsigned mutationsPerRun;
|
||||||
|
dynfile_t * dynfile;
|
||||||
|
bool staticFileTryMore;
|
||||||
|
uint32_t fuzzNo;
|
||||||
|
int persistentSock;
|
||||||
|
runState_t runState;
|
||||||
|
bool tmOutSignaled;
|
||||||
|
char * args[_HF_ARGS_MAX + 1];
|
||||||
|
int perThreadCovFeedbackFd;
|
||||||
|
unsigned triesLeft;
|
||||||
|
dynfile_t * current;
|
||||||
|
#if !defined(_HF_ARCH_DARWIN)
|
||||||
|
timer_t timerId;
|
||||||
|
#endif // !defined(_HF_ARCH_DARWIN)
|
||||||
|
hwcnt_t hwCnts;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
/* For Linux code */
|
||||||
|
uint8_t *perfMmapBuf;
|
||||||
|
uint8_t *perfMmapAux;
|
||||||
|
int cpuInstrFd;
|
||||||
|
int cpuBranchFd;
|
||||||
|
int cpuIptBtsFd;
|
||||||
|
|
||||||
|
} arch_linux;
|
||||||
|
|
||||||
|
} run_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
106
custom_mutators/honggfuzz/input.h
Normal file
106
custom_mutators/honggfuzz/input.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#ifndef _HG_INPUT_
|
||||||
|
#define _HG_INPUT_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#ifdef __clang__
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#endif
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "honggfuzz.h"
|
||||||
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go-style defer scoped implementation
|
||||||
|
*
|
||||||
|
* If compiled with clang, use: -fblocks -lBlocksRuntime
|
||||||
|
*
|
||||||
|
* Example of use:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* int fd = open(fname, O_RDONLY);
|
||||||
|
* if (fd == -1) {
|
||||||
|
* error(....);
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
* defer { close(fd); };
|
||||||
|
* ssize_t sz = read(fd, buf, sizeof(buf));
|
||||||
|
* ...
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __STRMERGE(a, b) a##b
|
||||||
|
#define _STRMERGE(a, b) __STRMERGE(a, b)
|
||||||
|
#ifdef __clang__
|
||||||
|
#if __has_extension(blocks)
|
||||||
|
static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
|
||||||
|
(*dfunc)();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define defer \
|
||||||
|
void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
|
||||||
|
__attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
|
||||||
|
|
||||||
|
#else /* __has_extension(blocks) */
|
||||||
|
#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
|
||||||
|
#endif /* __has_extension(blocks) */
|
||||||
|
#else /* !__clang__, e.g.: gcc */
|
||||||
|
|
||||||
|
#define __block
|
||||||
|
#define _DEFER(a, count) \
|
||||||
|
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
|
||||||
|
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
|
||||||
|
__attribute__((unused)); \
|
||||||
|
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
|
||||||
|
#define defer _DEFER(a, __COUNTER__)
|
||||||
|
#endif /* ifdef __clang__ */
|
||||||
|
|
||||||
|
#define HF_MIN(x, y) (x <= y ? x : y)
|
||||||
|
#define HF_MAX(x, y) (x >= y ? x : y)
|
||||||
|
#define ATOMIC_GET
|
||||||
|
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
|
||||||
|
#define HF_ATTR_UNUSED __attribute__((unused))
|
||||||
|
#define util_Malloc(x) malloc(x)
|
||||||
|
|
||||||
|
extern uint8_t * queue_input;
|
||||||
|
extern size_t queue_input_size;
|
||||||
|
extern afl_state_t * afl_struct;
|
||||||
|
|
||||||
|
inline void wmb() { }
|
||||||
|
inline void LOG_F(const char *format, ...) { }
|
||||||
|
static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
|
||||||
|
return min + rand_below(afl_struct, max - min + 1);
|
||||||
|
}
|
||||||
|
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||||
|
|
||||||
|
static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
|
||||||
|
*buf = queue_input;
|
||||||
|
run->dynfile->data = queue_input;
|
||||||
|
run->dynfile->size = queue_input_size;
|
||||||
|
return queue_input_size;
|
||||||
|
}
|
||||||
|
static inline void input_setSize(run_t* run, size_t sz) {
|
||||||
|
run->dynfile->size = sz;
|
||||||
|
}
|
||||||
|
static inline void util_turnToPrintable(uint8_t* buf, size_t sz) {
|
||||||
|
for (size_t i = 0; i < sz; i++)
|
||||||
|
buf[i] = buf[i] % 95 + 32;
|
||||||
|
}
|
||||||
|
static inline void util_rndBuf(uint8_t* buf, size_t sz) {
|
||||||
|
if (sz == 0) return;
|
||||||
|
for (size_t i = 0; i < sz; i++)
|
||||||
|
buf[i] = (uint8_t)rand_below(afl_struct, 256);
|
||||||
|
}
|
||||||
|
static inline uint8_t util_rndPrintable() {
|
||||||
|
return 32 + rand_below(afl_struct, 127 - 32);
|
||||||
|
}
|
||||||
|
static inline void util_rndBufPrintable(uint8_t* buf, size_t sz) {
|
||||||
|
for (size_t i = 0; i < sz; i++)
|
||||||
|
buf[i] = util_rndPrintable();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1
custom_mutators/honggfuzz/libhfcommon
Symbolic link
1
custom_mutators/honggfuzz/libhfcommon
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.
|
1
custom_mutators/honggfuzz/log.h
Symbolic link
1
custom_mutators/honggfuzz/log.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
common.h
|
1039
custom_mutators/honggfuzz/mangle.c
Normal file
1039
custom_mutators/honggfuzz/mangle.c
Normal file
File diff suppressed because it is too large
Load Diff
32
custom_mutators/honggfuzz/mangle.h
Normal file
32
custom_mutators/honggfuzz/mangle.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* honggfuzz - buffer mangling routines
|
||||||
|
* -----------------------------------------
|
||||||
|
*
|
||||||
|
* Author: Robert Swiecki <swiecki@google.com>
|
||||||
|
*
|
||||||
|
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HF_MANGLE_H_
|
||||||
|
#define _HF_MANGLE_H_
|
||||||
|
|
||||||
|
#include "honggfuzz.h"
|
||||||
|
|
||||||
|
extern void mangle_mangleContent(run_t *run, int speed_factor);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
1
custom_mutators/honggfuzz/util.h
Symbolic link
1
custom_mutators/honggfuzz/util.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
common.h
|
@ -11,16 +11,21 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
|
|
||||||
### Version ++2.66d (devel)
|
### Version ++2.66d (devel)
|
||||||
- afl-fuzz:
|
- afl-fuzz:
|
||||||
|
- added -F option to allow -M main fuzzers to sync to foreign fuzzers,
|
||||||
|
e.g. honggfuzz or libfuzzer
|
||||||
- eliminated CPU affinity race condition for -S/-M runs
|
- eliminated CPU affinity race condition for -S/-M runs
|
||||||
- llvm_mode:
|
- llvm_mode:
|
||||||
|
- now supports llvm 12!
|
||||||
- fixes for laf-intel float splitting (thanks to mark-griffin for
|
- fixes for laf-intel float splitting (thanks to mark-griffin for
|
||||||
reporting)
|
reporting)
|
||||||
- LTO: autodictionary mode is a default
|
- LTO: autodictionary mode is a default
|
||||||
- LTO: instrim instrumentation disabled, only classic support used
|
- LTO: instrim instrumentation disabled, only classic support used
|
||||||
as it is always better
|
as it is always better
|
||||||
|
- added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz :)
|
||||||
- added afl-frida gum solution to examples/afl_frida (mostly imported
|
- added afl-frida gum solution to examples/afl_frida (mostly imported
|
||||||
from https://github.com/meme/hotwax/)
|
from https://github.com/meme/hotwax/)
|
||||||
- small fixes to afl-plot, afl-whatsup and man page creation
|
- small fixes to afl-plot, afl-whatsup and man page creation
|
||||||
|
- new README, added FAQ
|
||||||
|
|
||||||
|
|
||||||
### Version ++2.66c (release)
|
### Version ++2.66c (release)
|
||||||
|
113
docs/FAQ.md
Normal file
113
docs/FAQ.md
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# Frequently asked questions about afl++
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
1. [What is an edge?](#what-is-an-edge)
|
||||||
|
2. [Why is my stability below 100%?](#why-is-my-stability-below-100)
|
||||||
|
3. [How can I improve the stability value](#how-can-i-improve-the-stability-value)
|
||||||
|
|
||||||
|
If you find an interesting or important question missing, submit it via
|
||||||
|
[https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues)
|
||||||
|
|
||||||
|
## What is an "edge"
|
||||||
|
|
||||||
|
A program contains `functions`, `functions` contain the compiled machine code.
|
||||||
|
The compiled machine code in a `function` can be in a single or many `basic blocks`.
|
||||||
|
A `basic block` is the largest possible number of subsequent machine code
|
||||||
|
instructions that runs independent, meaning it does not split up to different
|
||||||
|
locations nor is it jumped into it from a different location:
|
||||||
|
```
|
||||||
|
function() {
|
||||||
|
A:
|
||||||
|
some
|
||||||
|
code
|
||||||
|
B:
|
||||||
|
if (x) goto C; else goto D;
|
||||||
|
C:
|
||||||
|
some code
|
||||||
|
goto D
|
||||||
|
D:
|
||||||
|
some code
|
||||||
|
goto B
|
||||||
|
E:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Every code block between two jump locations is a `basic block`.
|
||||||
|
|
||||||
|
An `edge` is then the unique relationship between two `basic blocks` (from the
|
||||||
|
code example above):
|
||||||
|
```
|
||||||
|
Block A
|
||||||
|
|
|
||||||
|
v
|
||||||
|
Block B <------+
|
||||||
|
/ \ |
|
||||||
|
v v |
|
||||||
|
Block C Block D --+
|
||||||
|
\
|
||||||
|
v
|
||||||
|
Block E
|
||||||
|
```
|
||||||
|
Every line between two blocks is an `edge`.
|
||||||
|
|
||||||
|
## Why is my stability below 100
|
||||||
|
|
||||||
|
Stability is measured by how many percent of the edges in the target are
|
||||||
|
"stable". Sending the same input again and again should take the exact same
|
||||||
|
path through the target every time. If that is the case, the stability is 100%.
|
||||||
|
|
||||||
|
If however randomness happens, e.g. a thread reading from shared memory,
|
||||||
|
reaction to timing, etc. then in some of the re-executions with the same data
|
||||||
|
will result in the edge information being different accross runs.
|
||||||
|
Those edges that change are then flagged "unstable".
|
||||||
|
|
||||||
|
The more "unstable" edges, the more difficult for afl++ to identify valid new
|
||||||
|
paths.
|
||||||
|
|
||||||
|
A value above 90% is usually fine and a value above 80% is also still ok, and
|
||||||
|
even above 20% can still result in successful finds of bugs.
|
||||||
|
However, it is recommended that below 90% or 80% you should take measures to
|
||||||
|
improve the stability.
|
||||||
|
|
||||||
|
## How can I improve the stability value
|
||||||
|
|
||||||
|
Four steps are required to do this and requires quite some knowledge of
|
||||||
|
coding and/or disassembly and it is only effectively possible with
|
||||||
|
afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
|
||||||
|
|
||||||
|
1. First step: Identify which edge ID numbers are unstable
|
||||||
|
|
||||||
|
run the target with `export AFL_DEBUG=1` for a few minutes then terminate.
|
||||||
|
The out/fuzzer_stats file will then show the edge IDs that were identified
|
||||||
|
as unstable.
|
||||||
|
|
||||||
|
2. Second step: Find the responsible function.
|
||||||
|
|
||||||
|
a) For LTO instrumented binaries just disassemble or decompile the target
|
||||||
|
and look which edge is writing to that edge ID. Ghidra is a good tool
|
||||||
|
for this: [https://ghidra-sre.org/](https://ghidra-sre.org/)
|
||||||
|
|
||||||
|
b) For PCGUARD instrumented binaries it is more difficult. Here you can
|
||||||
|
either modify the __sanitizer_cov_trace_pc_guard function in
|
||||||
|
llvm_mode/afl-llvm-rt.o.c to write a backtrace to a file if the ID in
|
||||||
|
__afl_area_ptr[*guard] is one of the unstable edge IDs. Then recompile
|
||||||
|
and reinstall llvm_mode and rebuild your target. Run the recompiled
|
||||||
|
target with afl-fuzz for a while and then check the file that you
|
||||||
|
wrote with the backtrace information.
|
||||||
|
Alternatively you can use `gdb` to hook __sanitizer_cov_trace_pc_guard_init
|
||||||
|
on start, check to which memory address the edge ID value is written
|
||||||
|
and set a write breakpoint to that address (`watch 0x.....`).
|
||||||
|
|
||||||
|
3. Third step: create a text file with the filenames
|
||||||
|
|
||||||
|
Identify which source code files contain the functions that you need to
|
||||||
|
remove from instrumentation.
|
||||||
|
|
||||||
|
Simply follow this document on how to do this: [llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md)
|
||||||
|
If PCGUARD is used, then you need to follow this guide: [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
|
||||||
|
|
||||||
|
4. Fourth step: recompile the target
|
||||||
|
|
||||||
|
Recompile, fuzz it, be happy :)
|
||||||
|
|
@ -99,7 +99,15 @@ example may be:
|
|||||||
This is not a concern if you use @@ without -f and let afl-fuzz come up with the
|
This is not a concern if you use @@ without -f and let afl-fuzz come up with the
|
||||||
file name.
|
file name.
|
||||||
|
|
||||||
## 3) Multi-system parallelization
|
## 3) Syncing with non-afl fuzzers or independant instances
|
||||||
|
|
||||||
|
A -M main node can be told with the `-F other_fuzzer_queue_directory` option
|
||||||
|
to sync results from other fuzzers, e.g. libfuzzer or honggfuzz.
|
||||||
|
|
||||||
|
Only the specified directory will by synced into afl, not subdirectories.
|
||||||
|
The specified directories do not need to exist yet at the start of afl.
|
||||||
|
|
||||||
|
## 4) Multi-system parallelization
|
||||||
|
|
||||||
The basic operating principle for multi-system parallelization is similar to
|
The basic operating principle for multi-system parallelization is similar to
|
||||||
the mechanism explained in section 2. The key difference is that you need to
|
the mechanism explained in section 2. The key difference is that you need to
|
||||||
@ -176,7 +184,7 @@ It is *not* advisable to skip the synchronization script and run the fuzzers
|
|||||||
directly on a network filesystem; unexpected latency and unkillable processes
|
directly on a network filesystem; unexpected latency and unkillable processes
|
||||||
in I/O wait state can mess things up.
|
in I/O wait state can mess things up.
|
||||||
|
|
||||||
## 4) Remote monitoring and data collection
|
## 5) Remote monitoring and data collection
|
||||||
|
|
||||||
You can use screen, nohup, tmux, or something equivalent to run remote
|
You can use screen, nohup, tmux, or something equivalent to run remote
|
||||||
instances of afl-fuzz. If you redirect the program's output to a file, it will
|
instances of afl-fuzz. If you redirect the program's output to a file, it will
|
||||||
@ -200,7 +208,7 @@ Keep in mind that crashing inputs are *not* automatically propagated to the
|
|||||||
main instance, so you may still want to monitor for crashes fleet-wide
|
main instance, so you may still want to monitor for crashes fleet-wide
|
||||||
from within your synchronization or health checking scripts (see afl-whatsup).
|
from within your synchronization or health checking scripts (see afl-whatsup).
|
||||||
|
|
||||||
## 5) Asymmetric setups
|
## 6) Asymmetric setups
|
||||||
|
|
||||||
It is perhaps worth noting that all of the following is permitted:
|
It is perhaps worth noting that all of the following is permitted:
|
||||||
|
|
||||||
|
BIN
docs/screenshot.png
Normal file
BIN
docs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
@ -70,11 +70,13 @@ ifeq "$(TEST_MMAP)" "1"
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq "$(shell uname -s)" "Haiku"
|
ifneq "$(shell uname -s)" "Haiku"
|
||||||
LDFLAGS += -lrt
|
LDFLAGS += -lrt
|
||||||
|
else
|
||||||
|
CFLAGS_SAFE += -DUSEMMAP=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq "$(shell uname -s)" "SunOS"
|
ifeq "$(shell uname -s)" "SunOS"
|
||||||
PLUGIN_FLAGS += -I/usr/include/gmp
|
PLUGIN_FLAGS += -I/usr/include/gmp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -348,6 +348,13 @@ struct afl_pass_stat {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct foreign_sync {
|
||||||
|
|
||||||
|
u8 * dir;
|
||||||
|
time_t ctime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct afl_state {
|
typedef struct afl_state {
|
||||||
|
|
||||||
/* Position of this state in the global states list */
|
/* Position of this state in the global states list */
|
||||||
@ -581,6 +588,15 @@ typedef struct afl_state {
|
|||||||
u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
|
u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
|
||||||
up to 256 */
|
up to 256 */
|
||||||
|
|
||||||
|
unsigned long long int last_avg_exec_update;
|
||||||
|
u32 last_avg_execs;
|
||||||
|
float last_avg_execs_saved;
|
||||||
|
|
||||||
|
/* foreign sync */
|
||||||
|
#define FOREIGN_SYNCS_MAX 32
|
||||||
|
u8 foreign_sync_cnt;
|
||||||
|
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||||
|
|
||||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||||
u8 do_document;
|
u8 do_document;
|
||||||
u32 document_counter;
|
u32 document_counter;
|
||||||
@ -944,6 +960,7 @@ void fix_up_banner(afl_state_t *, u8 *);
|
|||||||
void check_if_tty(afl_state_t *);
|
void check_if_tty(afl_state_t *);
|
||||||
void setup_signal_handlers(void);
|
void setup_signal_handlers(void);
|
||||||
void save_cmdline(afl_state_t *, u32, char **);
|
void save_cmdline(afl_state_t *, u32, char **);
|
||||||
|
void read_foreign_testcases(afl_state_t *, int);
|
||||||
|
|
||||||
/* CmpLog */
|
/* CmpLog */
|
||||||
|
|
||||||
|
@ -32,15 +32,16 @@ ifeq "$(shell uname)" "OpenBSD"
|
|||||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||||
ifeq "$(HAS_OPT)" "1"
|
ifeq "$(HAS_OPT)" "1"
|
||||||
$(error llvm_mode needs a complete llvm installation (versions 3.4 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
$(error llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
LLVM_CONFIG ?= llvm-config
|
LLVM_CONFIG ?= llvm-config
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
|
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
|
||||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 )
|
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^19' && echo 1 || echo 0 )
|
||||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||||
|
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
|
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
|
||||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||||
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||||
@ -53,7 +54,7 @@ ifeq "$(LLVMVER)" ""
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||||
$(warning llvm_mode only supports llvm versions 3.4 up to 11)
|
$(warning llvm_mode only supports llvm versions 3.4 up to 12)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq "$(LLVM_MAJOR)" "9"
|
ifeq "$(LLVM_MAJOR)" "9"
|
||||||
@ -65,8 +66,8 @@ ifeq "$(LLVM_NEW_API)" "1"
|
|||||||
LLVM_STDCXX = c++14
|
LLVM_STDCXX = c++14
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq "$(LLVM_MAJOR)" "11"
|
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||||
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
|
$(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation)
|
||||||
LLVM_LTO = 1
|
LLVM_LTO = 1
|
||||||
#TEST_MMAP = 1
|
#TEST_MMAP = 1
|
||||||
endif
|
endif
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## TLDR;
|
## TLDR;
|
||||||
|
|
||||||
This version requires a current llvm 11 compiled from the github master.
|
This version requires a current llvm 11+ compiled from the github master.
|
||||||
|
|
||||||
1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
|
1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
|
||||||
coverage than anything else that is out there in the AFL world
|
coverage than anything else that is out there in the AFL world
|
||||||
@ -10,7 +10,7 @@ This version requires a current llvm 11 compiled from the github master.
|
|||||||
2. You can use it together with llvm_mode: laf-intel and the instrument file listing
|
2. You can use it together with llvm_mode: laf-intel and the instrument file listing
|
||||||
features and can be combined with cmplog/Redqueen
|
features and can be combined with cmplog/Redqueen
|
||||||
|
|
||||||
3. It only works with llvm 11 (current github master state)
|
3. It only works with llvm 11+
|
||||||
|
|
||||||
4. AUTODICTIONARY feature! see below
|
4. AUTODICTIONARY feature! see below
|
||||||
|
|
||||||
@ -61,9 +61,9 @@ AUTODICTIONARY: 11 strings found
|
|||||||
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
|
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting llvm 11
|
## Getting llvm 11+
|
||||||
|
|
||||||
### Installing llvm 11 from the llvm repository
|
### Installing llvm from the llvm repository (version 11)
|
||||||
|
|
||||||
Installing the llvm snapshot builds is easy and mostly painless:
|
Installing the llvm snapshot builds is easy and mostly painless:
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
|
|||||||
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
|
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building llvm 11 yourself
|
### Building llvm yourself (version 12)
|
||||||
|
|
||||||
Building llvm from github takes quite some long time and is not painless:
|
Building llvm from github takes quite some long time and is not painless:
|
||||||
```
|
```
|
||||||
@ -157,7 +157,7 @@ instrument it:
|
|||||||
when compiling, so we have to trick configure:
|
when compiling, so we have to trick configure:
|
||||||
|
|
||||||
```
|
```
|
||||||
./configure --enable-lto --disable-shared
|
./configure --enable-lto --disable-shared --disable-inline-asm
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Now the configuration is done - and we edit the settings in `./ffbuild/config.mak`
|
3. Now the configuration is done - and we edit the settings in `./ffbuild/config.mak`
|
||||||
@ -201,15 +201,15 @@ cd WebKit
|
|||||||
```
|
```
|
||||||
mkdir -p WebKitBuild/Release
|
mkdir -p WebKitBuild/Release
|
||||||
cd WebKitBuild/Release
|
cd WebKitBuild/Release
|
||||||
ln -s ../../../../../usr/bin/llvm-ar-11 llvm-ar-11
|
ln -s ../../../../../usr/bin/llvm-ar-12 llvm-ar-12
|
||||||
ln -s ../../../../../usr/bin/llvm-ranlib-11 llvm-ranlib-11
|
ln -s ../../../../../usr/bin/llvm-ranlib-12 llvm-ranlib-12
|
||||||
cd ../..
|
cd ../..
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Build :)
|
3. Build :)
|
||||||
|
|
||||||
```
|
```
|
||||||
Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-11' -DCMAKE_RANLIB='llvm-ranlib-11' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON"
|
Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-12' -DCMAKE_RANLIB='llvm-ranlib-12' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Potential issues
|
## Potential issues
|
||||||
@ -246,17 +246,17 @@ AS=llvm-as ...
|
|||||||
afl-clang-lto is still work in progress.
|
afl-clang-lto is still work in progress.
|
||||||
|
|
||||||
Known issues:
|
Known issues:
|
||||||
* Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously
|
* Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously
|
||||||
* Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
|
* Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
|
||||||
|
|
||||||
Hence if building a target with afl-clang-lto fails try to build it with llvm11
|
Hence if building a target with afl-clang-lto fails try to build it with llvm12
|
||||||
and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
|
and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and
|
||||||
`CXXFLAGS=-flto=full`).
|
`CXXFLAGS=-flto=full`).
|
||||||
|
|
||||||
If this succeeeds then there is an issue with afl-clang-lto. Please report at
|
If this succeeeds then there is an issue with afl-clang-lto. Please report at
|
||||||
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
|
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
|
||||||
|
|
||||||
Even some targets where clang-11 fails can be build if the fail is just in
|
Even some targets where clang-12 fails can be build if the fail is just in
|
||||||
`./configure`, see `Solving difficult targets` above.
|
`./configure`, see `Solving difficult targets` above.
|
||||||
|
|
||||||
### Target crashes immediately
|
### Target crashes immediately
|
||||||
@ -296,7 +296,7 @@ Still more problems came up though as this only works without bugs from
|
|||||||
llvm 9 onwards, and with high optimization the link optimization ruins
|
llvm 9 onwards, and with high optimization the link optimization ruins
|
||||||
the instrumented control flow graph.
|
the instrumented control flow graph.
|
||||||
|
|
||||||
This is all now fixed with llvm 11. The llvm's own linker is now able to
|
This is all now fixed with llvm 11+. The llvm's own linker is now able to
|
||||||
load passes and this bypasses all problems we had.
|
load passes and this bypasses all problems we had.
|
||||||
|
|
||||||
Happy end :)
|
Happy end :)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## 1) Introduction
|
## 1) Introduction
|
||||||
|
|
||||||
! llvm_mode works with llvm versions 3.4 up to 11 !
|
! llvm_mode works with llvm versions 3.4 up to 12 !
|
||||||
|
|
||||||
The code in this directory allows you to instrument programs for AFL using
|
The code in this directory allows you to instrument programs for AFL using
|
||||||
true compiler-level instrumentation, instead of the more crude
|
true compiler-level instrumentation, instead of the more crude
|
||||||
@ -183,4 +183,4 @@ AFL_LLVM_INSTRUMENT=PCGUARD make
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note that this us currently the default, as it is the best mode.
|
Note that this us currently the default, as it is the best mode.
|
||||||
If you have llvm 11 and compiled afl-clang-lto - this is the only better mode.
|
If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode.
|
||||||
|
@ -514,6 +514,8 @@ static void __afl_start_snapshots(void) {
|
|||||||
|
|
||||||
if (!child_pid) {
|
if (!child_pid) {
|
||||||
|
|
||||||
|
//(void)nice(-20); // does not seem to improve
|
||||||
|
|
||||||
signal(SIGCHLD, old_sigchld_handler);
|
signal(SIGCHLD, old_sigchld_handler);
|
||||||
|
|
||||||
close(FORKSRV_FD);
|
close(FORKSRV_FD);
|
||||||
@ -717,6 +719,8 @@ static void __afl_start_forkserver(void) {
|
|||||||
|
|
||||||
if (!child_pid) {
|
if (!child_pid) {
|
||||||
|
|
||||||
|
//(void)nice(-20);
|
||||||
|
|
||||||
signal(SIGCHLD, old_sigchld_handler);
|
signal(SIGCHLD, old_sigchld_handler);
|
||||||
|
|
||||||
close(FORKSRV_FD);
|
close(FORKSRV_FD);
|
||||||
|
@ -620,7 +620,13 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
|
|||||||
|
|
||||||
last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base,
|
last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base,
|
||||||
c.last_tb.flags, c.cf_mask);
|
c.last_tb.flags, c.cf_mask);
|
||||||
if (last_tb) { tb_add_jump(last_tb, c.tb_exit, tb); }
|
#define TB_JMP_RESET_OFFSET_INVALID 0xffff
|
||||||
|
if (last_tb && (last_tb->jmp_reset_offset[c.tb_exit] !=
|
||||||
|
TB_JMP_RESET_OFFSET_INVALID)) {
|
||||||
|
|
||||||
|
tb_add_jump(last_tb, c.tb_exit, tb);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,6 +438,159 @@ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read all testcases from foreign input directories, then queue them for
|
||||||
|
testing. Called at startup and at sync intervals.
|
||||||
|
Does not descend into subdirectories! */
|
||||||
|
|
||||||
|
void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||||
|
|
||||||
|
if (!afl->foreign_sync_cnt) return;
|
||||||
|
|
||||||
|
struct dirent **nl;
|
||||||
|
s32 nl_cnt;
|
||||||
|
u32 i, iter;
|
||||||
|
|
||||||
|
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
|
||||||
|
|
||||||
|
for (iter = 0; iter < afl->foreign_sync_cnt; iter++) {
|
||||||
|
|
||||||
|
if (afl->foreign_syncs[iter].dir != NULL &&
|
||||||
|
afl->foreign_syncs[iter].dir[0] != 0) {
|
||||||
|
|
||||||
|
if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir);
|
||||||
|
time_t ctime_max = 0;
|
||||||
|
|
||||||
|
/* We use scandir() + alphasort() rather than readdir() because otherwise,
|
||||||
|
the ordering of test cases would vary somewhat randomly and would be
|
||||||
|
difficult to control. */
|
||||||
|
|
||||||
|
nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL);
|
||||||
|
|
||||||
|
if (nl_cnt < 0) {
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
|
||||||
|
WARNF("Unable to open directory '%s'", afl->foreign_syncs[iter].dir);
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nl_cnt == 0) {
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
WARNF("directory %s is currently empty",
|
||||||
|
afl->foreign_syncs[iter].dir);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show stats */
|
||||||
|
|
||||||
|
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "foreign sync %u", iter);
|
||||||
|
|
||||||
|
afl->stage_name = afl->stage_name_buf;
|
||||||
|
afl->stage_cur = 0;
|
||||||
|
afl->stage_max = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nl_cnt; ++i) {
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
u8 *fn2 =
|
||||||
|
alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
|
||||||
|
|
||||||
|
free(nl[i]); /* not tracked */
|
||||||
|
|
||||||
|
if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
|
||||||
|
|
||||||
|
if (first) PFATAL("Unable to access '%s'", fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we detect new files by their ctime */
|
||||||
|
if (likely(st.st_ctime <= afl->foreign_syncs[iter].ctime)) {
|
||||||
|
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This also takes care of . and .. */
|
||||||
|
|
||||||
|
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
|
||||||
|
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.st_size > MAX_FILE) {
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
WARNF(
|
||||||
|
"Test case '%s' is too big (%s, limit is %s), skipping", fn2,
|
||||||
|
stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
|
||||||
|
stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets do not use add_to_queue(afl, fn2, st.st_size, 0);
|
||||||
|
// as this could add duplicates of the startup input corpus
|
||||||
|
|
||||||
|
int fd = open(fn2, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 fault;
|
||||||
|
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
|
||||||
|
if (mem == MAP_FAILED) {
|
||||||
|
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
write_to_testcase(afl, mem, st.st_size);
|
||||||
|
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||||
|
afl->syncing_party = "foreign";
|
||||||
|
afl->queued_imported +=
|
||||||
|
save_if_interesting(afl, mem, st.st_size, fault);
|
||||||
|
afl->syncing_party = 0;
|
||||||
|
munmap(mem, st.st_size);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (st.st_ctime > ctime_max) ctime_max = st.st_ctime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
afl->foreign_syncs[iter].ctime = ctime_max;
|
||||||
|
free(nl); /* not tracked */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
|
||||||
|
afl->last_path_time = 0;
|
||||||
|
afl->queued_at_start = afl->queued_paths;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Read all testcases from the input directory, then queue them for testing.
|
/* Read all testcases from the input directory, then queue them for testing.
|
||||||
Called at startup. */
|
Called at startup. */
|
||||||
|
|
||||||
@ -466,7 +619,7 @@ void read_testcases(afl_state_t *afl) {
|
|||||||
ACTF("Scanning '%s'...", afl->in_dir);
|
ACTF("Scanning '%s'...", afl->in_dir);
|
||||||
|
|
||||||
/* We use scandir() + alphasort() rather than readdir() because otherwise,
|
/* We use scandir() + alphasort() rather than readdir() because otherwise,
|
||||||
the ordering of test cases would vary somewhat randomly and would be
|
the ordering of test cases would vary somewhat randomly and would be
|
||||||
difficult to control. */
|
difficult to control. */
|
||||||
|
|
||||||
nl_cnt = scandir(afl->in_dir, &nl, NULL, alphasort);
|
nl_cnt = scandir(afl->in_dir, &nl, NULL, alphasort);
|
||||||
@ -527,9 +680,11 @@ void read_testcases(afl_state_t *afl) {
|
|||||||
|
|
||||||
if (st.st_size > MAX_FILE) {
|
if (st.st_size > MAX_FILE) {
|
||||||
|
|
||||||
FATAL("Test case '%s' is too big (%s, limit is %s)", fn2,
|
WARNF("Test case '%s' is too big (%s, limit is %s), skipping", fn2,
|
||||||
stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
|
stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
|
||||||
stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
|
stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
|
||||||
|
ck_free(fn2);
|
||||||
|
continue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ void setup_custom_mutators(afl_state_t *afl) {
|
|||||||
|
|
||||||
if (fn) {
|
if (fn) {
|
||||||
|
|
||||||
if (afl->limit_time_sig)
|
if (afl->limit_time_sig && afl->limit_time_sig != -1)
|
||||||
FATAL(
|
FATAL(
|
||||||
"MOpt and custom mutator are mutually exclusive. We accept pull "
|
"MOpt and custom mutator are mutually exclusive. We accept pull "
|
||||||
"requests that integrates MOpt with the optional mutators "
|
"requests that integrates MOpt with the optional mutators "
|
||||||
@ -168,7 +168,8 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
|
|||||||
|
|
||||||
/* "afl_custom_deinit", optional for backward compatibility */
|
/* "afl_custom_deinit", optional for backward compatibility */
|
||||||
mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
|
mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
|
||||||
if (!mutator->afl_custom_deinit) FATAL("Symbol 'afl_custom_init' not found.");
|
if (!mutator->afl_custom_deinit)
|
||||||
|
FATAL("Symbol 'afl_custom_deinit' not found.");
|
||||||
|
|
||||||
/* "afl_custom_post_process", optional */
|
/* "afl_custom_post_process", optional */
|
||||||
mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
|
mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
|
||||||
@ -282,9 +283,23 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
|
|||||||
|
|
||||||
} else if (unlikely(retlen > orig_len)) {
|
} else if (unlikely(retlen > orig_len)) {
|
||||||
|
|
||||||
FATAL(
|
/* Do not exit the fuzzer, even if the trimmed data returned by the custom
|
||||||
"Trimmed data returned by custom mutator is larger than original "
|
mutator is larger than the original data. For some use cases, like the
|
||||||
"data");
|
grammar mutator, the definition of "size" may have different meanings.
|
||||||
|
For example, the trimming function in a grammar mutator aims at
|
||||||
|
reducing the objects in a grammar structure, but does not guarantee to
|
||||||
|
generate a smaller binary buffer.
|
||||||
|
|
||||||
|
Thus, we allow the custom mutator to generate the trimmed data that is
|
||||||
|
larger than the original data. */
|
||||||
|
|
||||||
|
if (afl->not_on_tty && afl->debug) {
|
||||||
|
|
||||||
|
WARNF(
|
||||||
|
"Trimmed data returned by custom mutator is larger than original "
|
||||||
|
"data");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else if (unlikely(retlen == 0)) {
|
} else if (unlikely(retlen == 0)) {
|
||||||
|
|
||||||
|
@ -612,6 +612,8 @@ void sync_fuzzers(afl_state_t *afl) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trim all new test cases to save cycles when doing deterministic checks. The
|
/* Trim all new test cases to save cycles when doing deterministic checks. The
|
||||||
|
@ -39,7 +39,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
|||||||
u8 fn[PATH_MAX];
|
u8 fn[PATH_MAX];
|
||||||
s32 fd;
|
s32 fd;
|
||||||
FILE * f;
|
FILE * f;
|
||||||
uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
|
u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
|
||||||
|
|
||||||
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
|
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
|
||||||
|
|
||||||
@ -67,6 +67,17 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((unlikely(!afl->last_avg_exec_update ||
|
||||||
|
cur_time - afl->last_avg_exec_update >= 60000))) {
|
||||||
|
|
||||||
|
afl->last_avg_execs_saved =
|
||||||
|
(float)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
|
||||||
|
(float)(cur_time - afl->last_avg_exec_update);
|
||||||
|
afl->last_avg_execs = afl->fsrv.total_execs;
|
||||||
|
afl->last_avg_exec_update = cur_time;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __HAIKU__
|
#ifndef __HAIKU__
|
||||||
if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
|
if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
|
||||||
#endif
|
#endif
|
||||||
@ -81,7 +92,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
|||||||
"cycles_wo_finds : %llu\n"
|
"cycles_wo_finds : %llu\n"
|
||||||
"execs_done : %llu\n"
|
"execs_done : %llu\n"
|
||||||
"execs_per_sec : %0.02f\n"
|
"execs_per_sec : %0.02f\n"
|
||||||
// "real_execs_per_sec: %0.02f\n" // damn the name is too long
|
"execs_ps_last_min : %0.02f\n"
|
||||||
"paths_total : %u\n"
|
"paths_total : %u\n"
|
||||||
"paths_favored : %u\n"
|
"paths_favored : %u\n"
|
||||||
"paths_found : %u\n"
|
"paths_found : %u\n"
|
||||||
@ -117,6 +128,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
|||||||
afl->fsrv.total_execs,
|
afl->fsrv.total_execs,
|
||||||
afl->fsrv.total_execs /
|
afl->fsrv.total_execs /
|
||||||
((double)(get_cur_time() - afl->start_time) / 1000),
|
((double)(get_cur_time() - afl->start_time) / 1000),
|
||||||
|
afl->last_avg_execs_saved,
|
||||||
afl->queued_paths, afl->queued_favored, afl->queued_discovered,
|
afl->queued_paths, afl->queued_favored, afl->queued_discovered,
|
||||||
afl->queued_imported, afl->max_depth, afl->current_entry,
|
afl->queued_imported, afl->max_depth, afl->current_entry,
|
||||||
afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable,
|
afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable,
|
||||||
@ -126,17 +138,17 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
|||||||
afl->fsrv.exec_tmout, afl->slowest_exec_ms,
|
afl->fsrv.exec_tmout, afl->slowest_exec_ms,
|
||||||
#ifndef __HAIKU__
|
#ifndef __HAIKU__
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
(unsigned long int)(rus.ru_maxrss >> 20),
|
(unsigned long int)(rus.ru_maxrss >> 20),
|
||||||
#else
|
#else
|
||||||
(unsigned long int)(rus.ru_maxrss >> 10),
|
(unsigned long int)(rus.ru_maxrss >> 10),
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
-1UL,
|
-1UL,
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_AFFINITY
|
#ifdef HAVE_AFFINITY
|
||||||
afl->cpu_aff,
|
afl->cpu_aff,
|
||||||
#else
|
#else
|
||||||
-1,
|
-1,
|
||||||
#endif
|
#endif
|
||||||
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner,
|
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner,
|
||||||
afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
|
afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
|
||||||
|
@ -131,10 +131,13 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
|
|||||||
"executions.\n\n"
|
"executions.\n\n"
|
||||||
|
|
||||||
"Other stuff:\n"
|
"Other stuff:\n"
|
||||||
" -T text - text banner to show on the screen\n"
|
|
||||||
" -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n"
|
" -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n"
|
||||||
" use -D to force -S secondary to perform deterministic "
|
" use -D to force -S secondary to perform deterministic "
|
||||||
"fuzzing\n"
|
"fuzzing\n"
|
||||||
|
" -F path - sync to a foreign fuzzer queue directory (requires "
|
||||||
|
"-M, can\n"
|
||||||
|
" be specified up to %u times)\n"
|
||||||
|
" -T text - text banner to show on the screen\n"
|
||||||
" -I command - execute this command/script when a new crash is "
|
" -I command - execute this command/script when a new crash is "
|
||||||
"found\n"
|
"found\n"
|
||||||
//" -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap
|
//" -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap
|
||||||
@ -142,7 +145,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
|
|||||||
" -C - crash exploration mode (the peruvian rabbit thing)\n"
|
" -C - crash exploration mode (the peruvian rabbit thing)\n"
|
||||||
" -e ext - file extension for the fuzz test input file (if "
|
" -e ext - file extension for the fuzz test input file (if "
|
||||||
"needed)\n\n",
|
"needed)\n\n",
|
||||||
argv0, EXEC_TIMEOUT, MEM_LIMIT);
|
argv0, EXEC_TIMEOUT, MEM_LIMIT, FOREIGN_SYNCS_MAX);
|
||||||
|
|
||||||
if (more_help > 1) {
|
if (more_help > 1) {
|
||||||
|
|
||||||
@ -269,7 +272,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
|
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv,
|
while ((opt = getopt(argc, argv,
|
||||||
"+c:i:I:o:f:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) >
|
"+c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) >
|
||||||
0) {
|
0) {
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@ -403,6 +406,19 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
afl->use_splicing = 1;
|
afl->use_splicing = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'F': /* foreign sync dir */
|
||||||
|
|
||||||
|
if (!afl->is_main_node)
|
||||||
|
FATAL(
|
||||||
|
"Option -F can only be specified after the -M option for the "
|
||||||
|
"main fuzzer of a fuzzing campaign");
|
||||||
|
if (afl->foreign_sync_cnt >= FOREIGN_SYNCS_MAX)
|
||||||
|
FATAL("Maximum %u entried of -F option can be specified",
|
||||||
|
FOREIGN_SYNCS_MAX);
|
||||||
|
afl->foreign_syncs[afl->foreign_sync_cnt].dir = optarg;
|
||||||
|
afl->foreign_sync_cnt++;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'f': /* target file */
|
case 'f': /* target file */
|
||||||
|
|
||||||
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
|
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
|
||||||
@ -1060,6 +1076,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
setup_cmdline_file(afl, argv + optind);
|
setup_cmdline_file(afl, argv + optind);
|
||||||
|
|
||||||
read_testcases(afl);
|
read_testcases(afl);
|
||||||
|
// read_foreign_testcases(afl, 1); for the moment dont do this
|
||||||
|
|
||||||
load_auto(afl);
|
load_auto(afl);
|
||||||
|
|
||||||
pivot_inputs(afl);
|
pivot_inputs(afl);
|
||||||
@ -1217,6 +1235,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (void)nice(-20); // does not improve the speed
|
||||||
// real start time, we reset, so this works correctly with -V
|
// real start time, we reset, so this works correctly with -V
|
||||||
afl->start_time = get_cur_time();
|
afl->start_time = get_cur_time();
|
||||||
|
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
__AFL_FUZZ_INIT();
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
float magic;
|
ssize_t bytes_read;
|
||||||
|
|
||||||
ssize_t bytes_read = read(STDIN_FILENO, &magic, sizeof(magic));
|
__AFL_INIT();
|
||||||
if (bytes_read < (ssize_t)sizeof(magic)) { return 1; }
|
float *magic = (float *)__AFL_FUZZ_TESTCASE_BUF;
|
||||||
|
|
||||||
if ((-magic == 15.0 + 0.5 + 0.125 + 0.03125 +
|
while (__AFL_LOOP(INT_MAX)) {
|
||||||
0.0078125)) { /* 15 + 1/2 + 1/8 + 1/32 + 1/128 */
|
|
||||||
abort();
|
if (__AFL_FUZZ_TESTCASE_LEN != sizeof(float)) return 1;
|
||||||
|
/* 15 + 1/2 + 1/8 + 1/32 + 1/128 */
|
||||||
|
if ((-*magic == 15.0 + 0.5 + 0.125 + 0.03125 + 0.0078125)) abort();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,13 +385,13 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
|||||||
CODE=1
|
CODE=1
|
||||||
}
|
}
|
||||||
rm -f test-compcov.compcov test.out
|
rm -f test-compcov.compcov test.out
|
||||||
AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 AFL_LLVM_LAF_SPLIT_FLOATS=1 ../afl-clang-fast -o test-floatingpoint test-floatingpoint.c > test.out 2>&1
|
AFL_LLVM_INSTRUMENT=AFL AFL_LLVM_LAF_ALL=1 ../afl-clang-fast -o test-floatingpoint test-floatingpoint.c > test.out 2>&1
|
||||||
test -e test-floatingpoint && {
|
test -e test-floatingpoint && {
|
||||||
mkdir -p in
|
mkdir -p in
|
||||||
echo ZZ > in/in
|
echo ZZ > in/in
|
||||||
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 30 seconds"
|
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 30 seconds"
|
||||||
{
|
{
|
||||||
AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -s1 -V30 -m ${MEM_LIMIT} -i in -o out -- ./test-floatingpoint >>errors 2>&1
|
AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -s 123 -V30 -m ${MEM_LIMIT} -i in -o out -- ./test-floatingpoint >>errors 2>&1
|
||||||
} >>errors 2>&1
|
} >>errors 2>&1
|
||||||
test -n "$( ls out/crashes/id:* 2>/dev/null )" && {
|
test -n "$( ls out/crashes/id:* 2>/dev/null )" && {
|
||||||
$ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
|
$ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
|
||||||
|
Reference in New Issue
Block a user