Coder Social home page Coder Social logo

fgsect / fitm Goto Github PK

View Code? Open in Web Editor NEW
273.0 9.0 19.0 68.44 MB

FitM, the Fuzzer in the Middle, can fuzz client and server binaries at the same time using userspace snapshot-fuzzing and network emulation. It's fast and comparably easy to set up.

License: MIT License

Makefile 1.42% Shell 3.74% Python 1.72% Rust 22.44% C 70.34% C++ 0.34%
fuzzing aflplusplus qemu criu

fitm's Introduction

FitM, the Fuzzer in the Middle

FitM, the Fuzzer-in-the-Middle, is a AFL++-based coverage-guided fuzzer for stateful, binary-only client-server applications. It can be used in situations where you would normally turn to grammar-based fuzzers or start patching your target. With FitM you can explore the communication between client and server by fuzzing them at the same time. It builds on top of qemuafl for emulation and CRIU for userspace snapshots. No source code needed!

How it works

The FitM tool uses FitM-qemu for instrumentation. FitM-qemu extends qemuafl with a network emulation layer on the syscall level. With it, we can fuzz two targets (binary A & B) at the same time, usually a server and a client and schedule different snapshots of these processes ("generations") we collect while exploring the protocol. Each generation represents a stage in the protocol's communication levels that the client-server pair speaks. The fuzzer starts in generation 0 with binary A. This binary should produce some output without needing any input. Using the initial output of binary A as seed, FitM will fuzz binary B for a while. Afterwards, FitM creates a set of new snapshots of B, generation 3, for later. Next, the snapshot of generation 0 (binary A) is restored, seeded with generation 1's output and fuzzed (generation 2). A snapshot is always created during a receive call that followed a send call until we fully explore the client-server interaction. The below figure depicts this cycle.

Overview over the different stages of FitM, see paper

See our paper for technical explanations, benchmarks, and further details.

Getting Started

This module uses submodules. Clone with --recurse-submodules.

Alternatively, run the following after cloning:

git submodule init
git submodule update

Building

vagrant up
vagrant ssh
cd /vagrant
make

If you don't want to use the provided Vagrantfile you can read the provided provision.sh script to understand the necessary dependencies. In general you will need packages to build QEMU and Criu. Additionally, you will need a stable rust toolchain.

Running

Run this: FITM_ARGS=config/fitm-args.ftp.json make run

The fuzzer will create the folders active-state, saved-states and cmin-tmp. Whenever afl-cmin is used the inputs that should be fed into cmin are put into cmin-tmp. active-state holds the necessary folder/files for FitM's operation and the restored snapshot's files. The structure is as follows:

  • fd: files that are used by the process. You will find current output here.
  • in, out: afl's in/out folders.
  • next_snapshot: populated during create_next_snapshot() with the files produced by criu. Renamed to snapshot and eventually copied to saved-states.
  • out_postrun: the content of the out folder after fuzzing.
  • outputs: folder with "persisted" outputs. Generally, output is written to files in the fd folder, but since those files (and the folder) need to be returned to the state they were in before restoring in order to snapshot the next state we collect outputs in an extra step create_outputs() and store them in the outputs folder.
  • snapshot: serialized process data, i.e. the snapshot. The criu docs are helpful here.
  • envfile: env for target process. Read by getenv_from_file() (see ./fitm-qemu/FitM-qemu/qemuafl/fitm.h) in QEMU syscall translation layer.
  • pipes: names of forkserver pipes. Needed to reconnect pipes in restored snapshot to pipes from forkserver. Done with the --inherit-fd argument in ./active-state/restore.sh.
  • prev_input / prev_input_path: input and path to input file that was used to generate current snapshot.
  • restore.log: criu output of the snapshot restore process.
  • run-info: serialized FITMSnapshot object for the active state. Helps to know where you are.
  • snapshot_map: afl-map output for the snapshot with prev_input.
  • stdout/stderr: stdout/err of the target process.
  • stdout-afl/stderr-afl: stdout/err from the AFL process.

Each folder in saved-states represents one snapshot plus FitM-related files. Some of the files, e.g. pipes, related to each snapshot are specific to the snapshots state and thus have to be managed for every state. In general, criu breaks very quickly if a process had a handle to a file while it ran, but the file changes (contents, path, size, metadata) in any way between snapshot and restore.

Apart from the above three folder you will find the following temporary files in the repo's root folder after running FitM:

  • criu_stdout/criu_stderr: stdout/err of the criu server process. To create snapshots each target process communicates with a separate criu process, the criu server.
  • fdinfo, file: Criu has a tool called "crit" that can be used to parse the binary files that are part of a snapshot folder. We use crit to parse the open files in the target process and attach them accordingly. The parsing code can be found in create_restore.py. This script create a bash script restore.sh based on the restore.sh.tmp template for each state. The restore.sh script is the target given to AFL when starting another fuzz run. The script will call criu restore and by using the --restore-detached flag we make sure that the target process ends up as a child of AFL after criu has exited.

Special Files

fitm-args.json

This file is used to configure FitM. The meaning of each key is as follows:

  • client: path to the binary that should be gen0.
  • client_args: command-line arguments for the client binary.
  • client_envs: environment variables that will be available to the client binary.
  • client_files: currently unused.
  • server: path to the binary that should be gen1.
  • server_args: command-line arguments for the server binary.
  • server_envs: environment variables that will be available to the server binary.
  • server_files: currently unused.
  • run_time: time spent fuzzing each generation in seconds.
  • server_only: boolean to indicate that we only want to fuzz the server. The client is only fuzzed for 100ms and it's output is disregarded.

fitm-state.json

A JSON file used to save state information from previous runs. This allows us to abort fuzzing at any point, introduce changes and then reuse the accumulated states in ./saved-states. The file holds a serialized form of the generation_snaps variable. This variable holds a list of generations that need to be fuzzed, each generation being another list of FITMSnapshot objects ([[gen0_snap0, gen0_snap1, .., gen0_snapN], [gen1_snap0, .. gen1_snapN], .., [genN_snap0, .., genN_snapN]]).

Debugging

When using FitM with a new target you will probably investigate weird behaviour sooner or later. You will generally want to check ./active-state/restore.log and see the log end with a message similar to this one:

(00.052019) Running pre-resume scripts
(00.052043) Restore finished successfully. Tasks resumed.
(00.052062) Writing stats
(00.052705) Running post-resume scripts

At this point you know that the target was successfully restored by criu and any further fails come from the target misbehaving. You will want to check ./active-state/stdout for the target's stdout, in case you are doing printf-debugging. When you set the FITM_DEBUG macro to 1 you will find a lot of debug prints there that might give you a first idea of where things are breaking. Next, you can add QEMU_STRACE with a value of 1 to the client_envs/server_envs in your fitm-args.json to get strace output from QEMU. You will see the strace output in ./active-state/stderr. These are the syscalls that the emulated target sends to emulation layer. By diffing the syscall traces of the target with and without FITM enabled you should be able to learn where things break (see FITM_DISABLED in ./fitm-qemu/FitM-qemu/linux-user/syscall.c).

Paper / Citing / More Information

The FitM paper

For further details, see our paper at BAR 2022.

To cite, use:

@InProceedings{fitm,
  title     = {FitM: Binary-Only Coverage-Guided Fuzzing for Stateful Network Protocols},
  author    = {Maier, Dominik and Bittner, Otto and Munier, Marc and Beier, Julian},
  booktitle = {Workshop on Binary Analysis Research (BAR), 2022},
  year      = 2022,
}

fitm's People

Contributors

5aint2ero avatar derpsteb avatar domenukk avatar liikt avatar mmunier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fitm's Issues

get_traces: cache most recent traces

Taken from TODO in code:

Cache the most recent (<=3) snapshot maps for a given generation. This reduces the number of times we have to iterate over the saved states folder AND the number of files we have to read.
When implementing this we should think about whether or not it takes up too much memory to hold traces for up to 3 gens for all states in the queue.

cli: Internal use of arrays

Is there a problem in using vecs instead of arrays to allow for configurable parameters?

I remember @domenukk wanted to use arrays and strs to reduce memory footprint.

Example run failed

Hi,
I built FitM with make, and run the example using FITM_ARGS=config/fitm-args.ftp.json make run but got the following failure:

FITM_ARGS=config/fitm-args.ftp.json make run
cargo build --release
   Compiling fitm v0.1.0 (/root/projects/fuzzer/FitM)
    Finished release [optimized + debuginfo] target(s) in 27.20s
sudo rm -rf ./active-state
sudo rm -rf ./cmin-tmp
sudo ./target/release/fitm config/fitm-args.ftp.json
cwd: "/root/projects/fuzzer/FitM"

    __________________  ___
   / ____/  _/_  __/  |/  /
  / /_   / /  / / / /|_/ / 
 / __/ _/ /  / / / /  / /  
/_/   /___/ /_/ /_/  /_/   


File fitm-state.json not found. Restarting from scratch.
No valid state to resume. Starting fresh :)
==== [*] Time start init_run: 2022-04-04 21:13:55 ====
[*] Init run finished with exit code None
[*] Target was killed by signal. Assuming dump success.
thread 'main' panicked at '[!] parse_pid failed to parse JSON in utils::parse_pid: UnexpectedEndOfJson', src/utils.rs:67:59
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
make: *** [Makefile:40:run] error 101

Could you please help me?

client/server_args with spaces in them?

Hi,

Thanks for sharing this interesting work!

I am trying to fuzz a proprietary binary/client where client_args and server_args have spaces in them - for example --server --arg1 value1 --arg2 value2 --arg3

I am fairly sure I am missing something json related here but if I try to run the session with just 1 argument I get expected output, if I try with 2 arguments I get output I would expect if I missed the spaces out.

I am guessing I need to do something different to ensure the spaces are not stripped as if I recall correctly json strips spaces out, any pointers would be appreciated?

Alan

Some thing wrong

I can't even start the program, so sad. But there are no errors in the make process

vagrant@ubuntu-focal:/vagrant$ FITM_ARGS=config/fitm-args.ftp.json make run
cargo build --release
sudo rm -rf ./active-state
sudo rm -rf ./cmin-tmp
sudo ./target/release/fitm config/fitm-args.ftp.json
sudo: ./target/release/fitm: command not found
make: *** [Makefile:40: run] Error 1

vagrant@ubuntu-focal:/vagrant$ ls
AFLplusplus Makefile config debug fitm.pdf restore.sh.tmp src
Cargo.toml README.md create_restore.py fitm-qemu libqasan.so rpc.proto tests
LICENSE Vagrantfile criu fitm-qemu-trace misc rust-toolchain tmp

criu dump failed

Hi, I setup a new ubuntu20.04 vm, run commands in misc/provision.sh to prepare the environment.

Then I try the example with make and FITM_ARGS=config/fitm-args.ftp.json make run, but I got criu dump failed error message. The fuzzer stuck at gen1 for about 1min then exit.

Could you please help? Thank you.

cargo build --release
    Finished release [optimized + debuginfo] target(s) in 0.03s
sudo rm -rf ./active-state
sudo rm -rf ./cmin-tmp
sudo -E ./target/release/fitm config/fitm-args.ftp.json
cwd: "/home/qwe/FitM"

    __________________  ___
   / ____/  _/_  __/  |/  /
  / /_   / /  / / / /|_/ / 
 / __/ _/ /  / / / /  / /  
/_/   /___/ /_/ /_/  /_/   


File fitm-state.json not found. Restarting from scratch.
No valid state to resume. Starting fresh :)
==== [*] Time start init_run: 2022-04-15 19:39:09 ====
[*] Init run finished with exit code None
[*] Target was killed by signal. Assuming dump success.
[*] Init run finished with exit code Some(0)
[!] Unexpected exit status '0' from snapshot creation.
thread 'main' panicked at 'Namespace call failed with error Custom { kind: Other, error: "[!] criu dump failed, check active-state dir." }', src/namespacing.rs:135:31
stack backtrace:
   0: rust_begin_unwind
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/panicking.rs:143:14
   2: fitm::namespacing::NamespaceContext::execute
             at /home/qwe/FitM/src/namespacing.rs:135:31
   3: fitm::FITMSnapshot::init_run
             at /home/qwe/FitM/src/lib.rs:269:28
   4: fitm::run
             at /home/qwe/FitM/src/lib.rs:1351:13
   5: fitm::main
             at /home/qwe/FitM/src/main.rs:88:21
   6: core::ops::function::FnOnce::call_once
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
[*] Init run finished with exit code None
[*] Target was killed by signal. Assuming dump success.
==== [*] Time end init_run: "2022-04-15 19:39:10" ====
---> Round 1: Fuzzing Gen 1
==== [*] Queue before process_stage contains: [[], ["fitm-gen1-state0"], ["fitm-gen2-state0"], []] ====
==== [*] Time start process_stage gen 1: "2022-04-15 19:39:10" ====
     -> Processing stage with 1 inputs.
==== [*] Time start process_stage loop step fitm-gen1-state0: "2022-04-15 19:39:10" ====
==== [*] Wrote cmin contents from /home/qwe/FitM/cmin-tmp to /home/qwe/FitM/saved-states/fitm-gen1-state0/in ====
==== [*] Start fuzzing fitm-gen1-state0 ("ftp") ====
         Fuzzer Stats:
         - cycles_done       : 1
         - execs_done        : 62990
         - execs_per_sec     : 1049.52
         - paths_total       : 103
         - max_depth         : 2
         - stability         : 100.00%
         - unique_crashes    : 0
         - unique_hangs      : 0
==== [*] Finished fuzzing fitm-gen1-state0 ====
==== [*] Wrote cmin contents from /home/qwe/FitM/cmin-tmp to /home/qwe/FitM/saved-states/fitm-gen1-state0/out/main/queue ====
==== [*] Creating outputs for state: fitm-gen1-state0 ====
==== [*] Using input: "/home/qwe/FitM/saved-states/fitm-gen1-state0/out/main/queue/id:000068,time:0,orig:id:000131,src:000055+000118,time:58311,op:splice,rep:2" ====
thread 'main' panicked at '[!] create_outputs_file(): Snapshot run failed: Os { code: 10, kind: Uncategorized, message: "No child processes" }', src/lib.rs:552:55
stack backtrace:
   0: rust_begin_unwind
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/panicking.rs:143:14
   2: core::result::unwrap_failed
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/result.rs:1749:5
   3: core::result::Result<T,E>::expect
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/result.rs:1022:23
   4: fitm::FITMSnapshot::create_outputs_file::{{closure}}
             at /home/qwe/FitM/src/lib.rs:552:21
   5: fitm::namespacing::NamespaceContext::execute
             at /home/qwe/FitM/src/namespacing.rs:126:27
   6: fitm::FITMSnapshot::create_outputs_file
             at /home/qwe/FitM/src/lib.rs:525:27
   7: fitm::FITMSnapshot::create_outputs
             at /home/qwe/FitM/src/lib.rs:623:13
   8: fitm::process_stage
             at /home/qwe/FitM/src/lib.rs:981:9
   9: fitm::run
             at /home/qwe/FitM/src/lib.rs:1458:30
  10: fitm::main
             at /home/qwe/FitM/src/main.rs:88:21
  11: core::ops::function::FnOnce::call_once
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
[!] Error during create_outputs execution. Please check latest statefolder for output
make: *** [Makefile:40: run] Error 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.