diff options
author | van Hauser <vh@thc.org> | 2021-05-10 13:57:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-10 13:57:47 +0200 |
commit | 8b7a7b29c60f11cdf6226b3e418e87a5c3f5caac (patch) | |
tree | 6ce9d90644f161d21d802e9cbe48eb38467684e9 /utils/custom_mutators/XmlMutatorMin.py | |
parent | d0225c2c4d465968660a08c93857fed354e539b1 (diff) | |
download | afl++-8b7a7b29c60f11cdf6226b3e418e87a5c3f5caac.tar.gz |
Push to stable (#895)
* sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name <you@example.com> * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name <you@example.com> * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name <you@example.com> * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name <you@example.com> * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name <you@example.com> * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com> * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name <you@example.com> * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name <you@example.com> * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name <you@example.com> * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name <you@example.com> * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation Co-authored-by: Dominik Maier <domenukk@gmail.com> Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name <you@example.com> Co-authored-by: Dmitry Zheregelya <zheregelya.d@gmail.com> Co-authored-by: hexcoder <hexcoder-@users.noreply.github.com> Co-authored-by: hexcoder- <heiko@hexco.de> Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com> Co-authored-by: David CARLIER <devnexen@gmail.com> Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev <SecNotice@ya.ru>
Diffstat (limited to 'utils/custom_mutators/XmlMutatorMin.py')
-rw-r--r-- | utils/custom_mutators/XmlMutatorMin.py | 348 |
1 files changed, 0 insertions, 348 deletions
diff --git a/utils/custom_mutators/XmlMutatorMin.py b/utils/custom_mutators/XmlMutatorMin.py deleted file mode 100644 index 3e6cd0ff..00000000 --- a/utils/custom_mutators/XmlMutatorMin.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/python - -""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """ - -from __future__ import print_function -from copy import deepcopy -from lxml import etree as ET -import random, re, io - - -########################### -# The XmlMutatorMin class # -########################### - - -class XmlMutatorMin: - - """ - Optionals parameters: - seed Seed used by the PRNG (default: "RANDOM") - verbose Verbosity (default: False) - """ - - def __init__(self, seed="RANDOM", verbose=False): - - """ Initialize seed, database and mutators """ - - # Verbosity - self.verbose = verbose - - # Initialize PRNG - self.seed = str(seed) - if self.seed == "RANDOM": - random.seed() - else: - if self.verbose: - print("Static seed '%s'" % self.seed) - random.seed(self.seed) - - # Initialize input and output documents - self.input_tree = None - self.tree = None - - # High-level mutators (no database needed) - hl_mutators_delete = [ - "del_node_and_children", - "del_node_but_children", - "del_attribute", - "del_content", - ] # Delete items - hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values - - # Exposed mutators - self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete - - def __parse_xml(self, xml): - - """ Parse an XML string. Basic wrapper around lxml.parse() """ - - try: - # Function parse() takes care of comments / DTD / processing instructions / ... - tree = ET.parse(io.BytesIO(xml)) - except ET.ParseError: - raise RuntimeError("XML isn't well-formed!") - except LookupError as e: - raise RuntimeError(e) - - # Return a document wrapper - return tree - - def __exec_among(self, module, functions, min_times, max_times): - - """ Randomly execute $functions between $min and $max times """ - - for i in xrange(random.randint(min_times, max_times)): - # Function names are mangled because they are "private" - getattr(module, "_XmlMutatorMin__" + random.choice(functions))() - - def __serialize_xml(self, tree): - - """ Serialize a XML document. Basic wrapper around lxml.tostring() """ - - return ET.tostring( - tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding - ) - - def __ver(self, version): - - """ Helper for displaying lxml version numbers """ - - return ".".join(map(str, version)) - - def reset(self): - - """ Reset the mutator """ - - self.tree = deepcopy(self.input_tree) - - def init_from_string(self, input_string): - - """ Initialize the mutator from a XML string """ - - # Get a pointer to the top-element - self.input_tree = self.__parse_xml(input_string) - - # Get a working copy - self.tree = deepcopy(self.input_tree) - - def save_to_string(self): - - """ Return the current XML document as UTF-8 string """ - - # Return a text version of the tree - return self.__serialize_xml(self.tree) - - def __pick_element(self, exclude_root_node=False): - - """ Pick a random element from the current document """ - - # Get a list of all elements, but nodes like PI and comments - elems = list(self.tree.getroot().iter(tag=ET.Element)) - - # Is the root node excluded? - if exclude_root_node: - start = 1 - else: - start = 0 - - # Pick a random element - try: - elem_id = random.randint(start, len(elems) - 1) - elem = elems[elem_id] - except ValueError: - # Should only occurs if "exclude_root_node = True" - return (None, None) - - return (elem_id, elem) - - def __fuzz_attribute(self): - - """ Fuzz (part of) an attribute value """ - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't replace!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # We have the attribute to modify - # Get its value - attrib_value = rand_elem.get(rand_attrib) - # print("- Value: " + attrib_value) - - # Should we work on the whole value? - func_call = "(?P<func>[a-zA-Z:\-]+)\((?P<args>.*?)\)" - p = re.compile(func_call) - l = p.findall(attrib_value) - if random.choice((True, False)) and l: - # Randomly pick one the function calls - (func, args) = random.choice(l) - # Split by "," and randomly pick one of the arguments - value = random.choice(args.split(",")) - # Remove superfluous characters - unclean_value = value - value = value.strip(" ").strip("'") - # print("Selected argument: [%s]" % value) - else: - value = attrib_value - - # For each type, define some possible replacement values - choices_number = ( - "0", - "11111", - "-128", - "2", - "-1", - "1/3", - "42/0", - "1094861636 idiv 1.0", - "-1123329771506872 idiv 3.8", - "17=$numericRTF", - str(3 + random.randrange(0, 100)), - ) - - choices_letter = ( - "P" * (25 * random.randrange(1, 100)), - "%s%s%s%s%s%s", - "foobar", - ) - - choices_alnum = ( - "Abc123", - "020F0302020204030204", - "020F0302020204030204" * (random.randrange(5, 20)), - ) - - # Fuzz the value - if random.choice((True, False)) and value == "": - - # Empty - new_value = value - - elif random.choice((True, False)) and value.isdigit(): - - # Numbers - new_value = random.choice(choices_number) - - elif random.choice((True, False)) and value.isalpha(): - - # Letters - new_value = random.choice(choices_letter) - - elif random.choice((True, False)) and value.isalnum(): - - # Alphanumeric - new_value = random.choice(choices_alnum) - - else: - - # Default type - new_value = random.choice(choices_alnum + choices_letter + choices_number) - - # If we worked on a substring, apply changes to the whole string - if value != attrib_value: - # No ' around empty values - if new_value != "" and value != "": - new_value = "'" + new_value + "'" - # Apply changes - new_value = attrib_value.replace(unclean_value, new_value) - - # Log something - if self.verbose: - print( - "Fuzzing attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Modify the attribute - rand_elem.set(rand_attrib, new_value.decode("utf-8")) - - def __del_node_and_children(self): - - """High-level minimizing mutator - Delete a random node and its children (i.e. delete a random tree)""" - - self.__del_node(True) - - def __del_node_but_children(self): - - """High-level minimizing mutator - Delete a random node but its children (i.e. link them to the parent of the deleted node)""" - - self.__del_node(False) - - def __del_node(self, delete_children): - - """ Called by the __del_node_* mutators """ - - # Select a node to modify (but the root one) - (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True) - - # If the document includes only a top-level element - # Then we can't pick a element (given that "exclude_root_node = True") - - # Is the document deep enough? - if rand_elem is None: - if self.verbose: - print("Can't delete a node: document not deep enough!") - return - - # Log something - if self.verbose: - but_or_and = "and" if delete_children else "but" - print( - "Deleting tag #%i '%s' %s its children" - % (rand_elem_id, rand_elem.tag, but_or_and) - ) - - if delete_children is False: - # Link children of the random (soon to be deleted) node to its parent - for child in rand_elem: - rand_elem.getparent().append(child) - - # Remove the node - rand_elem.getparent().remove(rand_elem) - - def __del_content(self): - - """High-level minimizing mutator - Delete the attributes and children of a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Log something - if self.verbose: - print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) - - # Reset the node - rand_elem.clear() - - def __del_attribute(self): - - """High-level minimizing mutator - Delete a random attribute from a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't delete!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # Log something - if self.verbose: - print( - "Deleting attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Delete the attribute - rand_elem.attrib.pop(rand_attrib) - - def mutate(self, min=1, max=5): - - """ Execute some high-level mutators between $min and $max times, then some medium-level ones """ - - # High-level mutation - self.__exec_among(self, self.hl_mutators_all, min, max) |