Proj THUDBFuzz: AFLplusplus

Cite

Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.

为了对比,应当使用fuzzbench aflplusplus setup或者afl-clang-fast + AFL_LLVM_COMLOG=1

插桩

插桩的编译器选择

  1. clang 11+:使用afl-clang-lto或者afl-clang-lto++
  2. clang 3.8+: 使用afl-clang-fast或者afl-clang-fast++
  3. gcc 5+: 使用afl-gcc-fast或者afl-g++-fast++
  4. afl-gcc/afl-g++ or afl-clang/afl-clang++

Overview

framework的主要元素是:

  1. 带有多种变异方法和设置参数的fuzzer: afl-fuzz
  2. 不同的源代码插桩模块:LLVM mode, afl-as, GCC plugin
  3. 不同的二进制代码插桩模块: QEMU mode, Unicorn mode, QBDI mode
  4. testcase/corpus reduction: afl-tmin, afl-cmin
  5. 其他Helper libraries: libtokencap, libdislocator, libcompcov

Features

已经支持:

  1. llvm 11
  2. QEMU 5.1
  3. BSD and Android Support
  4. AFL fast的power schedule功能 https://github.com/mboehme/aflfast
  5. MOpt变异 https://github.com/puppet-meteor/MOpt-AFL
  6. InsTrim: 高效的CFG llvm_mode插桩实现 https://github.com/csienslab/instrim
  7. afl-fuzz Python mutator + llvm mode whitelist support: https://github.com/choller/afl
  8. Custom mutator by a library
  9. Unicorn mode: allows fuzzin of binaries from different platforms
  10. LAF-Intel/CompCov support for llvm_mode,qemu_mode and unicorn_mode
  11. NeverZero patch, 使得wrapping map值不为0
  12. Persistent mode and deferred forkserver for qemu_mode
  13. Win32 PE binary-only fuzzing with QEMU and wine
  14. Radamsa mutator
  15. QBDI mode(fuzz android native libs)
  16. CmpLog instrumentation for LLVM and QEMU(inspired by RedQueen)

Fuzzing binary-only programs with afl++ 如何对只有源码的程序进行模糊测试

  1. afl-fuzz -n是不插桩模式,但是效果并不好。
  2. 官方建议按照以下优先顺序
  3. qemu_mode + persistent mode最快,不过要求程序足够稳定
  4. retrowrite
  5. afl-dyninst
  6. qemu_mode with AFL_ENTRYPOINT

QEMU

qemu支持对只有二进制的程序进行模糊测试,甚至还能跨平台测试。
qemu会把测试程序的速度减慢50%,但是下面的选项能够增加qemu测试的速度

  1. using AFL_ENTRYPOINT to move the forkserver entry to a later basic block in the binary (+5-10% speed)
  2. persistent mode(150-300% overall speed increase)
  3. using AFL_CODE_START/AFL_CODE_END to only instrument specific parts

honggfuzz也有qemu_mode,但是只能增进1.5%的速度

WINE+QEMU

wine + python3 + pefile(python package) + qemu可以在Linux上测win32

UNICORN

UNICORN是QEMU的fork,不过,UNICORN提供的不是整个系统或者用户界面仿真。用户需要从头写runtime environment 或者是loaders。此外,UNICORN中的区块链已经被删除了。

AFL Frida

frida-gum + utils/afl_frida,此时使用afl-frida.c作为模板来调用library中的目标函数

AFL Untracer

utils/afl_untracer,这里用afl-untracer.c做模板

DYNINST

类似Pintool和Dynamorio的二进制工具框架。不过Dyninst在加载时会对目标进行插桩(而Pintool和Dynamorio不会),然后再保存对应二进制。接着,用afl-fuzz来模糊测修改后的二进制。一般来说,我们会用dyninst插桩并将必要的信息加入二进制。但这样做存在一个隐患,会改变进程空间中的地址,这导致待测程序很可能会崩溃。DYNINST会给速度带来15到35%的降低。

https://github.com/vanhauser-thc/afl-dyninst

Retrowrite

如果待测程序携带符号表,而且是编译时选择了位置无关,并且没有用大多数c++features,那就可以用retrowrite。只会降低15%到20%的性能

https://github.com/HexHive/retrowrite

MCSEMA

理论上可行
https://github.com/lifting-bits/mcsema

INTEL-PT

硬件需求: 新世代Intel CPU
效果: 利用intels processor trace
问题:缓存区很小,而且PT传回来的debug信息的解码非常麻烦需要大量CPU计算来解码。
As a result, the overall speed decrease is about 70-90%
https://github.com/junxzm1990/afl-pt
https://github.com/hunter-ht-2018/ptfuzzer

CoreSight

ARM,但是还没找到实现

Frida

动态插桩引擎,特殊在于其用python写的,然后用JS来跑具体执行。该软件通常用在逆向手机软件上。
https://github.com/andreafioraldi/frida-fuzzer
https://github.com/AFLplusplus/AFLplusplus/tree/frida

PIN & DYNAMORIO

动态插桩引擎,能够在运行时获取基本块信息。
会严重拖慢时间

Dynamorio solutions:
https://github.com/vanhauser-thc/afl-dynamorio
https://github.com/mxmssh/drAFL
https://github.com/googleprojectzero/winafl/ <= very good but windows only

Pintool solutions:
https://github.com/vanhauser-thc/afl-pin
https://github.com/mothran/aflpin
https://github.com/spinpx/afl_pin_mode <= only old Pintool version supported

ENV

为了避免出现ENV的笔误,Afl++中的一些工具可能会警告自己不用也不知道的环境变量,那时可以用AFL_IGNORE_UNKNOWN_ENVS 来避免这个问题

AFL custom mutators

该目录下一共有grammar mutator, honggfuzz, libfuzzer, libprotobuf-mutator-example, radamsa, rust, symcc这几个子目录。此外,还提到了superion这个项目。

grammar mutator

使用git submodule update --init来初始化子项目
该项目是AFL++内部为了兼容高度结构化的测试样例而做的,其功能或者思想基本来自 F1 fuzzer and Nautilus

该项目能够做以下操作:

  • Tree-based mutation: rules mutation, random mutation, random recursive mutation, splicing mutation
  • Tree-based trimming: subtree trimming, recursive trimming
  • An ANTLR4 shim for parsing fuzzing test cases during the runtime

Usage

static void usage(u8 *argv0, int more_help) {

  SAYF(
      "\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"

      "Required parameters:\n"
      "  -i dir        - input directory with test cases\n"
      "  -o dir        - output directory for fuzzer findings\n\n"

      "Execution control settings:\n"
      "  -p schedule   - power schedules compute a seed's performance score:\n"
      "                  fast(default), explore, exploit, seek, rare, mmopt, "
      "coe, lin\n"
      "                  quad -- see docs/power_schedules.md\n"
      "  -f file       - location read by the fuzzed program (default: stdin "
      "or @@)\n"
      "  -t msec       - timeout for each run (auto-scaled, default %u ms). "
      "Add a '+'\n"
      "                  to auto-calculate the timeout, the value being the "
      "maximum.\n"
      "  -m megs       - memory limit for child process (%u MB, 0 = no limit "
      "[default])\n"
      "  -Q            - use binary-only instrumentation (QEMU mode)\n"
      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
      "  -W            - use qemu-based instrumentation with Wine (Wine "
      "mode)\n\n"

      "Mutator settings:\n"
      "  -D            - enable deterministic fuzzing (once per queue entry)\n"
      "  -L minutes    - use MOpt(imize) mode and set the time limit for "
      "entering the\n"
      "                  pacemaker mode (minutes of no new paths). 0 = "
      "immediately,\n"
      "                  -1 = immediately and together with normal mutation).\n"
      "                  See docs/README.MOpt.md\n"
      "  -c program    - enable CmpLog by specifying a binary compiled for "
      "it.\n"
      "                  if using QEMU, just use -c 0.\n"
      "  -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
      "                  1=small files (default), 2=larger files, 3=all "
      "files,\n"
      "                  A=arithmetic solving, T=transformational solving.\n\n"
      "Fuzzing behavior settings:\n"
      "  -Z            - sequential queue selection instead of weighted "
      "random\n"
      "  -N            - do not unlink the fuzzing input file (for devices "
      "etc.)\n"
      "  -n            - fuzz without instrumentation (non-instrumented mode)\n"
      "  -x dict_file  - fuzzer dictionary (see README.md, specify up to 4 "
      "times)\n\n"

      "Testing settings:\n"
      "  -s seed       - use a fixed seed for the RNG\n"
      "  -V seconds    - fuzz for a specified time then terminate\n"
      "  -E execs      - fuzz for an approx. no. of total executions then "
      "terminate\n"
      "                  Note: not precise and can have several more "
      "executions.\n\n"

      "Other stuff:\n"
      "  -M/-S id      - distributed mode (see docs/parallel_fuzzing.md)\n"
      "                  -M auto-sets -D, -Z (use -d to disable -D) and no "
      "trimming\n"
      "  -F path       - sync to a foreign fuzzer queue directory (requires "
      "-M, can\n"
      "                  be specified up to %u times)\n"
      "  -d            - skip deterministic fuzzing in -M mode\n"
      "  -T text       - text banner to show on the screen\n"
      "  -I command    - execute this command/script when a new crash is "
      "found\n"
      //"  -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap
      //" "file\n"
      "  -C            - crash exploration mode (the peruvian rabbit thing)\n"
      "  -b cpu_id     - bind the fuzzing process to the specified CPU core "
      "(0-...)\n"
      "  -e ext        - file extension for the fuzz test input file (if "
      "needed)\n\n",
      argv0, EXEC_TIMEOUT, MEM_LIMIT, FOREIGN_SYNCS_MAX);

  if (more_help > 1) {

#if defined USE_COLOR && !defined ALWAYS_COLORED
  #define DYN_COLOR \
    "AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
#else
  #define DYN_COLOR
#endif

    SAYF(
      "Environment variables used:\n"
      "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
      "ASAN_OPTIONS: custom settings for ASAN\n"
      "              (must contain abort_on_error=1 and symbolize=0)\n"
      "MSAN_OPTIONS: custom settings for MSAN\n"
      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
      "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
      "AFL_BENCH_JUST_ONE: run the target just once\n"
      "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
      "AFL_CMPLOG_ONLY_NEW: do not run cmplog on initial testcases (good for resumes!)\n"
      "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
      "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
      "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
      "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
      "AFL_DEBUG: extra debugging output for Python mode trimming\n"
      "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
      "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
      "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
      "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
      "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n"
      "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
      "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
      "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
      "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
      "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
      "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
      "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
      "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
      "              the target was compiled for\n"
      "AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n"
      "                    then they are randomly selected instead all of them being\n"
      "                    used. Defaults to 200.\n"
      "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
      "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
      "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
      "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
      "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
      "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
      "AFL_NO_UI: switch status screen off\n"

      DYN_COLOR

      "AFL_PATH: path to AFL support binaries\n"
      "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
      "AFL_QUIET: suppress forkserver status messages\n"
      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
      "AFL_TARGET_ENV: pass extra environment variables to target\n"
      "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
      "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n"
      "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
      "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
      "AFL_STATSD: enables StatsD metrics collection\n"
      "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n"
      "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
      "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
      "                        Supported formats are: 'dogstatsd', 'librato',\n"
      "                        'signalfx' and 'influxdb'\n"
      "AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n"
      "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
      //"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n"
      //"AFL_DEFER_FORKSRV: not supported anymore -> no effect, just a warning\n"
      "\n"
    );
posted @ 2021-04-12 09:30  雪溯  阅读(1013)  评论(2编辑  收藏  举报