1#!/usr/bin/env python
2
3from XmlMutatorMin import XmlMutatorMin
4
5# Default settings (production mode)
6
7__mutator__ = None
8__seed__ = "RANDOM"
9__log__ = False
10__log_file__ = "wrapper.log"
11
12
13# AFL functions
14def log(text):
15    """
16    Logger
17    """
18
19    global __seed__
20    global __log__
21    global __log_file__
22
23    if __log__:
24        with open(__log_file__, "a") as logf:
25            logf.write("[%s] %s\n" % (__seed__, text))
26
27
28def init(seed):
29    """
30    Called once when AFL starts up. Seed is used to identify the AFL instance in log files
31    """
32
33    global __mutator__
34    global __seed__
35
36    # Get the seed
37    __seed__ = seed
38
39    # Create a global mutation class
40    try:
41        __mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
42        log("init(): Mutator created")
43    except RuntimeError as e:
44        log("init(): Can't create mutator: %s" % e.message)
45
46
47def fuzz(buf, add_buf, max_size):
48    """
49    Called for each fuzzing iteration.
50    """
51
52    global __mutator__
53
54    # Do we have a working mutator object?
55    if __mutator__ is None:
56        log("fuzz(): Can't fuzz, no mutator available")
57        return buf
58
59    # Try to use the AFL buffer
60    via_buffer = True
61
62    # Interpret the AFL buffer (an array of bytes) as a string
63    if via_buffer:
64        try:
65            buf_str = str(buf)
66            log("fuzz(): AFL buffer converted to a string")
67        except Exception:
68            via_buffer = False
69            log("fuzz(): Can't convert AFL buffer to a string")
70
71    # Load XML from the AFL string
72    if via_buffer:
73        try:
74            __mutator__.init_from_string(buf_str)
75            log(
76                "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)"
77                % len(buf_str)
78            )
79        except Exception:
80            via_buffer = False
81            log("fuzz(): Can't initialize mutator with AFL buffer")
82
83    # If init from AFL buffer wasn't succesful
84    if not via_buffer:
85        log("fuzz(): Returning unmodified AFL buffer")
86        return buf
87
88    # Sucessful initialization -> mutate
89    try:
90        __mutator__.mutate(max=5)
91        log("fuzz(): Input mutated")
92    except Exception:
93        log("fuzz(): Can't mutate input => returning buf")
94        return buf
95
96    # Convert mutated data to a array of bytes
97    try:
98        data = bytearray(__mutator__.save_to_string())
99        log("fuzz(): Mutated data converted as bytes")
100    except Exception:
101        log("fuzz(): Can't convert mutated data to bytes => returning buf")
102        return buf
103
104    # Everything went fine, returning mutated content
105    log("fuzz(): Returning %d bytes" % len(data))
106    return data
107
108
109# Main (for debug)
110if __name__ == "__main__":
111
112    __log__ = True
113    __log_file__ = "/dev/stdout"
114    __seed__ = "RANDOM"
115
116    init(__seed__)
117
118    in_1 = bytearray(
119        "<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>"
120    )
121    in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
122    out = fuzz(in_1, in_2)
123    print(out)
124