PHP Fuzzer

repository·master·Indexed 19 days ago

https://github.com/nikic/php-fuzzer

A coverage-guided fuzzer for PHP designed to find bugs in libraries and parsers using edge coverage instrumentation. It supports defining fuzzing targets via PhpFuzzer\Config, utilizing mutation dictionaries, and minimizing crashing inputs. The tool automatically detects uncaught Error exceptions, notices, warnings, and timeouts as bugs.

Tokens
2.1K
Snippets
11
Records
14
Agent score
66%

What's inside php-fuzzer

  1. Understand detected bug types

    master

    PHP Fuzzer automatically detects the following as bugs:

    1. Error exceptions: Uncaught Error exceptions (e.g., calling a method on null).
    2. Notices and Warnings: Thrown notices and warnings are converted to Error exceptions via a registered error handler.
    3. Timeouts: If the target exceeds the specified timeout (default: 3s), it is treated as an infinite loop and triggers an Error via pcntl_alarm().
  2. Minimize and inspect crashes

    master

    When a crash is found, it is saved as crash-HASH.txt. Because these inputs can be complex, you should minimize them to find the simplest reproducing case.

    • Minimize a crash: Produces a sequence of smaller minimized-HASH.txt files.
    • Run a single input: Use this to quickly check the exception trace produced by a specific crashing input.
    # Minimize the crashing input
    php-fuzzer minimize-crash target.php crash-HASH.txt
    
    # Run a specific minimized input to see the trace
    php-fuzzer run-single target.php minimized-HASH.txt
  3. Run the fuzzer

    master

    The fuzzer can be run against a corpus of initial inputs (e.g., from existing unit tests). If no corpus is provided, a temporary directory is created.

    • Run without initial corpus: Creates a temporary corpus.
    • Run with initial corpus: Uses a directory containing one input per file.
    • Resuming: If interrupted, you can resume by specifying the same corpus directory used previously.
    # Run without initial corpus
    php-fuzzer fuzz target.php
    
    # Run with initial corpus (one input per file)
    php-fuzzer fuzz target.php corpus/
  4. Install PHP Fuzzer

    master

    You can install PHP Fuzzer using two methods:

    1. Phar (Recommended): Download the phar package from the releases page. Using the phar is recommended to avoid dependency conflicts with libraries that use PHP-Parser.
    2. Composer: Install it globally via Composer.
    # Using Composer
    composer global require nikic/php-fuzzer
  5. Define a fuzzing target

    master

    To use the fuzzer, you must create a target script that defines the function to be tested. The target must accept a single input string and execute it through the library being tested.

    Key requirements and options:

    • Target Function: Use $config->setTarget(callable $callback) where the callback receives a string $input.
    • Error Handling: The target can throw normal Exception objects (which are ignored), but uncaught Error exceptions are treated as bugs.
    • Max Length: Use $config->setMaxLen(int $length) to limit input size and improve performance.
    • Dictionary: Use $config->addDictionary(string $path) to provide useful fragments (like language keywords) to guide the fuzzer.
    • Correctness Checking: You can manually check for logic errors by throwing an Error inside the target if the output of two implementations differs.
    <?php // target.php
    
    /** @var PhpFuzzer\Config $config */
    
    require 'path/to/library/vendor/autoload.php';
    
    $parser = new Microsoft\PhpParser\Parser();
    
    // Define the target
    $config->setTarget(function(string $input) use($parser) {
        $parser->parseSourceFile($input);
    });
    
    // Optional: Limit input length
    $config->setMaxLen(1024);
    
    // Optional: Add a dictionary for keywords
    $config->addDictionary('example/php.dict');
  6. Reference: Fuzzer status output

    master

    While running, the fuzzer outputs a single line of status updates. The fields are:

    1. NEW or REDUCED: Action taken (new input added or existing input replaced with shorter version).
    2. run: N: Total iterations performed.
    3. (N/s): Current execution speed (runs/sec).
    4. ft: N: Total unique features discovered.
    5. (N/s): Average feature discovery rate.
    6. corp: N: Number of inputs in the corpus.
    7. (%s): Total size of the corpus.
    8. len: %d/%d: Current input length / Max allowed length.
    9. t: Total elapsed time (seconds).
    10. mem: Current PHP process memory usage.
  7. Configure the fuzzing target and constraints with Config

    master

    The PhpFuzzer\Config class is used to define the fuzzing target (the code you want to test) and set constraints like allowed exceptions, maximum input length, and mutation dictionaries.

    Important: You must call setTarget() with a ext{Closure} representing the code to be fuzzed. All other configuration options are optional.

    use PhpFuzzer\Config;
    
    $config = new Config();
    
    // Required: Define the code to fuzz
    $config->setTarget(function (string $input) {
        // Your target logic here
        $result = some_function_to_test($input);
    });
    
    // Optional: Set constraints
    $config->setMaxLen(1024);
    $config->setAllowedExceptions([\InvalidArgumentException::class]);
    $config->addDictionary('/path/to/dictionary.txt');
  8. Handle fuzzer configuration errors with FuzzerException

    master
    The PhpFuzzer\FuzzerException is thrown when there is an error in the provided fuzzer parameters or configuration. If you are integrating the fuzzer programmatically, you should catch this exception to handle invalid setup or configuration issues.
  9. Use the php-fuzzer CLI

    master

    The php-fuzzer binary is the primary entrypoint for running the fuzzer. It initializes the PhpFuzzer\Fuzzer engine and processes command-line arguments to start fuzzing sessions.

    To use it, ensure you have installed the dependencies via Composer so that autoload.php is available in the expected vendor directory.

    # Run the fuzzer (arguments are handled by the Fuzzer class)
    ./bin/php-fuzzer [options]
  10. Set the fuzzing target

    master

    Use setTarget(\Closure $target) to provide the function or logic that the fuzzer will execute repeatedly with mutated inputs. The closure should accept the fuzzed input (typically a string) as its argument.

    $config->setTarget(function (string $input) {
        // Target code
    });
  11. Set maximum input length

    master

    Use setMaxLen(int $maxLen) to limit the size of the mutated inputs generated by the fuzzer. This is useful for preventing the fuzzer from generating extremely large inputs that might cause memory exhaustion or slow down the fuzzing process.

    $config->setMaxLen(256);