FOSSA Logo

Fuzzing

An automated software testing technique that inputs invalid, unexpected, or random data to discover security vulnerabilities, bugs, and crashes in applications.

What is Fuzzing?

Fuzzing (or fuzz testing) is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a program. The goal is to make the application crash, identify memory leaks, discover security vulnerabilities, or reveal other defects that might not be detected through conventional testing methods.

Fuzzing is particularly effective at finding issues like buffer overflows, format string vulnerabilities, input validation flaws, and various memory corruption bugs. By generating and testing a vast number of inputs automatically, fuzzing can uncover edge cases and vulnerabilities that would be difficult to discover manually.

How Fuzzing Works

The fuzzing process typically involves:

  1. Identifying Target Inputs: Determining the input interfaces to test, such as file formats, network protocols, API endpoints, or command-line arguments
  2. Generating Test Cases: Creating a large number of malformed, random, or manipulated inputs
  3. Delivering Inputs: Feeding these inputs to the target software
  4. Monitoring Execution: Watching for crashes, hangs, memory leaks, or other abnormal behaviors
  5. Analyzing Results: Investigating detected issues and determining their root causes
  6. Minimizing Inputs: Reducing the test case to the smallest input that still triggers the issue

Types of Fuzzing

Based on Knowledge of Target System

Black-box Fuzzing

Testing without knowledge of the internal structure of the application. The fuzzer generates inputs without understanding the application's internal logic.

White-box Fuzzing

Leveraging knowledge of the application's internal structure, source code, and logic to generate more targeted inputs that can reach deeper parts of the application.

Grey-box Fuzzing

A hybrid approach that uses some knowledge of the internal structure (often through instrumentation) without requiring full access to source code.

Based on Input Generation Strategy

Mutation-based Fuzzing

Modifies existing valid inputs (seeds) to create new test cases by applying various mutations such as bit flips, byte swaps, or value replacements.

Original input: "GET /index.html HTTP/1.1"
Mutated input: "GET /index.html\0 HTTP/1.1"

Generation-based Fuzzing

Creates inputs from scratch based on a specification or model of the expected input format.

Protocol fuzzer generating HTTP requests with various headers, methods, and body content

Evolutionary Fuzzing

Uses genetic algorithms and coverage feedback to evolve test cases that explore new paths through the program.

Start with seed → Mutate → Test coverage → Select best performers → Repeat

Fuzzing Tools and Frameworks

General-Purpose Fuzzers

  • American Fuzzy Lop (AFL): Popular coverage-guided fuzzer
  • libFuzzer: In-process, coverage-guided fuzzing engine
  • Honggfuzz: Security-oriented fuzzer with multi-threading support
  • Peach Fuzzer: Commercial framework for structured protocol fuzzing

Language-Specific Fuzzers

  • go-fuzz: For Go applications
  • jsfuzz: For JavaScript applications
  • Jazzer: For Java applications
  • Atheris: For Python applications
  • cargo-fuzz: For Rust applications

Specialized Fuzzers

  • Radamsa: General-purpose fuzzer for binary and text formats
  • Domato: For DOM fuzzing in web browsers
  • Sulley: For network protocol fuzzing
  • FuzzDB: Database of attack patterns and primitives

Fuzzing in the Software Supply Chain

Component Security Assessment

Fuzzing can be applied to third-party libraries and dependencies to discover vulnerabilities before incorporating them into your software.

Continuous Fuzzing

Integrating fuzzing into CI/CD pipelines to continually test for vulnerabilities as code evolves.

Coordinated Vulnerability Disclosure

Finding vulnerabilities through fuzzing often leads to responsible disclosure processes to protect users across the supply chain.

OSS-Fuzz

Google's continuous fuzzing service for open source software, which has found thousands of vulnerabilities in critical open source projects.

Effective Fuzzing Strategies

Corpus Selection

Starting with a diverse set of valid inputs (corpus) that achieve good code coverage.

Instrumentation

Adding runtime instrumentation to gather coverage information and detect memory safety issues.

Sanitizers

Using tools like AddressSanitizer (ASan), MemorySanitizer (MSan), and UndefinedBehaviorSanitizer (UBSan) to detect various runtime errors.

Resource Limits

Setting appropriate timeouts and memory limits to prevent resource exhaustion.

Deterministic Reproduction

Ensuring that bugs can be reliably reproduced with the same input.

Implementing Fuzzing in Development

When to Implement Fuzzing

  • During development of new features
  • Before releasing software
  • After fixing security vulnerabilities
  • As part of ongoing security testing

Integration with Development Workflow

  • Local Development: Developers run fuzzers on their changes
  • Continuous Integration: Automated fuzzing runs on each commit
  • Scheduled Fuzzing: Longer fuzzing sessions run nightly or weekly
  • Regression Testing: Ensuring fixed bugs don't reappear

Challenges in Fuzzing

  • Time Constraints: Effective fuzzing often requires significant compute time
  • False Positives: Not all crashes indicate exploitable vulnerabilities
  • Coverage Limitations: Difficulty reaching deeply nested code paths
  • State Explosion: The potential input space is often enormous
  • Environment Dependencies: Some bugs only manifest in specific environments

Best Practices for Fuzzing

  1. Start Early: Incorporate fuzzing early in the development lifecycle
  2. Use Multiple Techniques: Combine different fuzzing approaches for better coverage
  3. Preserve Test Cases: Save inputs that trigger bugs or reach new code paths
  4. Automate Bug Reproduction: Create automated tests from fuzzer-discovered bugs
  5. Analyze Root Causes: Don't just fix symptoms; understand underlying issues
  6. Fuzz Security-Critical Components: Prioritize code that handles untrusted input
  7. Set Clear Goals: Define success criteria for your fuzzing efforts
  8. Monitor Fuzzing Metrics: Track code coverage, execution speed, and bug discovery rate