mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-10 01:01:33 +00:00
python mutator examples added
This commit is contained in:
parent
4e3d921f1a
commit
d10ebd1a68
@ -21,6 +21,9 @@ american fuzzy lop plus plus
|
||||
https://github.com/andreafioraldi/afl and got the community patches applied
|
||||
to it.
|
||||
|
||||
C. Hoellers Python mutator module support was added too
|
||||
(https://github.com/choeller/afl)
|
||||
|
||||
So all in all this is the best-of AFL that is currently out there :-)
|
||||
|
||||
|
||||
|
@ -12,6 +12,8 @@ Adding custom mutators to AFL using Python modules
|
||||
NOTE: This is for Python 2.7 !
|
||||
Anyone who wants to add Python 3.7 support is happily welcome :)
|
||||
|
||||
For an example and a template see ../python_mutators/
|
||||
|
||||
|
||||
1) Description and purpose
|
||||
--------------------------
|
||||
@ -50,6 +52,7 @@ is requested.
|
||||
There is also optional support for a trimming API, see the section below for
|
||||
further information about this feature.
|
||||
|
||||
|
||||
3) How to compile AFLFuzz with Python support
|
||||
---------------------------------------------
|
||||
|
||||
@ -91,6 +94,7 @@ AFL_DEBUG - When combined with AFL_NO_UI, this causes the C trimming code
|
||||
to emit additional messages about the performance and actions
|
||||
of your custom Python trimmer. Use this to see if it works :)
|
||||
|
||||
|
||||
5) Order and statistics
|
||||
-----------------------
|
||||
|
||||
@ -99,6 +103,7 @@ the havoc stage). In the statistics however, it shows up as the third number
|
||||
under "havoc". That's because I'm lazy and I didn't want to mess with the UI
|
||||
too much ;)
|
||||
|
||||
|
||||
6) Trimming support
|
||||
-------------------
|
||||
|
||||
|
11
python_mutators/README
Normal file
11
python_mutators/README
Normal file
@ -0,0 +1,11 @@
|
||||
These are example and helper files for the AFL_PYTHON_MODULE feature.
|
||||
See docs/python_mutators.txt for more information
|
||||
|
||||
|
||||
example.py - this is the template you can use, the functions are there
|
||||
but they are empty
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
37
python_mutators/common.py
Normal file
37
python_mutators/common.py
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
Module containing functions shared between multiple AFL modules
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import random
|
||||
import os
|
||||
import re
|
||||
|
||||
def randel(l):
|
||||
if not l:
|
||||
return None
|
||||
return l[random.randint(0,len(l)-1)]
|
||||
|
||||
def randel_pop(l):
|
||||
if not l:
|
||||
return None
|
||||
return l.pop(random.randint(0,len(l)-1))
|
||||
|
||||
def write_exc_example(data, exc):
|
||||
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
|
||||
|
||||
if not os.path.exists(exc_name):
|
||||
with open(exc_name, 'w') as f:
|
||||
f.write(data)
|
103
python_mutators/example.py
Normal file
103
python_mutators/example.py
Normal file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
Example Python Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
|
||||
import random
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
'''
|
||||
random.seed(seed)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
'''
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@param buf: The buffer that should be mutated.
|
||||
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
||||
ret = bytearray(buf)
|
||||
# Do something interesting with ret
|
||||
|
||||
return ret
|
||||
|
||||
# Uncomment and implement the following methods if you want to use a custom
|
||||
# trimming algorithm. See also the documentation for a better API description.
|
||||
|
||||
# def init_trim(buf):
|
||||
# '''
|
||||
# Called per trimming iteration.
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer that should be trimmed.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The maximum number of trimming steps.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# # Initialize global variables
|
||||
#
|
||||
# # Figure out how many trimming steps are possible.
|
||||
# # If this is not possible for your trimming, you can
|
||||
# # return 1 instead and always return 0 in post_trim
|
||||
# # until you are done (then you return 1).
|
||||
#
|
||||
# return steps
|
||||
#
|
||||
# def trim():
|
||||
# '''
|
||||
# Called per trimming iteration.
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: A new bytearray containing the trimmed data.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# # Implement the actual trimming here
|
||||
#
|
||||
# return bytearray(...)
|
||||
#
|
||||
# def post_trim(success):
|
||||
# '''
|
||||
# Called after each trimming operation.
|
||||
#
|
||||
# @type success: bool
|
||||
# @param success: Indicates if the last trim operation was successful.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The next trim index (0 to max number of steps) where max
|
||||
# number of steps indicates the trimming is done.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# if not success:
|
||||
# # Restore last known successful input, determine next index
|
||||
# else:
|
||||
# # Just determine the next index, based on what was successfully
|
||||
# # removed in the last step
|
||||
#
|
||||
# return next_index
|
59
python_mutators/simple-chunk-replace.py
Normal file
59
python_mutators/simple-chunk-replace.py
Normal file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
Simple Chunk Cross-Over Replacement Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
'''
|
||||
|
||||
import random
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
'''
|
||||
# Seed our RNG
|
||||
random.seed(seed)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
'''
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@param buf: The buffer that should be mutated.
|
||||
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
||||
# Make a copy of our input buffer for returning
|
||||
ret = bytearray(buf)
|
||||
|
||||
# Take a random fragment length between 2 and 32 (or less if add_buf is shorter)
|
||||
fragment_len = random.randint(1, min(len(add_buf), 32))
|
||||
|
||||
# Determine a random source index where to take the data chunk from
|
||||
rand_src_idx = random.randint(0, len(add_buf) - fragment_len)
|
||||
|
||||
# Determine a random destination index where to put the data chunk
|
||||
rand_dst_idx = random.randint(0, len(buf))
|
||||
|
||||
# Make the chunk replacement
|
||||
ret[rand_dst_idx:rand_dst_idx + fragment_len] = add_buf[rand_src_idx:rand_src_idx + fragment_len]
|
||||
|
||||
# Return data
|
||||
return ret
|
Loading…
x
Reference in New Issue
Block a user