Fuzzing

With the addition of the pfp.fuzz module, pfp now supports fuzzing out-of-the box! (w00t!).

pfp.fuzz.mutate() function

pfp contains a pfp.fuzz.mutate function that will mutate a provided field. The provided field will most likely just be the resulting dom from calling pfp.parse.

The pfp.fuzz.mutate function accepts several arguments:

  • field - The field to fuzz. This does not have to be a pfp.fields.Dom object, although in the normal use case it will be.
  • strat_name_or_cls - The name (or direct class) of the StratGroup to use
  • num - The number of iterations to perform. Defaults to 100
  • at_once - The number of fields to fuzz at once. Defaults to 1
  • yield_changed - If true, the mutate generator will yield a tuple of (mutated_dom,changed_fields), where changed_fields is a set (not a list) of the fields that were changed. Also note that the yielded set of changed fields can be modified and is no longer needed by the mutate function. Defaults to False

Strategies

My (d0c_s4vage’s) most successful fuzzing approaches have been ones that allowed me to pre-define various fuzzing strategies. This allows one to reuse, tweak existing, or create new strategies specific to each target or attack surface.

StratGroup

pfp strategy groups are containers for sets of field-specific fuzzing strategies. StratGroups must define a unique name. Strategy groups may also define a custom filter_fields method.

E.g. To define a strategy that only fuzzes integers, one could do something like this:

class IntegersOnly(pfp.fuzz.StratGroup):
    name = "ints_only"

    class IntStrat(pfp.fuzz.FieldStrat):
        klass = pfp.fields.IntBase
        choices = [0, 1, 2, 3]

    def filter_fields(self, fields):
        return filter(lambda x: isinstance(x, pfp.fields.IntBase), fields)

Then, after parsing some data using a template, the returned Dom instance could be mutated like so:

dom = pfp.parse(....)
for mutation in pfp.fuzz.mutate(dom, "ints_only", num=100, at_once=3):
    mutated = mutation._pfp__build()
    # do something with it

Note that the string ints_only was used as the strat_name_or_cls field. We could have also simply passed in the IntegersOnly class:

dom = pfp.parse(....)
for mutation in pfp.fuzz.mutate(dom, IntegersOnly, num=100, at_once=3):
    mutated = mutation._pfp__build()
    # do something with it

FieldStrat

FieldStrats define a specific fuzzing strategy for a specific field (or set of fields).

All FieldStrats must have either a choices field defined or a prob field defined.

Alternately, the next_val function may also be overriden if something more specific is needed.

Fuzzing Reference Documentation

This module contains the base classes used when defining mutation strategies for pfp

class pfp.fuzz.Changer(orig_data)[source]
build()[source]

Apply all changesets to the original data

change(**kwds)[source]

Intended to be used with a with block. Takes care of pushing and popping the changes, yields the modified data.

pop_changes()[source]

Return a version of the original data after popping the latest

push_changes(field_set)[source]

Push a new changeset onto the changeset stack for the provided set of fields.

pfp.fuzz.changeset_mutate(field, strat_name_or_cls, num=100, at_once=1, yield_changed=False, fields_to_modify=None, base_data=None)[source]

Mutate the provided field (probably a Dom or struct instance) using the strategy specified with strat_name_or_class, yielding num mutations that affect up to at_once fields at once.

This function will yield back the field after each mutation, optionally also yielding a set of fields that were mutated in that iteration (if yield_changed is True). It should also be noted that the yielded set of changed fields can be modified and is no longer needed by the mutate() function.

Parameters:
  • field (pfp.fields.Field) – The field to mutate (can be anything, not just Dom/Structs)
  • strat_name_or_class – Can be the name of a strategy, or the actual strategy class (not an instance)
  • num (int) – The number of mutations to yield
  • at_once (int) – The number of fields to mutate at once
  • yield_changed (bool) – Yield a list of fields changed along with the mutated dom
  • use_changesets (bool) – If a performance optimization should be used that builds the full output once, and then replaced only the changed fields, including watchers, etc. NOTE this does not yet work fully with packed structures (https://pfp.readthedocs.io/en/latest/metadata.html#packer-metadata)
Returns:

generator

pfp.fuzz.mutate(field, strat_name_or_cls, num=100, at_once=1, yield_changed=False)[source]

Mutate the provided field (probably a Dom or struct instance) using the strategy specified with strat_name_or_class, yielding num mutations that affect up to at_once fields at once. This function will yield back the field after each mutation, optionally also yielding a set of fields that were mutated in that iteration (if yield_changed is True). It should also be noted that the yielded set of changed fields can be modified and is no longer needed by the mutate() function. :param pfp.fields.Field field: The field to mutate (can be anything, not just Dom/Structs) :param strat_name_or_class: Can be the name of a strategy, or the actual strategy class (not an instance) :param int num: The number of mutations to yield :param int at_once: The number of fields to mutate at once :param bool yield_changed: Yield a list of fields changed along with the mutated dom :returns: generator

This module contains the base classes used when defining fuzzing strategies for pfp

class pfp.fuzz.strats.FieldStrat[source]

A FieldStrat is used to define a fuzzing strategy for a specific field (or list of fields). A list of choices can be defined, or a set or probabilities that will yield

choices = None

An enumerable of new value choices to choose from when mutating.

This can also be a function/callable that returns an enumerable of choices. If it is a callable, the currently-being-fuzzed field will be passed in as a parameter.

klass = None

The class this strategy should be applied to. Can be a pfp.fields.field class (or subclass) or a string of the class name.

Note that strings for the class name will only apply to direct instances of that class and not instances of subclasses.

Can also be a list of classes or class names.

mutate(field)[source]

Mutate the given field, modifying it directly. This is not intended to preserve the value of the field.

Field:The pfp.fields.Field instance that will receive the new value
next_val(field)[source]

Return a new value to mutate a field with. Do not modify the field directly in this function. Override the mutate() function if that is needed (the field is only passed into this function as a reference).

Field:The pfp.fields.Field instance that will receive the new value. Passed in for reference only.
Returns:The next value for the field
prob = None

An enumerable of probabilities used to choose from when mutating E.g.:

[
    (0.50, 0xffff),             # 50% of the time it should be the value 0xffff
    (0.25, xrange(0, 0x100)),   # 25% of the time it should be in the range [0, 0x100)
    (0.20, [0, 0xff, 0x100]),   # 20% of the time it should be on of 0, 0xff, or 0x100
    (0.05, {"min": 0, "max": 0x1000}), # 5% of the time, generate a number in [min, max)
]

NOTE that the percentages need to add up to 100.

This can also be a function/callable that returns an probabilities list. If it is a callable, the currently-being-fuzzed field will be passed in as a parameter.

exception pfp.fuzz.strats.MutationError[source]
pfp.fuzz.strats.STRATS = {None: <class 'pfp.fuzz.strats.StratGroup'>, 'basic': <class 'pfp.fuzz.basic.BasicStrat'>}

Stores information on registered StatGroups

class pfp.fuzz.strats.StratGroup[source]

StatGroups choose which sub-fields should be mutated, and which FieldStrat should be used to do the mutating.

The filter_fields method is intended to be overridden to provide custom filtering of child leaf fields should be mutated.

filter_fields(field_list)[source]

Intented to be overridden. Should return a list of fields to be mutated.

Field_list:The list of fields to filter
get_field_strat(field)[source]

Return the strategy defined for the field.

Field:The field
Returns:The FieldStrat for the field or None
name = None

The unique name of the fuzzing strategy group. Can be used as the strat_name_or_cls parameter to the pfp.fuzz.mutate() function

which(field)[source]

Return a list of leaf fields that should be mutated. If the field passed in is a leaf field, it will be returned in a list.

class pfp.fuzz.strats.StratGroupMeta(*args, **kwargs)[source]

A metaclass for StratGroups that tracks subclasses of the StatGroup class.

pfp.fuzz.strats.get_strategy(name_or_cls)[source]

Return the strategy identified by its name. If name_or_class is a class, it will be simply returned.

This module defines basic mutation strategies

class pfp.fuzz.basic.BasicStrat[source]

A basic strategy that has FieldStrats (field strategies) defined for every field type. Nothing fancy, just basic.

class Double[source]
klass

alias of pfp.fields.Double

class Enum[source]
klass

alias of pfp.fields.Enum

class Float[source]
klass

alias of pfp.fields.Float

class Int[source]
class String[source]
klass

alias of pfp.fields.String

next_val(field)[source]

Return a new value to mutate a field with. Do not modify the field directly in this function. Override the mutate() function if that is needed (the field is only passed into this function as a reference).

Field:The pfp.fields.Field instance that will receive the new value. Passed in for reference only.
Returns:The next value for the field