PythonFuzz

repository·master·Indexed 42 days ago

https://github.com/fuzzitdev/pythonfuzz

A coverage-guided fuzzer for testing Python packages to identify unhandled exceptions, logic bugs, and security vulnerabilities such as Denial-of-Service (DoS). It utilizes the @PythonFuzz decorator to define fuzz targets and supports seed corpora, memory limits, and custom mutators via command-line configuration.

Tokens
1.3K
Snippets
5
Records
6
Agent score
3%

What's inside PythonFuzz

  1. Use a Corpus to speed up fuzzing

    master

    A corpus is an optional directory used to store generated test cases.

    • Seed Corpus: You can provide an existing directory of valid test cases to act as a seed. This can significantly speed up the fuzzing process by providing a starting point of valid inputs.
    • Persistence: PythonFuzz uses the corpus directory to save generated test cases so that subsequent runs can start from the same point, building upon previously discovered paths.
  2. Run a PythonFuzz fuzzer

    master

    Once you have implemented your fuzz target in a Python file, run it directly as a script. PythonFuzz will start the fuzzing loop and output real-time statistics including coverage, corpus size, execution speed, and memory usage. If a crash is found, it will be written to a crash file.

    # Example running a specific fuzz target file
    python examples/htmlparser/fuzz.py
  3. Implement a Fuzz Target with @PythonFuzz

    master

    A fuzz target is a function decorated with @PythonFuzz that accepts a single argument buf (a buffer of random data). PythonFuzz will call this function in an infinite loop in a separate process.

    Key requirements for your fuzz target:

    • Catch expected exceptions: The function must catch and ignore exceptions that are expected when passing invalid or malformed input to the library being tested (e.g., UnicodeDecodeError).
    • Transform input: You must pass the buf (or a transformation of it) to the library/function you are testing.
    • Detect logical bugs: You can implement application-level checks. If a logical bug is detected (e.g., a round-trip encoding check fails), the function should throw an exception to signal the bug to PythonFuzz.
    • Crash reporting: PythonFuzz reports unhandled exceptions, memory limit violations, and hangs (timeouts) as crashes.
    from html.parser import HTMLParser
    from pythonfuzz.main import PythonFuzz
    
    
    @PythonFuzz
    def fuzz(buf):
        try:
            # Transform the buffer (e.g., decode to string)
            string = buf.decode("ascii")
            parser = HTMLParser()
            parser.feed(string)
        except UnicodeDecodeError:
            # Ignore expected exceptions from invalid input
            pass
    
    
    if __name__ == '__main__':
        fuzz()
  4. Define a fuzz target using the @PythonFuzz decorator

    master

    To create a fuzz target, decorate the function you wish to test with @PythonFuzz. This decorator wraps your function and prepares it to be executed by the pythonfuzz engine. When the script is run, it parses command-line arguments to configure the fuzzer's behavior (such as corpus directories, memory limits, and timeouts) and then starts the fuzzing process on the decorated function.

    from pythonfuzz import PythonFuzz
    
    @PythonFuzz
    def my_target_function(data: bytes):
        # Your code to be fuzzed goes here
        pass
    
    if __name__ == '__main__':
        PythonFuzz()
  5. Configure the fuzzer via command-line arguments

    master

    The pythonfuzz entrypoint accepts several command-line arguments to control the fuzzing session.

    Positional Arguments:

    • dirs: One or more directories or files to use as a seed corpus. The first directory provided will be used as the location to save generated test cases.

    Optional Arguments:

    • --exact-artifact-path <path>: Sets the exact path for crashes or Out-Of-Memory (OOM) artifacts.
    • --regression: A boolean flag. If set, the fuzzer runs through a specific set of files for regression testing or reproduction.
    • --rss-limit-mb <int>: Sets the memory usage limit in MB (default: 2048).
    • --max-input-size <int>: Sets the maximum input size in bytes (default: 4096).
    • --dict <path>: Path to a dictionary file to guide mutations.
    • --close-fd-mask <int>: An integer indicating which output streams to close at startup (default: 0).
    • --runs <int>: The number of individual test runs to perform. Use -1 to run indefinitely (default: -1).
    • --help-mutators: Displays help information regarding available mutators.
    • --mutator-filter <string>: Filters the types of mutators used. Prefix with ! to disable specific mutator types.
    • --timeout <int>: The timeout in seconds. If an input takes longer than this, the process is treated as a failure (default: 30).
    # Example: Run fuzzer with a seed directory, 1GB RAM limit, and 100 runs
    python main.py ./corpus --rss-limit-mb 1024 --runs 100