* push to stable (#1983) * Output afl-clang-fast stuffs only if necessary (#1912) * afl-cc header * afl-cc common declarations - Add afl-cc-state.c - Strip includes, find_object, debug/be_quiet/have_*/callname setting from afl-cc.c - Use debugf_args in main - Modify execvp stuffs to fit new aflcc struct * afl-cc show usage * afl-cc mode selecting 1. compiler_mode by callname in argv[0] 2. compiler_mode by env "AFL_CC_COMPILER" 3. compiler_mode/instrument_mode by command line options "--afl-..." 4. instrument_mode/compiler_mode by various env vars including "AFL_LLVM_INSTRUMENT" 5. final checking steps 6. print "... - mode: %s-%s\n" 7. determine real argv[0] according to compiler_mode * afl-cc macro defs * afl-cc linking behaviors * afl-cc fsanitize behaviors * afl-cc misc * afl-cc body update * afl-cc all-in-one formated with custom-format.py * nits --------- Co-authored-by: vanhauser-thc <vh@thc.org> * changelog * update grammar mutator * lto llvm 12+ * docs(custom_mutators): fix missing ':' (#1953) * Fix broken LTO mode and response file support (#1948) * Strip `-Wl,-no-undefined` during compilation (#1952) Make the compiler wrapper stripping `-Wl,-no-undefined` in addition to `-Wl,--no-undefined`. Both versions of the flag are accepted by clang and, therefore, used by building systems in the wild (e.g., samba will not build without this fix). * Remove dead code in write_to_testcase (#1955) The custom_mutators_count check in if case is duplicate with if condition. The else case is custom_mutators_count == 0, neither custom_mutator_list iteration nor sent check needed. Signed-off-by: Xeonacid <h.dwwwwww@gmail.com> * update qemuafl * WIP: Add ability to generate drcov trace using QEMU backend (#1956) * Document new drcov QEMU plugin * Add link to lightkeeper for QEMU drcov file loading --------- Co-authored-by: Jean-Romain Garnier <jean-romain.garnier@airbus.com> * code format * changelog * sleep on uid != 0 afl-system-config * fix segv about skip_next, warn on unsupported cases of linking options (#1958) * todos * ensure afl-cc only allows available compiler modes * update grammar mutator * disable aslr on apple * fix for arm64 * help selective instrumentation * typos * macos * add compiler test script * apple fixes * bump nyx submodules (#1963) * fix docs * update changelog * update grammar mutator * improve compiler test script * gcc asan workaround (#1966) * fix github merge fuckup * fix * Fix afl-cc (#1968) - Check if too many cmdline params here, each time before insert a new param. - Check if it is "-fsanitize=..." before we do sth. - Remove improper param_st transfer. * Avoid adding llvmnative instrumentation when linking rust sanitizer runtime (#1969) * Dynamic instrumentation filtering for LLVM native (#1971) * Add two dynamic instrumentation filter methods to runtime * Always use pc-table with native pcguard * Add make_symbol_list.py and README * changelog * todos * new forkserver check * fix * nyx test for CI * improve nyx docs * Fixes to afl-cc and documentation (#1974) * Always compile with -ldl when building for CODE_COVERAGE When building with CODE_COVERAGE, the afl runtime contains code that calls `dladdr` which requires -ldl. Under most circumstances, clang already adds this (e.g. when building with pc-table), but there are some circumstances where it isn't added automatically. * Add visibility declaration to __afl_connected When building with hidden visibility, the use of __AFL_LOOP inside such code can cause linker errors due to __afl_connected being declared "hidden". * Update docs to clarify that CODE_COVERAGE=1 is required for dynamic_covfilter * nits * nyx build script updates * test error output * debug ci * debug ci * Improve afl-cc (#1975) * update response file support - full support of rsp file - fix some segv issues * Improve afl-cc - remove dead code about allow/denylist options of sancov - missing `if (!aflcc->have_msan)` - add docs for each function - typo * enable nyx * debug ci * debug ci * debug ci * debug ci * debug ci * debug ci * debug ci * debug ci * fix ci * clean test script * NO_NYX * NO_NYX * fix ci * debug ci * fix ci * finalize ci fix * Enhancement on Deterministic stage (#1972) * fuzzer: init commit based on aflpp 60dc37a8cf09f8e9048e4b6a2204d6c90b27655a * fuzzers: adding the skip variables and initialize * log: profile the det/havoc finding * log: add profile log output * fuzzers: sperate log/skipdet module * fuzzers: add quick eff_map calc * fuzzers: add skip_eff_map in fuzz_one * fuzzers: mark whole input space in eff_map * fuzzers: add undet bit threshold to skip some seeds * fuzzers: fix one byte overflow * fuzzers: fix overflow * fix code format * add havoc only again * code format * remove log to INTROSPECTION, rename skipdet module * rename skipdet module * remove log to stats * clean redundant code * code format * remove redundant code format check * remove redundant doc * remove redundant objects * clean files * change -d to default skipdet * disable deterministic when using CUSTOM_MUTATOR * revert fix * final touches for skipdet * remove unused var * remove redundant eff struct (#1977) * update QEMU-Nyx submodule (#1978) * update QEMU-Nyx submodule (#1980) * Fix type in AFL_NOOPT env variable in afl-cc help message (#1982) * nits * 2024 v4.10c release * fixes --------- Signed-off-by: Xeonacid <h.dwwwwww@gmail.com> Co-authored-by: Sonic <50692172+SonicStark@users.noreply.github.com> Co-authored-by: Xeonacid <h.dwwwwww@gmail.com> Co-authored-by: Nils Bars <nils.bars@rub.de> Co-authored-by: Jean-Romain Garnier <7504819+JRomainG@users.noreply.github.com> Co-authored-by: Jean-Romain Garnier <jean-romain.garnier@airbus.com> Co-authored-by: Sergej Schumilo <sergej@schumilo.de> Co-authored-by: Christian Holler (:decoder) <choller@mozilla.com> Co-authored-by: Han Zheng <35988108+kdsjZh@users.noreply.github.com> Co-authored-by: Khaled Yakdan <yakdan@code-intelligence.com> * Fix dump_regs() type errors in Python TypeError will occur as gdb api return some strange type of values that json can't serialize, this would fix this issue * Update reg_val is None condition --------- Signed-off-by: Xeonacid <h.dwwwwww@gmail.com> Co-authored-by: van Hauser <vh@thc.org> Co-authored-by: Sonic <50692172+SonicStark@users.noreply.github.com> Co-authored-by: Xeonacid <h.dwwwwww@gmail.com> Co-authored-by: Nils Bars <nils.bars@rub.de> Co-authored-by: Jean-Romain Garnier <7504819+JRomainG@users.noreply.github.com> Co-authored-by: Jean-Romain Garnier <jean-romain.garnier@airbus.com> Co-authored-by: Sergej Schumilo <sergej@schumilo.de> Co-authored-by: Christian Holler (:decoder) <choller@mozilla.com> Co-authored-by: Han Zheng <35988108+kdsjZh@users.noreply.github.com> Co-authored-by: Khaled Yakdan <yakdan@code-intelligence.com>
Unicorn-based binary-only instrumentation for afl-fuzz
The idea and much of the original implementation comes from Nathan Voss njvoss299@gmail.com.
The port to AFL++ is by Dominik Maier mail@dmnk.co.
The CompareCoverage and NeverZero counters features are by Andrea Fioraldi andreafioraldi@gmail.com.
1) Introduction
The code in unicorn_mode/ allows you to build the Unicorn Engine with AFL++ support. This means, you can run anything that can be emulated in unicorn and obtain instrumentation output for black-box, closed-source binary code snippets. This mechanism can be then used by afl-fuzz to stress-test targets that couldn't be built with afl-cc or used in QEMU mode.
There is a significant performance penalty compared to native AFL, but at least we're able to use AFL++ on these binaries, right?
2) How to use
First, you will need a working harness for your target in unicorn, using Python, C, or Rust.
For some pointers for more advanced emulation, take a look at BaseSAFE and Qiling.
Building AFL++'s Unicorn mode
First, make AFL++ as usual. Once that completes successfully, you need to build and add in the Unicorn mode features:
cd unicorn_mode
./build_unicorn_support.sh
NOTE: This script checks out a Unicorn Engine fork as submodule that has been
tested and is stable-ish, based on the unicorn engine next
branch.
Building Unicorn will take a little bit (~5-10 minutes). Once it completes, it automatically compiles a sample application and verifies that it works.
Fuzzing with Unicorn mode
To use unicorn-mode effectively, you need to prepare the following:
- Relevant binary code to be fuzzed
- Knowledge of the memory map and good starting state
- Folder containing sample inputs to start fuzzing with
- Same ideas as any other AFL++ inputs
- Quality/speed of results will depend greatly on the quality of starting samples
- See AFL's guidance on how to create a sample corpus
- Unicornafl-based test harness in Rust, C, or Python, which:
- Adds memory map regions
- Loads binary code into memory
- Calls uc.afl_fuzz() / uc.afl_start_forkserver
- Loads and verifies data to fuzz from a command-line specified file
- AFL++ will provide mutated inputs by changing the file passed to the test harness
- Presumably the data to be fuzzed is at a fixed buffer address
- If input constraints (size, invalid bytes, etc.) are known, they should be checked in the place_input handler. If a constraint fails, just return false from the handler. AFL++ will treat the input as 'uninteresting' and move on.
- Sets up registers and memory state to start testing
- Emulates the interesting code from beginning to end
- If a crash is detected, the test harness must 'crash' by throwing a signal (SIGSEGV, SIGKILL, SIGABORT, etc.), or indicate a crash in the crash validation callback.
Once you have all those things ready to go, you just need to run afl-fuzz in
unicorn-mode
by passing in the -U
flag:
afl-fuzz -U -m none -i /path/to/inputs -o /path/to/results -- ./test_harness @@
The normal afl-fuzz command line format applies to everything here. Refer to AFL's main documentation for more info about how to use afl-fuzz effectively.
For a much clearer vision of what all of this looks like, refer to the sample provided in the samples/ directory. There is also a blog post that uses slightly older concepts, but describes the general ideas, at:
https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf
The helper_scripts/ directory also contains several helper scripts that allow you to dump context from a running process, load it, and hook heap allocations. For details on how to use this, check out the follow-up blog post to the one linked above:
https://hackernoon.com/afl-unicorn-part-2-fuzzing-the-unfuzzable-bea8de3540a5
An example use of AFL-Unicorn mode is discussed in the paper Unicorefuzz: https://www.usenix.org/conference/woot19/presentation/maier
3) Options
As for the QEMU-based instrumentation, unicornafl comes with a sub-instruction based instrumentation similar in purpose to laf-intel.
The options that enable Unicorn CompareCoverage are the same used for QEMU. This will split up each multi-byte compare to give feedback for each correct byte:
AFL_COMPCOV_LEVEL=1
to instrument comparisons with only immediate values.AFL_COMPCOV_LEVEL=2
to instrument all comparison instructions.
Comparison instructions are currently instrumented only for the x86, x86_64, and ARM targets.
4) Gotchas, feedback, bugs
Running the build script builds unicornafl and its Python bindings and installs them on your system. This installation will leave any existing Unicorn installations untouched.
If you want to use unicornafl instead of unicorn in a script, replace all
unicorn
imports with unicornafl
inputs, everything else should "just work".
If you use 3rd party code depending on unicorn, you can use unicornafl
monkeypatching. Before importing anything that depends on unicorn, do:
import unicornafl
unicornafl.monkeypatch()
This will replace all unicorn imports with unicornafl inputs.
5) Examples
Apart from reading the documentation in afl.c
and the Python bindings of
unicornafl, the best documentation are the samples/.
The following examples exist at the time of writing:
- c: A simple example on how to use the C bindings
- compcov_x64: A Python example that uses compcov to traverse hard-to-reach blocks
- persistent: A C example using persistent mode for maximum speed, and resetting the target state between each iteration
- simple: A simple Python example
- speedtest/c: The C harness for an example target, used to compare C, Python, and Rust bindings and fix speed issues
- speedtest/python: Fuzzing the same target in Python
- speedtest/rust: Fuzzing the same target using a Rust harness
Usually, the place to look at is the harness
in each folder. The source code
in each harness is pretty well documented. Most harnesses also have the
afl-fuzz
commandline, or even offer a make fuzz
Makefile target. Targets in
these folders, if x86, can usually be made using make target
in each folder or
get shipped pre-built (plus their source).
Especially take a look at the speedtest documentation to see how the languages compare.