From 2f1c91b568411693361aad09b1053fdd9a3605c1 Mon Sep 17 00:00:00 2001 From: Hegusung Date: Tue, 25 Jan 2022 16:55:30 +0100 Subject: [PATCH 01/10] -I added to process_monitor to change the listening IP address --- process_monitor.py | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/process_monitor.py b/process_monitor.py index 1eb09bdc..4bb4e4c8 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -8,28 +8,20 @@ from boofuzz.utils.process_monitor_pedrpc_server import ProcessMonitorPedrpcServer -def serve_procmon(port, crash_bin, proc_name, ignore_pid, log_level): +def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): with ProcessMonitorPedrpcServer( - host="0.0.0.0", - port=port, - crash_filename=crash_bin, - debugger_class=DebuggerThreadSimple, - proc_name=proc_name, - pid_to_ignore=ignore_pid, - level=log_level, - coredump_dir=None, + host=ip, + port=port, + crash_filename=crash_bin, + debugger_class=DebuggerThreadSimple, + proc_name=proc_name, + pid_to_ignore=ignore_pid, + level=log_level, + coredump_dir=None, ) as servlet: servlet.serve_forever() -# app.args.add_argument("-c", "--crash_bin", help='filename to serialize crash bin class to', -# default='boofuzz-crash-bin', metavar='FILENAME') -# app.args.add_argument("-i", "--ignore_pid", help='PID to ignore when searching for target process', type=int, -# metavar='PID') -# app.args.add_argument("-l", "--log_level", help='log level: default 1, increase for more verbosity', type=int, -# default=1, metavar='LEVEL') -# app.args.add_argument("-p", "--proc_name", help='process name to search for and attach to', metavar='NAME') -# app.args.add_argument("-P", "--port", help='TCP port to bind this agent to', type=int, default=DEFAULT_PROCMON_PORT) @click.command() @click.option( "--crash-bin", @@ -58,8 +50,9 @@ def serve_procmon(port, crash_bin, proc_name, ignore_pid, log_level): ) @click.option("--proc-name", "--proc_name", "-p", help="process name to search for and attach to", metavar="NAME") @click.option("--port", "-P", help="TCP port to bind this agent to", type=int, default=DEFAULT_PROCMON_PORT) -def go(crash_bin, ignore_pid, log_level, proc_name, port): - serve_procmon(port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) +@click.option("--ip", "-I", help="IP of the computer", type=str) +def go(crash_bin, ignore_pid, log_level, proc_name, port, ip): + serve_procmon(ip, port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) if __name__ == "__main__": From 2a06481866830dca5843ad9b12ddee5332d8aec8 Mon Sep 17 00:00:00 2001 From: Hegusung Date: Tue, 25 Jan 2022 17:00:35 +0100 Subject: [PATCH 02/10] Making processmonitor compatible with windows --- boofuzz/utils/debugger_thread_simple.py | 31 +++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/boofuzz/utils/debugger_thread_simple.py b/boofuzz/utils/debugger_thread_simple.py index cb414518..4601fbbd 100644 --- a/boofuzz/utils/debugger_thread_simple.py +++ b/boofuzz/utils/debugger_thread_simple.py @@ -152,20 +152,23 @@ def run(self): gone, _ = psutil.wait_procs([self._psutil_proc]) self.exit_status = gone[0].returncode else: - exit_info = os.waitpid(self.pid, 0) - self.exit_status = exit_info[1] # [0] is the pid + # Waitpid doesn't work well on windows, switching to _process.wait() + self.exit_status = self._process.wait() default_reason = "Process died for unknown reason" if self.exit_status is not None: - if os.WCOREDUMP(self.exit_status): - reason = "Segmentation fault" - elif os.WIFSTOPPED(self.exit_status): - reason = "Stopped with signal " + str(os.WTERMSIG(self.exit_status)) - elif os.WIFSIGNALED(self.exit_status): - reason = "Terminated with signal " + str(os.WTERMSIG(self.exit_status)) - elif os.WIFEXITED(self.exit_status): - reason = "Exit with code - " + str(os.WEXITSTATUS(self.exit_status)) - else: + try: + if os.WCOREDUMP(self.exit_status): + reason = "Segmentation fault" + elif os.WIFSTOPPED(self.exit_status): + reason = "Stopped with signal " + str(os.WTERMSIG(self.exit_status)) + elif os.WIFSIGNALED(self.exit_status): + reason = "Terminated with signal " + str(os.WTERMSIG(self.exit_status)) + elif os.WIFEXITED(self.exit_status): + reason = "Exit with code - " + str(os.WEXITSTATUS(self.exit_status)) + else: + reason = default_reason + except AttributeError: # Windows does not support WCOREDUMP reason = default_reason else: reason = default_reason @@ -210,7 +213,11 @@ def get_exit_status(self): def stop_target(self): try: - os.kill(self.pid, signal.SIGKILL) + try: + os.kill(self.pid, signal.SIGKILL) + except AttributeError: + # Windows does not support signal.SIGKILL + os.system("taskkill /F /PID:%d" % self.pid) except OSError as e: print( 'Error while killing process. PID: {0} errno: {1} "{2}"'.format(self.pid, e.errno, os.strerror(e.errno)) From 09e9654381db018a2cb65baed619d70c7628dd28 Mon Sep 17 00:00:00 2001 From: Hegusung Date: Tue, 25 Jan 2022 17:03:27 +0100 Subject: [PATCH 03/10] Session.restart_wait parameter added to wait for a defined time for a process to start properly (by default 3 seconds just like previously) --- boofuzz/sessions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boofuzz/sessions.py b/boofuzz/sessions.py index 39a8ef6d..735e9d97 100644 --- a/boofuzz/sessions.py +++ b/boofuzz/sessions.py @@ -443,6 +443,7 @@ def __init__( restart_callbacks=None, restart_threshold=None, restart_timeout=None, + restart_wait=3, pre_send_callbacks=None, post_test_case_callbacks=None, post_start_target_callbacks=None, @@ -480,6 +481,7 @@ def __init__( self.restart_sleep_time = restart_sleep_time self.restart_threshold = restart_threshold self.restart_timeout = restart_timeout + self.restart_wait = restart_wait if fuzz_loggers is None: fuzz_loggers = [] if self.console_gui and os.name != "nt": @@ -1043,8 +1045,8 @@ def _restart_target(self, target): self._fuzz_data_logger.log_info("Restarting target process using {}".format(monitor.__class__.__name__)) if monitor.restart_target(target=target, fuzz_data_logger=self._fuzz_data_logger, session=self): # TODO: doesn't this belong in the process monitor? - self._fuzz_data_logger.log_info("Giving the process 3 seconds to settle in") - time.sleep(3) + self._fuzz_data_logger.log_info("Giving the process %d seconds to settle in" % self.restart_wait) + time.sleep(self.restart_wait) restarted = True break From 8ee71bcaaf62377f948258d45c9a0f6d6a094729 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 25 Jan 2022 16:14:27 +0000 Subject: [PATCH 04/10] Fixing style errors. --- boofuzz/utils/debugger_thread_simple.py | 2 +- process_monitor.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/boofuzz/utils/debugger_thread_simple.py b/boofuzz/utils/debugger_thread_simple.py index 4601fbbd..5866117e 100644 --- a/boofuzz/utils/debugger_thread_simple.py +++ b/boofuzz/utils/debugger_thread_simple.py @@ -168,7 +168,7 @@ def run(self): reason = "Exit with code - " + str(os.WEXITSTATUS(self.exit_status)) else: reason = default_reason - except AttributeError: # Windows does not support WCOREDUMP + except AttributeError: # Windows does not support WCOREDUMP reason = default_reason else: reason = default_reason diff --git a/process_monitor.py b/process_monitor.py index 4bb4e4c8..d97579d6 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -10,14 +10,14 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): with ProcessMonitorPedrpcServer( - host=ip, - port=port, - crash_filename=crash_bin, - debugger_class=DebuggerThreadSimple, - proc_name=proc_name, - pid_to_ignore=ignore_pid, - level=log_level, - coredump_dir=None, + host=ip, + port=port, + crash_filename=crash_bin, + debugger_class=DebuggerThreadSimple, + proc_name=proc_name, + pid_to_ignore=ignore_pid, + level=log_level, + coredump_dir=None, ) as servlet: servlet.serve_forever() From c128a57498e78e82d8074d51331d93ebbf5b8e06 Mon Sep 17 00:00:00 2001 From: hegusung Date: Fri, 28 Jan 2022 12:01:34 +0100 Subject: [PATCH 05/10] Default interface added --- process_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process_monitor.py b/process_monitor.py index d97579d6..119d34e6 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -50,7 +50,7 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): ) @click.option("--proc-name", "--proc_name", "-p", help="process name to search for and attach to", metavar="NAME") @click.option("--port", "-P", help="TCP port to bind this agent to", type=int, default=DEFAULT_PROCMON_PORT) -@click.option("--ip", "-I", help="IP of the computer", type=str) +@click.option("--ip", "-I", help="IP of the computer", type=str, default='0.0.0.0') def go(crash_bin, ignore_pid, log_level, proc_name, port, ip): serve_procmon(ip, port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) From 67c7e92653252855e1d7d538c2c778ded28737ea Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 28 Jan 2022 11:02:06 +0000 Subject: [PATCH 06/10] Fixing style errors. --- process_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process_monitor.py b/process_monitor.py index 119d34e6..5fae5c9c 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -50,7 +50,7 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): ) @click.option("--proc-name", "--proc_name", "-p", help="process name to search for and attach to", metavar="NAME") @click.option("--port", "-P", help="TCP port to bind this agent to", type=int, default=DEFAULT_PROCMON_PORT) -@click.option("--ip", "-I", help="IP of the computer", type=str, default='0.0.0.0') +@click.option("--ip", "-I", help="IP of the computer", type=str, default="0.0.0.0") def go(crash_bin, ignore_pid, log_level, proc_name, port, ip): serve_procmon(ip, port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) From 564e48e74b27ede19e5dd20f9fc800103e933475 Mon Sep 17 00:00:00 2001 From: Hegusung Date: Sat, 30 Apr 2022 17:41:06 +0200 Subject: [PATCH 07/10] Process monitor changes --- process_monitor.py | 2 +- process_monitor_unix.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/process_monitor.py b/process_monitor.py index eeb80cd6..a7a0d57c 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -48,7 +48,7 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): ) @click.option("--proc-name", "--proc_name", "-p", help="process name to search for and attach to", metavar="NAME") @click.option("--port", "-P", help="TCP port to bind this agent to", type=int, default=DEFAULT_PROCMON_PORT) -@click.option("--ip", "-I", help="IP of the computer", type=str, default="0.0.0.0") +@click.option("--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1") def go(crash_bin, ignore_pid, log_level, proc_name, port, ip): serve_procmon(ip, port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) diff --git a/process_monitor_unix.py b/process_monitor_unix.py index 271e0a73..ec074e37 100644 --- a/process_monitor_unix.py +++ b/process_monitor_unix.py @@ -43,9 +43,9 @@ def err(msg): sys.stderr.write("ERR> " + msg + "\n") or sys.exit(1) -def serve_procmon(port, crash_bin, proc_name, ignore_pid, log_level, coredump_dir): +def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level, coredump_dir): with ProcessMonitorPedrpcServer( - host="0.0.0.0", + host=ip, port=port, crash_filename=crash_bin, debugger_class=DebuggerThreadSimple, @@ -92,11 +92,13 @@ def serve_procmon(port, crash_bin, proc_name, ignore_pid, log_level, coredump_di help="directory where coredumps are moved to (you may need to adjust ulimits to create coredumps)", default="coredumps", ) -def go(crash_bin, ignore_pid, log_level, proc_name, port, coredump_dir): +@click.option("--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1") +def go(crash_bin, ignore_pid, log_level, proc_name, port, coredump_dir, ip): if coredump_dir is not None: helpers.mkdir_safe(coredump_dir) serve_procmon( + ip, port=port, crash_bin=crash_bin, proc_name=proc_name, From cc1935003a273b7373cf63a838c36259facf5a45 Mon Sep 17 00:00:00 2001 From: Hegusung Date: Sat, 30 Apr 2022 17:48:54 +0200 Subject: [PATCH 08/10] restart_wait changed to restart_sleep_time --- boofuzz/sessions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/boofuzz/sessions.py b/boofuzz/sessions.py index 18d48ad3..3eb23a7c 100644 --- a/boofuzz/sessions.py +++ b/boofuzz/sessions.py @@ -445,7 +445,6 @@ def __init__( restart_callbacks=None, restart_threshold=None, restart_timeout=None, - restart_wait=3, pre_send_callbacks=None, post_test_case_callbacks=None, post_start_target_callbacks=None, @@ -484,7 +483,6 @@ def __init__( self.restart_sleep_time = restart_sleep_time self.restart_threshold = restart_threshold self.restart_timeout = restart_timeout - self.restart_wait = restart_wait self.web_address = web_address if fuzz_loggers is None: fuzz_loggers = [] @@ -1053,8 +1051,8 @@ def _restart_target(self, target): self._fuzz_data_logger.log_info("Restarting target process using {}".format(monitor.__class__.__name__)) if monitor.restart_target(target=target, fuzz_data_logger=self._fuzz_data_logger, session=self): # TODO: doesn't this belong in the process monitor? - self._fuzz_data_logger.log_info("Giving the process %d seconds to settle in" % self.restart_wait) - time.sleep(self.restart_wait) + self._fuzz_data_logger.log_info("Giving the process %d seconds to settle in" % self.restart_sleep_time) + time.sleep(self.restart_sleep_time) restarted = True break From 7fba2984c96970dd08d768f3d36168229906c9cc Mon Sep 17 00:00:00 2001 From: Hegusung Date: Sat, 30 Apr 2022 17:52:53 +0200 Subject: [PATCH 09/10] Bugfix, skipped = 0 when the second mutant is fuzzed and fails 3 times --- boofuzz/fuzzable.py | 4 ++++ boofuzz/sessions.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/boofuzz/fuzzable.py b/boofuzz/fuzzable.py index 3b635acb..f2e5b25b 100644 --- a/boofuzz/fuzzable.py +++ b/boofuzz/fuzzable.py @@ -50,6 +50,8 @@ def __init__(self, name=None, default_value=None, fuzzable=True, fuzz_values=Non Fuzzable.name_counter += 1 self._name = "{0}{1}".format(type(self).__name__, Fuzzable.name_counter) + self.index_mutation = 0 + @property def fuzzable(self): """If False, this element should not be mutated in normal fuzzing.""" @@ -132,6 +134,7 @@ def get_mutations(self): if not self.fuzzable: return index = 0 + self.index_mutation = 0 for value in itertools.chain(self.mutations(self.original_value()), self._fuzz_values): if self._halt_mutations: self._halt_mutations = False @@ -141,6 +144,7 @@ def get_mutations(self): elif isinstance(value, Mutation): yield [value] else: + self.index_mutation += 1 yield [Mutation(value=value, qualified_name=self.qualified_name, index=index)] index += 1 finally: diff --git a/boofuzz/sessions.py b/boofuzz/sessions.py index 3eb23a7c..af47d8c3 100644 --- a/boofuzz/sessions.py +++ b/boofuzz/sessions.py @@ -942,7 +942,7 @@ def _process_failures(self, target): if not isinstance(self.fuzz_node.mutant, primitives.Group) and not isinstance( self.fuzz_node.mutant, blocks.Repeat ): - skipped = max(0, self.fuzz_node.mutant.get_num_mutations() - self.mutant_index) + skipped = max(0, self.fuzz_node.mutant.get_num_mutations() - self.fuzz_node.mutant.index_mutation) self._skip_current_element_after_current_test_case = True self._fuzz_data_logger.open_test_step( "Crash threshold reached for this element, exhausting {0} mutants.".format(skipped) From 739bc888cb4c2da571709c59fdd1b573663f6ab8 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 3 May 2022 16:32:56 +0000 Subject: [PATCH 10/10] Fixing style errors. --- boofuzz/sessions.py | 4 +++- process_monitor.py | 4 +++- process_monitor_unix.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/boofuzz/sessions.py b/boofuzz/sessions.py index af47d8c3..36651960 100644 --- a/boofuzz/sessions.py +++ b/boofuzz/sessions.py @@ -1051,7 +1051,9 @@ def _restart_target(self, target): self._fuzz_data_logger.log_info("Restarting target process using {}".format(monitor.__class__.__name__)) if monitor.restart_target(target=target, fuzz_data_logger=self._fuzz_data_logger, session=self): # TODO: doesn't this belong in the process monitor? - self._fuzz_data_logger.log_info("Giving the process %d seconds to settle in" % self.restart_sleep_time) + self._fuzz_data_logger.log_info( + "Giving the process %d seconds to settle in" % self.restart_sleep_time + ) time.sleep(self.restart_sleep_time) restarted = True break diff --git a/process_monitor.py b/process_monitor.py index a7a0d57c..8dd6549e 100644 --- a/process_monitor.py +++ b/process_monitor.py @@ -48,7 +48,9 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level): ) @click.option("--proc-name", "--proc_name", "-p", help="process name to search for and attach to", metavar="NAME") @click.option("--port", "-P", help="TCP port to bind this agent to", type=int, default=DEFAULT_PROCMON_PORT) -@click.option("--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1") +@click.option( + "--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1" +) def go(crash_bin, ignore_pid, log_level, proc_name, port, ip): serve_procmon(ip, port=port, crash_bin=crash_bin, proc_name=proc_name, ignore_pid=ignore_pid, log_level=log_level) diff --git a/process_monitor_unix.py b/process_monitor_unix.py index ec074e37..b71a418f 100644 --- a/process_monitor_unix.py +++ b/process_monitor_unix.py @@ -92,7 +92,9 @@ def serve_procmon(ip, port, crash_bin, proc_name, ignore_pid, log_level, coredum help="directory where coredumps are moved to (you may need to adjust ulimits to create coredumps)", default="coredumps", ) -@click.option("--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1") +@click.option( + "--ip", "-I", help="Listen on this IP for incoming connections from boofuzz", type=str, default="127.0.0.1" +) def go(crash_bin, ignore_pid, log_level, proc_name, port, coredump_dir, ip): if coredump_dir is not None: helpers.mkdir_safe(coredump_dir)