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 for fuzzinator.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 not None, change working directory before invoking AFL.

  • env: if not None, 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 not None, pass its value as the -t timeout parameter to AFL.

  • dictionary: if not None, 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 of fuzzer_class that transfers control to init, enter, exit, or call 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 type cls. 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 by super().call(cls, obj, index=index) (which will call this method, and then transitively the original __call__) or by super(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 type cls. 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 by super().enter(cls, obj) (which will call this method, and then transitively the original __enter__) or by super(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 type cls. 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 by super().exit(cls, obj, *exc) (which will call this method, and then transitively the original __exit__) or by super(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 type cls. 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 by super().init(cls, obj, **kwargs) (which will call this method, and then transitively the original __init__) or by super(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 not None, 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 not None, 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