Blocks
Request
The Request class has push and pop methods for creating it. Whenever a new Block is opened/started, it is pushed onto the “block stack”. Note that this is different than the “stack”. When a Block is closed, it is popped.
When the Request is assembled in the fuzz definition, its stack should be empty. To accomplish this, all blocks should be closed.
- class boofuzz.Request(name=None, children: tuple[BasePrimitive, ...] = None, timeout_check: bool = True, fragmentation: Callable = None, fragmentation_length: int = 516, receive_data_after_transmit: bool = True, answer_must_contain: list[str | bytes] | None = None, answer_must_not_contain: list[str | bytes] | None = None)[source]
Bases:
FuzzableBlock,NodeTop level container. Can hold any block structure or primitive.
This can essentially be thought of as a super-block, root-block, daddy-block or whatever other alias you prefer.
Here are the parameters of the Request class:
- Parameters:
name (str, optional) – Name of this request
children (boofuzz.Fuzzable, optional) – Children of this request, defaults to None
timeout_check (bool, optional) – If True, check for timeout, defaults to True
fragmentation (Callable, optional) – Fragmentation function, defaults to None
fragmentation_length (int, optional) – Fragmentation length, defaults to 516
receive_data_after_transmit (bool, optional) – default to True, force the request to not wait answer if False
answer_must_contain (list[str|bytes], optional) – List of strings or bytes that the answer must contain, defaults to None
answer_must_not_contain (list[str|bytes], optional) – List of strings or bytes that the answer must not contain, defaults to None
And it’s attributes:
- Parameters:
parent_session (boofuzz.Session) – Parent session of this Request, so children can now access parameters of session.
smooth_rtt (float) – Smoothed Round Trip Time
rtt_variations (float) – Round Trip Time Variations
- analyze_answer(data: bytes, session: Session) None[source]
If answer_must_contains or answer_must_not_contains is filled, when we got an anwer, we analyze it and log it
- Returns:
None
- calculate_rto(rtt: float, alpha: float = 0.125, beta: float = 0.25, k: int = 4) float[source]
Public method to calculate a new retransmission timeout using TCP formula :
\[ \begin{align}\begin{aligned}srtt = (1 - g).srtt + g.rtt\\rttvar = (1 - h).rttvar + h.|rtt - srtt|\\RTO = srtt + 4.rttvar\end{aligned}\end{align} \]See RFC 6298 for more information.
- Parameters:
rtt (float) – The new round trip time
alpha (float) – The alpha value of the formula. This gain factor determines how quickly the smoothed round-trip time (srtt) responds to changes in the measured round-trip time. A larger alpha makes srtt more sensitive to recent changes, making it adapt faster to network conditions. A smaller alpha makes srtt more stable but slower to react to changes. Optional, defaults to 0.125
beta (float) – The beta value of the formula. This gain factor affects how the round-trip time variation (rttvar) responds to changes in the deviation of the measured round-trip time from srtt. A larger beta makes rttvar more sensitive to fluctuations, capturing changes in variability more quickly. A smaller beta makes rttvar more stable but slower to adapt to new conditions. Optional, defaults to 0.25
k (int) – The k value of the formula. A larger value provides more buffer. Changes not recommended.
- Returns:
The new retransmission timeout
- property fuzzable
If False, this element should not be mutated in normal fuzzing.
- get_mutations(default_value=None, skip_elements=None)[source]
Iterate mutations. Used by boofuzz framework.
- Yields:
list of Mutation – Mutations
- property name
Element name, should be unique for each instance.
- Return type:
str
- push(item)[source]
Push an item into the block structure. If no block is open, the item goes onto the request stack. otherwise, the item goes onto the last open blocks stack.
What this method does: 1. Sets context_path for each pushed FuzzableWrapper. 2. Sets request for each FuzzableWrapper 3. Checks for duplicate qualified_name items 4. Adds item to self.names map (based on qualified_name) 5. Adds the item to self.stack, or to the stack of the currently opened block.
Also: Manages block_stack, mostly an implementation detail to help static protocol definition
@type item: BasePrimitive | Block | Request | Size | Repeat @param item: Some primitive/block/request/etc.
- render(mutation_context=None)[source]
Render after applying mutation, if applicable. :type mutation_context: MutationContext
- resolve_name(context_path, name)[source]
Names are resolved thus: #. If the name starts with a dot, it is treated as a relative path name in the style of PEP 328.
“.” refers to the current directory, so to speak.
“..” refers to the next directory up.
“…” refers to another directory up, and so forth.
If the name does _not_ start with a dot, it is treated as an absolute name.
- Backwards compatibility: If the absolute name fails to resolve, the engine searches for any block or
primitive with that name. If more or less than exactly one match is found, an error results.
- Parameters:
context_path – The “current working directory” for resolving the name. E.g. “block_1.block_2”.
name – The name being resolved. May be absolute or relative.
Returns:
Block
- class boofuzz.Block(name=None, default_value=None, request=None, children=None, group=None, encoder=None, dep=None, dep_value=None, dep_values=None, dep_compare='==', *args, **kwargs)[source]
Bases:
FuzzableBlockThe basic building block. Can contain primitives, sizers, checksums or other blocks.
- Parameters:
name (str, optional) – Name, for referencing later. Names should always be provided, but if not, a default name will be given, defaults to None
default_value (Any, optional) – Value used when the element is not being fuzzed - should typically represent a valid value, defaults to None
request (boofuzz.Request, optional) – Request this block belongs to, defaults to None
children (boofuzz.Fuzzable, optional) – Children of this block, defaults to None
group (str, optional) – Name of group to associate this block with, defaults to None
encoder (callable, optional) – Optional pointer to a function to pass rendered data to prior to return, defaults to None
dep (str, optional) – Optional primitive whose specific value this block is dependant on, defaults to None
dep_value (bytes, optional) – Value that field “dep” must contain for block to be rendered, defaults to None
dep_values (list, optional) – Values that field “dep” may contain for block to be rendered, defaults to None
dep_compare (str, optional) – Comparison method to apply to dependency (==, !=, >, >=, <, <=), defaults to None
- encode(value, mutation_context)[source]
Takes a value and encodes/renders/serializes it to a bytes (byte string).
Optional if mutations() yields bytes.
Example: Yield strings with mutations() and encode them to UTF-8 using encode().
Default behavior: Return value.
- Parameters:
value – Value to encode. Type should match the type yielded by mutations()
mutation_context (MutationContext) – Context for current mutation, if any.
- Returns:
Encoded/serialized value.
- Return type:
bytes
- mutations(default_value, skip_elements=None)[source]
Generator to yield mutation values for this element.
Values are either plain values or callable functions that take a “default value” and mutate it. Functions are used when the default or “normal” value influences the fuzzed value. Functions are used because the “normal” value is sometimes dynamic and not known at the time of generation.
Each mutation should be a pre-rendered value. That is, it must be suitable to pass to encode().
Default: Empty iterator.
- Parameters:
default_value
- num_mutations(default_value=None)[source]
Return the total number of mutations for this element (not counting “fuzz_values”).
Default implementation exhausts the mutations() generator, which is inefficient. Override if you can provide a value more efficiently, or if exhausting the mutations() generator has side effects.
- Parameters:
default_value – Use if number of mutations depends on the default value. Provided by FuzzableWrapper. Note: It is generally good behavior to have a consistent number of mutations for a given default value length.
- Returns:
Number of mutated forms this primitive can take
- Return type:
int
Checksum
Sulley’s Checksum class creates a block that calculates the checksum of another block.
Algorithms
Checksum contains only the Sulley block logic for a checksum, not specific algorithm implementations. Algorithms are implemented with a library or a free function.
Recursion
To enable a checksum to be calculated over its parent block, it is necessary to account for recursion. This is done with a recursion flag. When Checksum renders itself for the sake of calculations, it will set a recursion flag on itself. Then, when the parent block again renders the Checksum, Checksum will check its own recursion flag and return its default value.
Note: To avoid recursion problems with Size, it is important that Checksum’s length method not call render on itself.
UDP
UDP is special in that it is computed over a pseudo-header, including selected fields from IPv4 and the entire UDP header and payload. The IPv4 fields are:
IPv4 Source Address
IPv4 Destination Address
Protocol (should always be UDP)
Length of UDP header+payload
Note that these fields do not themselves need to be individually fuzzed, since fuzzing any of them would result in a bad checksum – and a bad checksum can be checked by fuzzing the checksum field itself.
Designs considered:
Passing a reference to the IPv4 Sulley Block and navigating to its children.
Passing source and destination addresses directly to the Checksum constructor.
Passing references to the source and destination Sulley Blocks into the Checksum constructor.
Option 1 was rejected as being too involved. It would need to know the structure of the IPv4 Sulley Block, which would result in complexity and possibly duplicated information.
Option 2 was rejected as inferior to 1 and 3. With option 2, when the IPv4 source or destination address is being fuzzed, the UDP checksum will automatically start failing. This could draw attention away from the IPv4 src/dst fields for the sake of fuzzing.
With option 3, when the IPv4 src/dst fields are being fuzzed, the UDP checksum will still pass. Furthermore, taking a reference to two Sulley Blocks is relatively easy.
Source Code
- class boofuzz.Checksum(name=None, block_name=None, request=None, algorithm='crc32', length=0, endian='<', ipv4_src_block_name=None, ipv4_dst_block_name=None, *args, **kwargs)[source]
Bases:
BasePrimitiveChecksum bound to the block with the specified name.
The algorithm may be chosen by name with the algorithm parameter, or a custom function may be specified with the algorithm parameter.
The length field is only necessary for custom algorithms. When using your own custom checksum function, the return value should be the calculated checksum of the data.
Function signature: <function_name>(data_bytes). Returns a number represented as a bytes type.
Recursive checksums are supported; the checksum field itself will render as all zeros for the sake of checksum or length calculations.
- Parameters:
name (str, optional) – Name, for referencing later. Names should always be provided, but if not, a default name will be given, defaults to None
block_name (str) – Name of target block for checksum calculations.
request (boofuzz.Request, optional) – Request this block belongs to
algorithm (str, function def name, optional) – Checksum algorithm to use from this list, default is crc32 (crc32, crc32c, adler32, md5, sha1, ipv4, udp). See above for custom checksum function example.
length (int, optional) – Length of checksum, auto-calculated by default. Must be specified manually when using custom algorithm, defaults to 0
endian (chr, optional) – Endianness of the bit field (LITTLE_ENDIAN: <, BIG_ENDIAN: >), defaults to LITTLE_ENDIAN
ipv4_src_block_name (str, optional) – Required for ‘udp’ algorithm. Name of block yielding IPv4 source address, defaults to None
ipv4_dst_block_name (str, optional) – Required for ‘udp’ algorithm. Name of block yielding IPv4 destination address, defaults to None
fuzzable (bool, optional) – Enable/disable fuzzing of this block, defaults to true
- checksum_lengths = {'adler32': 4, 'crc32': 4, 'crc32c': 4, 'ipv4': 2, 'md5': 16, 'sha1': 20, 'udp': 2}
- encode(value, mutation_context)[source]
Takes a value and encodes/renders/serializes it to a bytes (byte string).
Optional if mutations() yields bytes.
Example: Yield strings with mutations() and encode them to UTF-8 using encode().
Default behavior: Return value.
- Parameters:
value – Value to encode. Type should match the type yielded by mutations()
mutation_context (MutationContext) – Context for current mutation, if any.
- Returns:
Encoded/serialized value.
- Return type:
bytes
Repeat
- class boofuzz.Repeat(name=None, block_name=None, request=None, min_reps=0, max_reps=25, step=1, variable=None, default_value=None, *args, **kwargs)[source]
Bases:
FuzzableRepeat the rendered contents of the specified block cycling from min_reps to max_reps counting by step.
By default renders to nothing. This block modifier is useful for fuzzing overflows in table entries. This block modifier MUST come after the block it is being applied to.
- Parameters:
name (str, optional) – Name, for referencing later. Names should always be provided, but if not, a default name will be given, defaults to None
block_name (str, optional) – Name of block to repeat
request (boofuzz.Request, optional) – Request this block belongs to, defaults to None
min_reps (int, optional) – Minimum number of block repetitions, defaults to 0
max_reps (int, optional) – Maximum number of block repetitions, defaults to None
step (int, optional) – Step count between min and max reps, defaults to 1
variable (Boofuzz Integer Primitive, optional) – Repetitions will be derived from this variable, disables fuzzing, defaults to None
default_value (Raw) – Value used when the element is not being fuzzed - should typically represent a valid value, defaults to None
fuzzable (bool, optional) – Enable/disable fuzzing of this block, defaults to true
- encode(value, mutation_context)[source]
Takes a value and encodes/renders/serializes it to a bytes (byte string).
Optional if mutations() yields bytes.
Example: Yield strings with mutations() and encode them to UTF-8 using encode().
Default behavior: Return value.
- Parameters:
value – Value to encode. Type should match the type yielded by mutations()
mutation_context (MutationContext) – Context for current mutation, if any.
- Returns:
Encoded/serialized value.
- Return type:
bytes
- mutations(default_value)[source]
Generator to yield mutation values for this element.
Values are either plain values or callable functions that take a “default value” and mutate it. Functions are used when the default or “normal” value influences the fuzzed value. Functions are used because the “normal” value is sometimes dynamic and not known at the time of generation.
Each mutation should be a pre-rendered value. That is, it must be suitable to pass to encode().
Default: Empty iterator.
- Parameters:
default_value
Size
The Size class creates a block that calculates the size of another block.
Calculation
To calculate the size of its target block, Size simply calls len() on the target (all Sulley Primitives must support __len__()).
Design Considerations
Size was originally calculated by rendering the target block, or using callbacks to wait for it to get rendered. This resulted in dependency issues if a block contained both Size and Checksum primitives, or in blocks that referenced each other. Checksum naturally depends on Size’s value, but if Size depends on Checksum’s value, we have a recursion problem.
The current design is motivated by the fact that, in reality, Size does not depend on Checksum’s value. Depending on the length method rather than rendering more closely matches reality.
- class boofuzz.Size(name=None, block_name=None, request=None, offset=0, length=4, endian='<', output_format='binary', inclusive=False, signed=False, math=None, *args, **kwargs)[source]
Bases:
FuzzableCreate a sizer block bound to the block with the specified name.
Size blocks that size their own parent or grandparent are allowed.
- Parameters:
name (str, optional) – Name, for referencing later. Names should always be provided, but if not, a default name will be given, defaults to None
block_name (str, optional) – Name of block to apply sizer to.
request (boofuzz.Request, optional) – Request this block belongs to.
offset (int, optional) – Offset for calculated size value, defaults to 0
length (int, optional) – Length of sizer, defaults to 4
endian (chr, optional) – Endianness of the bit field (LITTLE_ENDIAN: <, BIG_ENDIAN: >), defaults to LITTLE_ENDIAN
output_format (str, optional) – Output format, “binary” or “ascii”, defaults to binary
inclusive (bool, optional) – Should the sizer count its own length? Defaults to False
signed (bool, optional) – Make size signed vs. unsigned (applicable only with format=”ascii”), defaults to False
math (def, optional) – Apply the mathematical op defined in this function to the size, defaults to None
fuzzable (bool, optional) – Enable/disable fuzzing of this block, defaults to true
- encode(value, mutation_context)[source]
Takes a value and encodes/renders/serializes it to a bytes (byte string).
Optional if mutations() yields bytes.
Example: Yield strings with mutations() and encode them to UTF-8 using encode().
Default behavior: Return value.
- Parameters:
value – Value to encode. Type should match the type yielded by mutations()
mutation_context (MutationContext) – Context for current mutation, if any.
- Returns:
Encoded/serialized value.
- Return type:
bytes
- mutations(default_value)[source]
Generator to yield mutation values for this element.
Values are either plain values or callable functions that take a “default value” and mutate it. Functions are used when the default or “normal” value influences the fuzzed value. Functions are used because the “normal” value is sometimes dynamic and not known at the time of generation.
Each mutation should be a pre-rendered value. That is, it must be suitable to pass to encode().
Default: Empty iterator.
- Parameters:
default_value
Aligned
- class boofuzz.Aligned(name=None, modulus=1, request=None, pattern=b'\x00', *args, **kwargs)[source]
Bases:
FuzzableBlockFuzzableBlock that aligns its contents to a certain number of bytes
- Parameters:
name (str, optional) – Name, for referencing later. Names should always be provided, but if not, a default name will be given, defaults to None
modulus (int, optional) – Pad length of child content to this many bytes, defaults to 1
request (boofuzz.Request, optional) – Request this block belongs to
pattern (bytes, optional) – Pad using these byte(s)
fuzzable (bool, optional) – Enable/disable fuzzing of this block, defaults to true
- encode(value, mutation_context)[source]
Takes a value and encodes/renders/serializes it to a bytes (byte string).
Optional if mutations() yields bytes.
Example: Yield strings with mutations() and encode them to UTF-8 using encode().
Default behavior: Return value.
- Parameters:
value – Value to encode. Type should match the type yielded by mutations()
mutation_context (MutationContext) – Context for current mutation, if any.
- Returns:
Encoded/serialized value.
- Return type:
bytes