An open API service indexing awesome lists of open source software.

https://github.com/demantz/frizzer

Frida-based general purpose fuzzer
https://github.com/demantz/frizzer

Last synced: about 1 month ago
JSON representation

Frida-based general purpose fuzzer

Awesome Lists containing this project

README

          

Frizzer
=======

A coverage-guided blackbox fuzzer based on the Frida instrumentation framework.

Idea
----

This fuzzer is meant to be quick and relatively easy to set up in scenarios
where no source code is available for a network service. Via Frida it is
possible to retrieve coverage from uninstrumented binaries. Therefore, even
though the fuzzer is not fast or efficient it can still be beneficial during
assessments with restricted time frames.

The fuzzer is written in Python 3 and runs under Linux. However, the fuzzed
application does not necessarily have to run on the same system as long as
Frida is also available for the respective system. The fuzzer can remotely
connect to the Frida instance which runs on the target system.

Currently the fuzzer expects a target which communicates via TCP (plain or TLS)
and is already running. The fuzzer won't start (or restart) the service but
only fuzz it until it crashes.

As the fuzzer is not very efficient it is necessary to restrict the coverage
tracking to the interesting part of the target service. The basic idea is that
the fuzzer will only track coverage during the execution of the main network
protocol handler (i.e. a function which handles the incoming TCP payloads) of
the target service. The address of this function needs to be found via reverse
engineering and has to be provided to the fuzzer.

Installation
------------

The fuzzer is written in Python 3 and depends on the python module `frida-tools`
and `toml`. It is recommended to set up a Python virtual environment:

$ git clone https://cis.ernw.net/dmantz/frida-fuzzer
$ cd frida-fuzzer
$ virtualenv3 venv
$ source venv/bin/activate
$ pip install -e .
$ frizzer --help

The fuzzer also needs radamsa () to be available on the system. For Debian
based systems it can be installed with the following commands:

$ sudo apt update && sudo apt install gcc git make wget
$ git clone https://gitlab.com/akihe/radamsa.git
$ cd radamsa
$ make
$ sudo make install

Usage
-----

First it is necessary to find the main protocol handler function of the target
service. It is important that this function is called exactly once for every
TCP connection that the fuzzer initiates. For example, the `picohttpparser.c`
file (`tests/picohttpparser/picohttpparser.c`) has a function
`parse_request(...)` which matches the above mentioned requirements. Once the
address of this function has been found via reverse engineering, the fuzzing
can be configured.

The first step is to create a new project (this command will create a new
project directory `fuzzproject1`):

$ frizzer init fuzzproject1

The project directory contains the following files/folders:
- config: Config file for the fuzzer
- corpus: Current fuzzing corpus (contains the payloads)
- crashes: Contains all payloads that have led to a crash

After creating the project, the config file has to be edited. The generated file
looks like this:

[fuzzer]
log_level = 3 # debug
debug_mode = false

[target]
process_name = "myprocess"
function = 0x123456
host = "localhost"
port = 7777
ssl = false
remote_frida = false
recv_timeout = 0.1
fuzz_in_process = false
modules = [
"/home/dennis/tools/frida-fuzzer/tests/simple_binary/test",
]

- Change the `process_name` parameter to the name of the process which should
be fuzzed. The fuzzer will resolve the name to a PID (make sure only one
instance of the service is running!) and attach to it via Frida.
- Change the `function` parameter to the address of the protocol handler
function. The fuzzer will hook this function via Frida and start the Frida
Stalker to record which basic blocks are executed. The Stalker is stopped and
the coverage processed as soon as the protocol handler function returns.
- Change the `host` and `port` parameters to point to the service that shall be
fuzzed. The fuzzer will establish a TCP connection for every new payload.
When setting `ssl` to `true` the fuzzer will establish a TLS connection and
send the payload through the TLS socket instead.
- Change the `modules` parameter so that it contains a list of all modules for
which the Stalker should track coverage (i.e. the main executable and
potentially interesting .so files). The modules have to be given with absolute
path! Do not include shared libraries in which you are not interested (e.g.
the libc or other standard libs) as this will generate a lot of coverage
data and render the fuzzing process inefficient.

Finally, add one or more initial payload files to the project:

$ frizzer add -p fuzzproject1 myinitialfiles

In this command, `-p fuzzproject1` specifies the project directory and
`myinitialfiles` is a directory which contains the payload files that shall
be copied over to the corpus directory. If the protocol format is completely
unknown just start with a single file containing a single 'A' and let radamsa
and the coverage tracking figure out the protocol format. This may be too
inefficient and it is recommended to continue reverse engineering as soon as
the fuzzer is running. New payload files can be added at any time with the
`add` subcommand of frizzer.

Now the fuzzer can be started with the following command (note that the service
needs to be running already!):

$ frizzer fuzz -p fuzzproject1

The output should look like this:

[+] Project: {'fuzzer': {'log_level': 3, 'debug_mode': False}, 'target': {'process_name': 'test', 'function': 4198998, 'host': 'localhost', 'port': 7777, 'remote_frida': False, 'fuzz_in_process': False, 'modules': ['/home/dennis/frida-fuzzer/tests/simple_binary/test']}}
[+] Loading script: /home/dennis/frida-fuzzer/frizzer/frida_script.js
[+] Attached to pid 502277!
[+] Filter coverage to only include the following modules:
/home/dennis/tools/frida-fuzzer/tests/simple_binary/test
[+] Initializing Corpus...
[*] 2020-06-24 11:34:02 [iteration=1] tmpprojdir/corpus/1
[!] 2020-06-24 11:34:02 [iteration=1] Inconsistent coverage for tmpprojdir/corpus/1!
[*] 2020-06-24 11:34:02 [iteration=1] tmpprojdir/corpus/2
[!] 2020-06-24 11:34:02 [iteration=1] Inconsistent coverage for tmpprojdir/corpus/2!
[*] Using 4 input files which cover a total of 10 basic blocks!
[D] Corpus: ['tmpprojdir/corpus/1', 'tmpprojdir/corpus/2', 'tmpprojdir/corpus/3', 'tmpprojdir/corpus/4']
[*] [seed=0] speed=[ 67 exec/sec (avg: 67)] coverage=[10 bblocks] corpus=[4 files] last new path: [-1] crashes: [0]
[*] [seed=1] speed=[ 87 exec/sec (avg: 76)] coverage=[10 bblocks] corpus=[4 files] last new path: [-1] crashes: [0]
[*] [seed=2] speed=[ 85 exec/sec (avg: 79)] coverage=[10 bblocks] corpus=[4 files] last new path: [-1] crashes: [0]
[*] [seed=3] speed=[ 90 exec/sec (avg: 81)] coverage=[10 bblocks] corpus=[4 files] last new path: [-1] crashes: [0]
[*] [seed=4] speed=[ 91 exec/sec (avg: 83)] coverage=[10 bblocks] corpus=[4 files] last new path: [-1] crashes: [0]
[*] [seed=5] 2020-06-24 11:34:02 tmpprojdir/corpus/3
[+] Found new path: [5] tmpprojdir/corpus/3
[*] [seed=5] speed=[ 86 exec/sec (avg: 83)] coverage=[12 bblocks] corpus=[4 files] last new path: [5] crashes: [0]
[*] [seed=6] speed=[ 88 exec/sec (avg: 84)] coverage=[12 bblocks] corpus=[5 files] last new path: [5] crashes: [0]
...

The `seed` value reveres to the seed which is passed to radamsa. By default the
seed will start at 0 and is increased in each round. Each round will produce
new payloads for all files which are currently in the `corpus` directory. This
is done by passing each file and the current seed to radamsa. The resulting new
payloads are sent to the target. If the coverage for a specific payload
contains new basic blocks (i.e. a `new path`), the payload is added to the
corpus.

Also have a look at the test cases to get an idea on how to use the fuzzer!