Skip to main content

coverage-guided fuzz testing for python

Project description

pythonfuzz: coverage-guided fuzz testing for python

Join the chat at https://slack.fuzzit.dev

PythonFuzz is coverage-guided fuzzer for testing python packages.

Fuzzing for safe languages like python is a powerful strategy for finding bugs like unhandled exceptions, logic bugs, security bugs that arise from both logic bugs and Denial-of-Service caused by hangs and excessive memory usage.

Fuzzing can be seen as a powerful and efficient strategy in real-world software in addition to classic unit-tests.

Usage

Fuzz Target

The first step is to implement the following function (also called a fuzz target). Here is an example of a simple fuzz function for the built-in html module

from html.parser import HTMLParser
from pythonfuzz.main import PythonFuzz


@PythonFuzz
def fuzz(buf):
    try:
        string = buf.decode("ascii")
        parser = HTMLParser()
        parser.feed(string)
    except UnicodeDecodeError:
        pass


if __name__ == '__main__':
    fuzz()

Features of the fuzz target:

  • fuzz will call the fuzz target in an infinite loop with random data (according to the coverage guided algorithm) passed to buf( in a separate process).
  • The function must catch and ignore any expected exceptions that arise when passing invalid input to the tested package.
  • The fuzz target must call the test function/library with with the passed buffer or a transformation on the test buffer if the structure is different or from different type.
  • Fuzz functions can also implement application level checks to catch application/logical bugs - For example: decode the buffer with the testable library, encode it again, and check that both results are equal. To communicate the results the result/bug the function should throw an exception.
  • pythonfuzz will report any unhandled exceptions as crashes as well as inputs that hit the memory limit specified to pythonfuzz or hangs/they run more the the specified timeout limit per testcase.

Running

The next step is to download js-fuzz and then run your fuzzer

pip install pythonfuzz
python examples/htmlparser/fuzz.py

#394378 NEW     cov: 608 corp: 24 exec/s: 1119 rss: 10.73828125 MB
subclasses of ParserBase must override error()
Traceback (most recent call last):
  File "/Users/yevgenyp/fuzzitdev/pythonfuzz/pythonfuzz/fuzzer.py", line 21, in worker
    target(buf)
  File "examples/htmlparser/fuzz.py", line 12, in fuzz
    pass
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/html/parser.py", line 111, in feed
    self.goahead(0)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/html/parser.py", line 179, in goahead
    k = self.parse_html_declaration(i)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/html/parser.py", line 264, in parse_html_declaration
    return self.parse_marked_section(i)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/_markupbase.py", line 159, in parse_marked_section
    self.error('unknown status keyword %r in marked section' % rawdata[i+3:j])
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/_markupbase.py", line 34, in error
    "subclasses of ParserBase must override error()")
NotImplementedError: subclasses of ParserBase must override error()
crash was written to crash-dbfa437e5956643645681fe6a3ac76997be0b29a7c7af82d88c8c390f379502d
crash = 3c215b63612121

This example quickly finds an an unhandled exception/flow in a few minutes.

Corpus

PythonFuzz will generate and test various inputs in an infinite loop. corpus is optional directory and will be used to save the generated testcases so later runs can be started from the same point and provided as seed corpus.

PythonFuzz can also start with an empty directory (i.e no seed corpus) though some valid test-cases in the seed corpus may speed up the fuzzing substantially.

PythonFuzz tries to mimic some of the arguments and output style from libFuzzer.

More fuzz targets examples (for real and popular libraries) are located under the examples directory and bugs that were found using those targets are listed in the trophies section.

Credits & Acknowledgments

PythonFuzz is a port of fuzzitdev/jsfuzz

which is in turn heavily based on go-fuzz originally developed by Dmitry Vyukov's. Which is in turn heavily based on Michal Zalewski AFL.

For coverage PythonFuzz is using coverage instrumentation and coverage library.

Contributions

Contributions are welcome!:) There are still a lot of things to improve, and tests and features to add. We will slowly post those in the issues section. Before doing any major contribution please open an issue so we can discuss and help guide the process before any unnecessary work is done.

Trophies

Feel free to add bugs that you found with pythonfuzz to this list via pull-request

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pythonfuzz-1.0.0.tar.gz (8.1 kB view details)

Uploaded Source

Built Distribution

pythonfuzz-1.0.0-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file pythonfuzz-1.0.0.tar.gz.

File metadata

  • Download URL: pythonfuzz-1.0.0.tar.gz
  • Upload date:
  • Size: 8.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4

File hashes

Hashes for pythonfuzz-1.0.0.tar.gz
Algorithm Hash digest
SHA256 052474d13be5b248c7a53e6926d12442cd0a0d23725d2c8061b8895db139b74b
MD5 e94ee59102ae0b5982f75a121ed2ef36
BLAKE2b-256 10a21e447e42442ff1fd7aadbbdc118b233f1d8bb306e11ec4142447360a2fab

See more details on using hashes here.

File details

Details for the file pythonfuzz-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pythonfuzz-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4

File hashes

Hashes for pythonfuzz-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7bfb59ea84596aa8133f2ae5d00cd29190fd265dfcf9a081fe7bead149d154d1
MD5 a153f2e1a21435cf66d9d579a52f6ed9
BLAKE2b-256 1a3a15e8503437ed2d670ef48ca40fe3c77088aef5b732182d93b84d89a1303a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page