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;
}
ON THIS PAGE