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 apfp.fields.Dom
object, although in the normal use case it will be.strat_name_or_cls
- The name (or direct class) of theStratGroup
to usenum
- The number of iterations to perform. Defaults to100
at_once
- The number of fields to fuzz at once. Defaults to1
yield_changed
- If true, the mutate generator will yield a tuple of(mutated_dom,changed_fields)
, where changed_fields is aset
(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 toFalse
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]¶
-
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
, yieldingnum
mutations that affect up toat_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 (ifyield_changed
isTrue
). 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
, yieldingnum
mutations that affect up toat_once
fields at once. This function will yield back the field after each mutation, optionally also yielding aset
of fields that were mutated in that iteration (ifyield_changed
isTrue
). 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.
-
-
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 thepfp.fuzz.mutate()
function
-
-
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
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
-
-
class