Platform Overview
Fuzzing Terminology
Install the Fuzzbuzz CLI
Find your first C/C++ bug
Find your first Python bug
Find your first Rust bug
Find your first Go bug
Protocol Fuzzing
Seeding your fuzzer
Integrating with libFuzzer
Heartbleed in 5 Minutes
GitHub Integration
GitLab Integration
CLI Integration
fuzzbuzz.yaml reference
Fuzzer Reference
Bug Types
Self-Hosted Fuzzbuzz
Overview
Getting Started
Guides
Tutorials
Integrations
Reference
Protocol Generator Reference
This page describes how to use the Fuzzbuzz CLI as an SDK to develop, validate, and test custom generators on a developer machine, before uploading them to the Fuzzbuzz platform to be used for protocol fuzzing.
First, ensure you have the Fuzzbuzz CLI installed. If you are using beta.fuzzbuzz.io, follow these instructions to install the Fuzzbuzz CLI. If you are working with an on-prem installation of Fuzzbuzz, head to the /download
URL of your installation to download the CLI.
Creating a new Generator
To create a new generator, run:
fuzzbuzz protocol generator init <folder_name>
The folder_name
should be the name of the directory you wish to create your new generator inside. It will also be used as the name of the generator, though this can be modified later on.
After running this command, the new folder will be created, and populated with a generator.ts
, along with other files like a tsconfig.json
that enable features like autocompletion in your IDE. The generator.ts
acts as the "main" file for the generator, and must contain the root generator definition.
Generator Structure
A generator definition is a directory containing a generator.ts
at the root. The generator.ts file is written in a subset of Typescript, any IDE or editor that supports Typescript syntax highlighting will be able to provide syntax highlighting for thesen grammar files.
A generator file is structured as follows:
// Imports the relevant objects used to build grammar generators
import { GrammarGenerator, GrammarBuilder, Rule } from "bex/grammar";
// Exports the generator, with the variable name "generator". This
// variable name must remain constant, similar to the "main" function.
// The string "hello" is the name of the grammar, and can be
// changed by the user.
export const generator = new GrammarGenerator("hello");
// Setting the grammar that the generator should use to build fuzzed data.
generator.setGrammar((f: GrammarBuilder): Rule => {
// Write grammar definition here
// This grammar contains a single rule that produces "hello, world!"
return f.rule("hello, world!")
}
In addition to importing Fuzzbuzz-created libraries, Typescript files in the generator definition can also import other .ts
files contained in the directory. Refer to the examples section for more details.
Testing and Validating Generators
Validate your generator by running the following command:
fuzzbuzz protocol generator validate <folder_name>
The folder_name
may also be omitted if you run the command from within the root of the generator's directory. Any syntax or type errors, as well as runtime errors, will be output to the user. This command can be added to Continuous Integration flows or other forms of automated testing to ensure that grammars are valid before they are merged into source control.
Generate examples of the types of inputs your grammar can produce by running:
fuzzbuzz protocol generator example <folder_name>
Similarly to the validate
command, the folder_name
can be omitted if the command is run from within a generator directory.
By default, this will produce one example. More can be produced by adding the --n <number>
flag:
fuzzbuzz protocol generator example --n 10 # will produce 10 examples
When building grammars for lower-level data formats, it can be useful to inspect the exact bytes that are generated. This can be achieved by passing the --b64
flag which will output all examples as base64-encoded strings, separated by newlines (\n
):
fuzzbuzz protocol generator example --n 5 --b64 # produce 5 base64-encoded examples
Grammar-based Generators
The simplest way to build a custom generator is using a grammar. The grammar builder enables construction of complex data format definitions through the use of custom rules.
A grammar is defined by using a GrammarBuilder
. The simplest possible grammar rule is an enumerated rule. This rule will return the exact value A
, B
, or C
:
(f: GrammarBuilder): Rule => {
return f.rule("A").or("B").or("C");
}
Composing rules
Rules can be defined individually and combined, allowing for further flexibility and code reuse. Here, the mammal
rule is used in the animal
rule. The generator will produce either Fish
, Dog
, Cat
, or Mouse
.
(f: GrammarBuilder): Rule => {
const mammal = f.rule("Cat").or("Dog").or("Mouse");
const animal = f.rule("Fish").or(mammal);
return animal
}
Working with bytes
Rules can accept raw bytes and byte arrays, in addition to strings. This rule will print the 0x0a
(new line) byte, followed by the word "hello":
(f: GrammarBuilder): Rule => {
return f.rule(0x0a, "hello");
}
The Javascript Uint8Array
type can also be used:
(f: GrammarBuilder): Rule => {
return f.rule(new Uint8Array([1, 2, 3, 4]));
}
Using type generators
In addition to custom rule definitions, Fuzzbuzz also provides generators for specific data types. These generators can produce random values and known malicious inputs, as well as mutate and splice examples provided by the user.
These generators can be combined with other rules:
(f: GrammarBuilder): Rule => {
return f.rule(f.ASCII("my_ascii_string", 200)).or(f.bytes("my_bytes", 100))
}
The currently supported random value generators are:
f.ASCII(name: string, length: number)
Generate an ASCII string with a maximum length.
f.UTF8(name: string, length: number)
Generate a UTF8 string with a maximum length.
f.bytes(name: string, length: number)
Generate a string of bytes with a maximum length.
f.integer(name: string)
Generate an integer.
f.date(name: string, format: string)
Generate a random date or time. The format supports strftime-style format strings. (https://strftime.org/)
f.sequenceNumber(name: string, max: number)
Produce a monotonically increasing integer that wraps back to zero when it reaches max
.
Examples
Reusing Grammar Rules
This example will describe how to split grammar rules out into other functions and modules.
Say in custom_rule.ts
we have a grammar rule that we'd like to use in a number of different places. The specific implementation isn't important:
// custom_rule.ts
import { GrammarBuilder, Rule } from "bex/grammar";
export function MyCustomRule(f: GrammarBuilder): Rule {
// Build custom rule here
}
In generator.ts
, we can import this rule function, and add it in multiple places:
// generator.ts
import { GrammarGenerator, GrammarBuilder, Rule } from "bex/grammar";
import { MyCustomRule } from "./custom_rule";
export const generator = new GrammarGenerator("my_generator");
generator.setGrammar((f: GrammarBuilder): Rule => {
const subrule = MyCustomRule(f);
const another_rule = f.rule("this").or(MyCustomRule(f));
return another_rule;
}