python mutator examples added
MODIFY
docs/README
docs/README
@@ -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 :-)

MODIFY
docs/python_mutators.txt
docs/python_mutators.txt
@@ -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
-------------------

ADD
python_mutators/README
+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 :)

ADD
python_mutators/common.py
+#!/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)

ADD
python_mutators/example.py
+#!/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

ADD
python_mutators/simple-chunk-replace.py
+#!/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

python mutator examples added