Fuzzers: package fuzzinator.fuzzer
¶
- class fuzzinator.fuzzer.AFLRunner(*, afl_fuzz, input, output, sut_command, cwd=None, env=None, timeout=None, dictionary=None, master_name=None, slave_name=None, work_dir, **kwargs)¶
Wrapper around AFL to be executed continuously in a subprocess. The findings of AFL are periodically checked and any new test cases are returned as test inputs to the SUT. (Thus, all AFL findings are processed, extended, and filtered by any and all SUT decorators, uniqueness is determined, etc.)
For AFL, it is best not to run multiple instances in parallel.
Mandatory parameters of the fuzzer:
afl_fuzz
: path to the AFL fuzzer tool.sut_command
: the string to append to the command string used to invoke AFL, probably the same string that is used forfuzzinator.call.SubprocessCall
’s command parameter (the{test}
substring is automatically replaced with the@@
input file placeholder used by AFL).input
: the directory of initial test cases for AFL.
Optional parameters of the fuzzer:
cwd
: if notNone
, change working directory before invoking AFL.env
: if notNone
, a dictionary of variable names-values to update the environment with (AFL_NO_UI=1
will be added automatically to suppress AFL’s own UI).timeout
: if notNone
, pass its value as the-t
timeout parameter to AFL.dictionary
: if notNone
, pass its value as the-x
dictionary parameter to AFL.master_name
: the name of the master fuzzer instance which will perform deterministic checks.slave_name
: the name of a slave fuzzer instance which will proceed to random tweaks. For further details check: https://github.com/mirrorer/afl/blob/master/docs/parallel_fuzzing.txt
Example configuration snippet:
[sut.foo] call=fuzzinator.call.SubprocessCall [sut.foo.call] command=./bin/foo {test} cwd=/home/alice/foo env={"BAR": "1"} [fuzz.foo-with-afl] sut=foo fuzzer=fuzzinator.fuzzer.AFLRunner batch=inf instances=1 [fuzz.foo-with-afl.fuzzer] afl_fuzz=/home/alice/afl/afl-fuzz sut_command=${sut.foo.call:command} cwd=${sut.foo.call:cwd} env=${sut.foo.call:env} input=/home/alice/foo-inputs
- class fuzzinator.fuzzer.ByteFlipDecorator(*, frequency, min_byte=32, max_byte=126, **kwargs)¶
Decorator to add extra random byte flips to fuzzer results.
Mandatory parameter of the decorator:
frequency
: the length of the test divided by this integer number gives the number of bytes flipped.
Optional parameters of the decorator:
min_byte
: minimum value for the flipped bytes (integer number, 32 by default, the smallest ASCII code of the printable characters).max_byte
: maximum value for the flipped bytes (integer number, 126 by default, the largest ASCII code of the printable characters).
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-flips] sut=foo fuzzer=fuzzinator.fuzzer.ListDirectory fuzzer.decorate(0)=fuzzinator.fuzzer.ByteFlipDecorator batch=inf [fuzz.foo-with-flips.fuzzer] outdir=/home/alice/foo-old-bugs/ [fuzz.foo-with-flips.fuzzer.decorate(0)] frequency=100 min_byte=0 max_byte=255
- class fuzzinator.fuzzer.FileWriterDecorator(*, filename, work_dir, **kwargs)¶
Decorator for fuzzers that create str or bytes-like output. The decorator writes the test input to a temporary file (relative to an implicit temporary working directory) and replaces the output with the name of that file.
Mandatory parameter of the decorator:
filename
: name pattern for the temporary file, which may contain the substring{uid}
as a placeholder for a unique string (replaced by the decorator).
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-random] sut=foo fuzzer=fuzzinator.fuzzer.RandomContent fuzzer.decorate(0)=fuzzinator.fuzzer.FileWriterDecorator [fuzz.foo-with-random.fuzzer.decorate(0)] filename=test-{uid}.txt
- class fuzzinator.fuzzer.Fuzzer¶
Abstract base class to represent a (random) test case generator, a.k.a. fuzzer.
- __call__(*, index)¶
Request a test case from the fuzzer. Return the test case (or
None
to signal that the fuzzer is exhausted and cannot generate more test cases).Raises
NotImplementedError
by default.- Parameters:
index (int) – A running counter distinguishing test case requests in a fuzz job.
- Returns:
The generated test case, or
None
if the fuzzer is exhausted. The semantics of the generated test case is not restricted by the framework. It is the responsibility of the configuration to ensure that the SUT targeted by the fuzzer can be called with the tests case.- Return type:
Any or None
- __enter__()¶
Set up steps before requesting test cases from the fuzzer.
No-op by default.
- __exit__(*exc)¶
Tear down steps after test case generation.
No-op by default.
- class fuzzinator.fuzzer.FuzzerDecorator¶
Base class for
Fuzzer
decorators.- __call__(fuzzer_class)¶
Return a decorated version of
fuzzer_class
. Create a subclass offuzzer_class
that transfers control toinit
,enter
,exit
, orcall
when its__init__
,__enter__
,__exit__
, or__call__
methods are invoked.- Parameters:
fuzzer_class – The fuzzer class to decorate.
- Returns:
The decorated version of the fuzzer class.
- call(cls, obj, *, index)¶
Call
obj
of typecls
. The default operation is to call the__call__
method of the original version of the fuzzer class and return its result.Subclasses of
FuzzerDecorator
may override this method if customization of calling the fuzzer is needed. Usually, the overridden method has to call the original__call__
at some point, which can be performed either bysuper().call(cls, obj, index=index)
(which will call this method, and then transitively the original__call__
) or bysuper(cls, obj).__call__(index=index)
(which calls the original__call__
directly).- Parameters:
cls – The decorated version of the fuzzer class, as returned by
__call__
.obj – The fuzzer instance to invoke.
index – A running counter, as defined by
Fuzzer.__call__
.
- Returns:
The generated test case, as defined by
Fuzzer.__call__
.
- enter(cls, obj)¶
Enter the context managed by
obj
of typecls
. The default operation is to call the__enter__
method of the original version of the fuzzer class and return its result.Subclasses of
FuzzerDecorator
may override this method if customization of entering the context is needed. Usually, the overridden method has to call the original__enter__
at some point, which can be performed either bysuper().enter(cls, obj)
(which will call this method, and then transitively the original__enter__
) or bysuper(cls, obj).__enter__()
(which calls the original__enter__
directly).- Parameters:
cls – The decorated version of the fuzzer class, as returned by
__call__
.obj – The fuzzer instance managing the context.
- Returns:
A value as defined by the context management protocol (usually,
obj
).
- exit(cls, obj, *exc)¶
Exit the context managed by
obj
of typecls
. The default operation is to call the__exit__
method of the original version of the fuzzer class and return its result.Subclasses of
FuzzerDecorator
may override this method if customization of exiting the context is needed. Usually, the overridden method has to call the original__exit__
at some point, which can be performed either bysuper().exit(cls, obj, *exc)
(which will call this method, and then transitively the original__exit__
) or bysuper(cls, obj).__exit__(*exc)
(which calls the original__exit__
directly).- Parameters:
cls – The decorated version of the fuzzer class, as returned by
__call__
.obj – The fuzzer instance managing the context.
exc – The exception that caused the context to be exited (if any), as defined by the context management protocol.
- Returns:
Whether to suppress the exception in
exc
, as defined by the context management protocol.
- init(cls, obj, **kwargs)¶
Initialize
obj
of typecls
. The default operation is to call the__init__
method of the original version of the fuzzer class.Subclasses of
FuzzerDecorator
may override this method if customization of the initialization is needed. Usually, the overridden method has to call the original__init__
at some point, which can be performed either bysuper().init(cls, obj, **kwargs)
(which will call this method, and then transitively the original__init__
) or bysuper(cls, obj).__init__(**kwargs)
(which calls the original__init__
directly).- Parameters:
cls – The decorated version of the fuzzer class, as returned by
__call__
.obj – The fuzzer instance to initialize.
- class fuzzinator.fuzzer.ListDirectory(*, pattern, contents=True, **kwargs)¶
A simple test generator to iterate through existing files in a directory and return their contents one by one. Useful for re-testing previously discovered issues.
Since the fuzzer starts iterating from the beginning of the directory in every fuzz job, there is no gain in running multiple instances of this fuzzer in parallel. Because of the same reason, the fuzzer should be left running in the same fuzz job batch until all the files of the directory are processed.
Mandatory parameter of the fuzzer:
pattern
: shell-like pattern to the test files.
Optional parameter of the fuzzer:
contents
: if it’s true then the content of the files will be returned instead of their path (boolean value, True by default).
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-oldbugs] sut=foo fuzzer=fuzzinator.fuzzer.ListDirectory instances=1 batch=inf [fuzz.foo-with-oldbugs.fuzzer] pattern=/home/alice/foo-old-bugs/**/*.js
- class fuzzinator.fuzzer.RandomContent(*, min_length=1, max_length=1, **kwargs)¶
Example fuzzer to generate strings of random length from random ASCII uppercase letters and decimal digits.
Optional parameters of the fuzzer:
min_length
: minimum length of the string to generate (integer number, 1 by default)max_length
: maximum length of the string to generate (integer number, 1 by default)
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-random] sut=foo fuzzer=fuzzinator.fuzzer.RandomContent batch=100 [fuzz.foo-with-random.fuzzer] min_length=100 max_length=1000
- class fuzzinator.fuzzer.RandomInteger(*, min_value, max_value, **kwargs)¶
A simple test generator to produce a single random integer number from a predefined interval.
Mandatory parameters of the fuzzer:
min_value
: lower boundary of the interval to generate the number from.max_value
: upper boundary of the interval to generate the number from.
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-randint] sut=foo fuzzer=fuzzinator.fuzzer.RandomNumber batch=100 [fuzz.foo-with-randint.fuzzer] min_value=0 max_value=1000
- class fuzzinator.fuzzer.SubprocessRunner(*, command, cwd=None, env=None, timeout=None, contents=True, encoding=None, work_dir, **kwargs)¶
Wrapper around a fuzzer that is available as an executable and can generate its test cases as file(s) in a directory. First, the external executable is invoked as a subprocess, and once it has finished, the contents of the generated files are returned one by one.
Mandatory parameters of the fuzzer:
command
: string to pass to the child shell as a command to run, which must generate its test cases in the temporary working directory unique to this fuzzer instance (all occurrences of{work_dir}
in the string are replaced by the path to this directory).
Optional parameters of the fuzzer:
cwd
: if notNone
, change working directory before the command invocation (all occurrences of{work_dir}
in the string are replaced by the path to the temporary working directory unique to this fuzzer instance).env
: if notNone
, a dictionary of variable names-values to update the environment with (all occurrences of{work_dir}
in the values are replaced by the path to the temporary working directory unique to this fuzzer instance)..timeout
: run subprocess with timeout.contents
: if it’s true then the content of the files will be returned instead of their path (boolean value, True by default).encoding
: stdout and stderr encoding (default: autodetect).
Example configuration snippet:
[sut.foo] # see fuzzinator.call.* [fuzz.foo-with-bar] sut=foo fuzzer=fuzzinator.fuzzer.SubprocessRunner batch=50 [fuzz.foo-with-bar.fuzzer] command=barfuzzer -n ${fuzz.foo-with-bar:batch} -o {work_dir}
- class fuzzinator.fuzzer.TornadoDecorator(*, template_path=None, static_path=None, url=None, refresh=None, certfile=None, keyfile=None, **kwargs)¶
Decorator for fuzzers to transport generated content through http. It is useful for transporting fuzz tests to browser SUTs.
The decorator starts a Tornado server at the start of the fuzz job and returns an http url as test input. If the SUT accesses the domain root through a GET request, then the decorated fuzzer is invoked and the response is the generated test. Accessing other paths can return static or dynamically rendered content.
When the certfile and possibly also the keyfile optional parameters are defined, the traffic will be served through SSL.
Optional parameters of the fuzzer decorator:
template_path
: Directory containing .html template files. These are served from the path/
without the .html extension.static_path
: Directory from which static files will be served. These are served from the path/static/
.url
: Url template with{port}
and{index}
placeholders, that will be filled in with appropriate values. This is the url that will be served for the SUT as the test case. (Default:http(s)://localhost:{port}?index={index}
)refresh
: Integer number denoting the time interval (in seconds) for the document at the root path (i.e., the test case) to refresh itself. Setting it to 0 means no refresh. (Default: 0)certfile
: Path to a PEM file containing the certificate (Default: None).keyfile
: Path to a file containing the private key (Default: None).
Example configuration snippet:
[sut.foo] # assuming that foo expects a http url as input, which it tries to access # afterwards [fuzz.foo-with-bar-over-http] sut=foo #fuzzer=... fuzzer.decorate(0)=fuzzinator.fuzzer.TornadoDecorator batch=5 [fuzz.foo-with-bar-over-http.fuzzer.decorate(0)] template_path=/home/lili/fuzzer/templates/ static_path=/home/lili/fuzzer/static/ # assuming that there is a main.html in the template_path directory url=http://localhost:{port}/main?index={index} refresh=3