Beispiel #1
0
    def __init__(self, opts):
        """
        :opts:
                {
                    debug:                    (boolean) Whether to print debug output,
                    coverage:                 (boolean) Coverage flag is passed for instrumentation module,
                    jobs:                     (int) Number of jobs to run concurrently,
                    input_module:             (string) Module to use for input generation,
                    fuzzing_module:           (string) Module to use for fuzzing the data,
                    preprocessing_module:     (string) Module to use for preprocessing the data,
                    instrumentation_module:   (string) Module to use for instrumentation
                }
        """
        self._init_logging()

        self.scheduled_functions = []

        self.process_management = ProcessManagement(opts)
        self.process_management.log = self.log
        self.process_management.new_process_handler = self.new_process_handler
        self.process_management.end_process_handler = self.end_process_handler

        # Load modules
        for key, item in opts.items():
            if key.endswith("_module"):
                getattr(self, "_load_%s" % key)(item)

        signal.signal(signal.SIGINT, self.exit)
Beispiel #2
0
class Fuzzer():
    """
    The base fuzzer class provides a standard handler
    interfaces to be used from external libraries like
    ProcessManagement.
    """

    def __init__(self, opts):
        """
        :opts:
                {
                    debug:                    (boolean) Whether to print debug output,
                    coverage:                 (boolean) Coverage flag is passed for instrumentation module,
                    jobs:                     (int) Number of jobs to run concurrently,
                    input_module:             (string) Module to use for input generation,
                    fuzzing_module:           (string) Module to use for fuzzing the data,
                    preprocessing_module:     (string) Module to use for preprocessing the data,
                    instrumentation_module:   (string) Module to use for instrumentation
                }
        """
        self._init_logging()

        self.scheduled_functions = []

        self.process_management = ProcessManagement(opts)
        self.process_management.log = self.log
        self.process_management.new_process_handler = self.new_process_handler
        self.process_management.end_process_handler = self.end_process_handler

        # Load modules
        for key, item in opts.items():
            if key.endswith("_module"):
                getattr(self, "_load_%s" % key)(item)

        signal.signal(signal.SIGINT, self.exit)

    def _init_logging(self):
        """
        Initialize standardized logging.
        """
        logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(message)s", datefmt="%H:%M:%S")
        self.log = logging.getLogger(__name__)
        self.log.setLevel(logging.INFO)

        if self.debug:
            self.log.setLevel(logging.DEBUG)

    def exit(self, *args):
        """
        When exiting, it is necessary to signal other
        threads that the program is exiting. This is
        so far done by using "running" flags.
        """
        self.process_management.running = False
        self.process_management.kill_processes()

        if hasattr(self, "_exit"):
            self._exit()

        sys.exit()

    def _load_module(self, path, module):
        """
        Load specified modules from the ./modules
        directory. If module is not specified, then
        is should be using "default" module which
        does nothing.
        """
        if not module:
            module = "default"

        self.log.debug("Using %s.%s module" % (path, module))

        try:
            return importlib.import_module("%s.%s" % (path, module))

        except ImportError as e:
            self.log.debug(path)
            self.log.debug(module)
            self.log.error(e)
            self.exit()

    def _load_preprocessing_module(self, module):
        """
        See _load_module.
        """
        preprocessing_module = self._load_module("modules.preprocessing", module)
        self.preprocessor = preprocessing_module.PreprocessingModule(self.log)

    def _load_input_module(self, module):
        """
        See _load_module.
        """
        input_module = self._load_module("modules.input", module)
        self.inputer = input_module.InputModule(self.log)

    def _load_fuzzing_module(self, module):
        """
        See _load_module.
        """
        fuzzing_module = self._load_module("modules.fuzzing", module)
        self.fuzzer = fuzzing_module.FuzzingModule(self.log)

    def _load_instrumentation_module(self, module):
        """
        See _load_module.
        """
        instrumentation_module = self._load_module("modules.instrumentation", module)
        self.instrumentation = instrumentation_module.InstrumentationModule(self.log, coverage=self.coverage)

    def new_process_handler(self, process):
        """
        This handler specifies how new processes are created.
        Additional attributes for the Process object can be added
        as needed in the _new_process_handler() function.
        """
        if not hasattr(self, "_new_process_handler"):
            self.log.error("_new_process_handler() does not exists")
            self.exit()

        if not hasattr(process, "instrumentation"):
            process.instrumentation = copy.copy(self.instrumentation)

        return self._new_process_handler(process)

    def post_start_handler(self, process):
        """
        After the subprocess starts, pass control to the
        _post_start_handler() for required post-start processing.
        """
        return self._post_start_handler(process)

    def data_handler(self, data, index):
        """
        By default pass data through preprocessing and
        fuzzing modules. Pass all data to _data_handler()
        which must return single data to the caller.
        """
        processed = self.preprocessor.preprocess(data)
        malformed = self.fuzzer.fuzz(processed)

        return self._data_handler(index, data, processed, malformed)

    def end_process_handler(self, process):
        """
        When processes have ended, they are passed first to the
        instrumentation module and then to the _end_process_handler.
        Afterwards the process object will kill and replace the
        subprocess.

        NOTE
        The instrumentation module must make do with all the attributes
        of the process object.
        """
        if not hasattr(self, "_end_process_handler"):
            self.log.error("end_process() function does not exists")
            self.exit()

        process.instrumentation.instrument(process)
        self._end_process_handler(process)

    def main_loop(self):
        """
        Fuzzers that inherit the base Fuzzer class should
        finally pass control to the main_loop() function
        and if necessary, set scheduled functions to run
        at one second intervals.
        """
        try:
            self.process_management.jobs = int(self.jobs)
            self.process_management.start()

        except TypeError:
            pass

        while True:
            time.sleep(1)

            for function in self.scheduled_functions:
                self.log.debug("Calling scheduled functions")
                function()