Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1ffe060
cfz: [feat] initial, very rough implementation
OleksiiOleksenko May 23, 2025
d9c86f6
cfz/pub_gen: [fix] restore terminal after AFL++ output
OleksiiOleksenko May 27, 2025
6604041
cfz: [fix] add missing invocation interface
OleksiiOleksenko May 27, 2025
5708527
cfz/trace: [fix] tracer should not terminate on target errors
OleksiiOleksenko May 27, 2025
3a49359
cfz/log: [feat] add a progress bar to the tracing stage
OleksiiOleksenko May 28, 2025
e49df80
cfz/report: [refact] store trace source in the Trace class
OleksiiOleksenko May 29, 2025
b8c17a0
cfz/config: [fix] conctract clauses were not set from the YAML config
OleksiiOleksenko May 29, 2025
45cacb3
cfz/config: [feat] add force_overwrite and archive_dir options
OleksiiOleksenko May 29, 2025
88dad3c
cfz/report: [feat] add progress bar to analyzer
OleksiiOleksenko May 29, 2025
409c52c
cfz/cli: [feat] add interface to run all three stages together
OleksiiOleksenko May 29, 2025
380cb47
cfz/config: [fix] singletone flag set incorrectly, rendering ineffective
OleksiiOleksenko May 30, 2025
6255c1b
cfz/test: [feat] add unit tests for configuration manager
OleksiiOleksenko May 30, 2025
a6cd1df
cfz/conf: [fix] working_dir requirement was not enforced
OleksiiOleksenko May 30, 2025
74aefe9
cfz/test: [feat] style and type checks
OleksiiOleksenko May 30, 2025
c2409a1
cfz/test: [feat] include cfz branch into github CI
OleksiiOleksenko May 30, 2025
6a8e7b5
cfz/log: [feat] add a logging module to the fuzzer
OleksiiOleksenko Jun 2, 2025
b47f5be
cfz/trace: [feat] add a determinism check before starting tracing
OleksiiOleksenko Jun 2, 2025
90e7a82
cfz/report: [feat] reporting in a more detailed json format
OleksiiOleksenko Jun 2, 2025
66b0587
cfz/cli: [feat] add --help-config flag
OleksiiOleksenko Jun 7, 2025
076b243
cfz/report: [feat] add ability to control verbosity of the report
OleksiiOleksenko Jun 7, 2025
d0b2dc5
cfz/conf: [feat] add afl_exec_timeout_ms option
OleksiiOleksenko Jun 7, 2025
8dbd1ca
cfz/trace: [fix] terminate on failed execution during nondeterminism …
OleksiiOleksenko Jun 12, 2025
a690bda
cfz/report: [feat] enable allow-listing known bugs
OleksiiOleksenko Jun 16, 2025
9231a51
cfz/report: [feat] record campaign coverage
OleksiiOleksenko Jun 18, 2025
fd2b275
cfz/config: [fix] CI fail when llvm not installed
OleksiiOleksenko Jun 19, 2025
96afce1
cfz/*: [feat] port to new DR backend
AlviseDeFaveri Jun 16, 2025
98740dc
cfz/*: [refact] use tqdm
AlviseDeFaveri Jun 8, 2025
0a66a9e
cfz/*: [fix] size of file names must be the same
AlviseDeFaveri Jun 13, 2025
9ef8e82
cfz/config: [fix] coverage option was never set
OleksiiOleksenko Jun 19, 2025
5115e61
cfz: [refact] minor style changes
OleksiiOleksenko Jun 19, 2025
df499db
cfz: [feat] generate public and private inputs together
OleksiiOleksenko Jun 27, 2025
8d0ad69
model/dr: [feat] log registers defs/uses
AlviseDeFaveri Jun 19, 2025
af47cdf
model/dr: [feat] log indirect calls in debug trace
AlviseDeFaveri Jul 14, 2025
cf89516
cfz: [feat] add triaging tool
AlviseDeFaveri Jul 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/python-lint-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ on:
- main-fixes
- pre-release
- dev
- feature-software-testing
pull_request:
branches:
- main
- main-fixes
- pre-release
- dev
- feature-software-testing

jobs:
build:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ dbg/
site
dist/
.cache/
*.asm
*.bin
*.dat
13 changes: 13 additions & 0 deletions consfuzz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python3
"""
File: Command Line Interface to Contract-based Software Fuzzer (ConSFuzz)

Copyright (C) Microsoft Corporation
SPDX-License-Identifier: MIT
"""
import sys
from consfuzz.cli import main

if __name__ == '__main__':
exit_code = main()
sys.exit(exit_code)
122 changes: 122 additions & 0 deletions consfuzz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Software Leakage Fuzzer

Note: This module is at the experimental stage of development and its interfaces
may (and likely will) change in the future.

This module leverages a leakage model to detect side-channel information leaks
in software binaries. The leakage model is the same one as used by the hardware fuzzer,
and it is assumed to be already tested against the target CPU. The software fuzzer uses
this model to collect contract traces for the target binary.

The software fuzzer takes as input a target binary and a grammar describing the format of
the binary's inputs. The grammar must specify which parts of the input are public and which
are private.
FIXME: the current prototype doesn't actually use a grammar, but instead assumes
that the target binary takes two files as input: one for public data and one for private data.

The goal of the software fuzzer is to identify cases where contract traces depend on
the private data, which is a sign of information leakage. To this end, the fuzzer checks
traces for the non-interference property: if two executions of the binary with different
private values but identical public data produce different traces, then the binary is
leaking information.

The fuzzer operates in three stages:

## THE BELOW IS NOT YET IMPLEMENTED (SEE "ACTUAL EXAMPLE" BELOW)

## Stage 1: Public Input Generation

The fuzzer uses AFL++ to generate a set of public inputs that cover a wide range of execution paths
in the target binary.

Example:
```
./consfuzz.py pub_gen -c config.yaml -w ~/consfuzz-results/ -t 60 --target-cov 5 -- /usr/bin/openssl enc -e -aes256 -out enc.bin -in @@ -pbkdf2 -pass @#
```

## Stage 2: [NAME TBD]

The second stage combines generation of secret inputs (fully random) and tracing of the binary.
The tracing is done for each pair of public and secret inputs, and the traces are
collected in a directory. The underlying tracing engine is the DynamoRIO-based backend of Revizor
(see `rvzr/model_dynamorio/backend`).

Example:
```
./consfuzz.py stage2 -c config.yaml -w ~/consfuzz-results/ -n 10 -- /usr/bin/openssl enc -e -aes256 -out enc.bin -in @@ -pbkdf2 -pass @#
```

## Stage 3: Leakage Analysis & Reporting

The third stage analyzes the traces collected in the previous stage and reports
the results.

Example:
```
./consfuzz.py report -c config.yaml -w ~/consfuzz-results/ -b /usr/bin/openssl
```

## Stage 4: Triaging

A line in the report might look something like this:


```yaml
{
"seq": {
"D": {
"lib/blockciphermodes.c:281": {
"4456491": [
"/home/ubuntu/results/stage2/id:000022,src:000014,time:302,execs:289,op:havoc,rep:1/002.trace:155734:155734",
```

To triage a violation you can use `consfuzz inspect` to either:

1. Inspect it with GDB
1. Print a use-def graph, both a textual version and a `.dot` graph


### GDB Script

As an example for the above violation, you can run:

```
./consfuzz.py inspect -c consfuzz.yaml --violation "D" /home/ubuntu/results/stage2/id:000022,src:000014,time:302,execs:289,op:havoc,rep:1/002.trace:155734:155734
```

This will:
1. analyze the trace to get the relevant PC
2. generate a debug trace (`.dbgtrace`)
* the original command is taken from `<PATH_OF_TRACE>.log` which should be generated by the fuzzer
3. find the same instruction in the debug trace
4. generate a gdb script to reach the desired speculative instruction.

Finally, a `gdb` command is printed at the end that can be used to spawn a shell at the leakage point. This gdb command will source a custom GDB plugin (`triage/plugin.py`) which makes the `spec` command available (`help spec`).

Following invocations can be use `--skip-tracing` to avoid rebuilding a debug trace.

### Use-Def Chains

By adding `--usedef` to the command, the tool will also generate two files:

* `/home/ubuntu/results/stage2/[...]/002.usedef` contains a textual representation of the reverse use-def analysis
* `/home/ubuntu/results/stage2/[...]/002.usedef.dot` contains a graphiz representation of the same

Such chains can be _very_ long. To enhance analysis, you can:

* Add a **baseline** with `--baseline`: this will add a baseline trace that will be used for pruning values that are the same
* `--baseline='auto'` simply selects the corresponding `000.trace` in the same folder
* Add **declassified symbols** and **key expansions** that cause the analysis to stop earlier. This should be done by
1. adding `--binary <PATH_OF_THE_BINARY>` to the command
2. adding the corresponding source_code_file:line entry in the dedicated list inside `config.yaml`


## ACTUAL EXAMPLE

```
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

./consfuzz.py pub_gen -c dbg/consfuzz.yaml -w ~/results/ -t 10 --target-cov 50 -- ~/eval-rvzr-sw/drivers/bearssl/bearssl -k @# -i ~/eval-rvzr-sw/drivers/bearssl/test/iv.bin -o enc.bin @@
./consfuzz.py stage2 -c dbg/consfuzz.yaml -w ~/results/ -n 2 -- ~/eval-rvzr-sw/drivers/bearssl/bearssl -k @# -i ~/eval-rvzr-sw/drivers/bearssl/test/iv.bin -o enc.bin @@
./consfuzz.py report -c dbg/consfuzz.yaml -w ~/results -b ~/eval-rvzr-sw/drivers/bearssl/bearssl
```
7 changes: 7 additions & 0 deletions consfuzz/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# flake8: noqa
# pylint: skip-file

from .config import *
from .fuzzer import *

__version__ = "0.0.1"
Loading