def start(self): if self.started: return self.started = True print "[*] Enable driller..." self.drill_extension = driller.LocalCallback( num_workers=config.DRILLER_WORKERS) print "[*] Initialize fuzzer..." self.fuzzer = fuzzer.Fuzzer( self.binary, config.FUZZ_DIR, afl_count=config.FUZZER_WORKERS, force_interval=config.FUZZER_FORCE_INTERVAL, create_dictionary=True, stuck_callback=self.drill_extension, time_limit=self.time_limit) print "[*] Starting fuzzer..." self.fuzzer.start()
drill_extension = None grease_extension = None if args.grease_with: print("[*] Greasing...") grease_extension = fuzzer.GreaseCallback( args.grease_with, grease_filter=helper_module.grease_filter if helper_module is not None else None, grease_sorter=helper_module.grease_sorter if helper_module is not None else None) print(args.driller_workers) if args.driller_workers: print("[*] Drilling...") drill_extension = driller.LocalCallback( num_workers=args.driller_workers, worker_timeout=args.driller_timeout, length_extension=args.length_extension) # exit() stuck_callback = ((lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension else drill_extension or grease_extension) seeds = None if args.seed_dir: seeds = [] print("[*] Seeding...") for dirpath in args.seed_dir: for filename in os.listdir(dirpath): filepath = os.path.join(dirpath, filename) if not os.path.isfile(filepath):
def main(): parser = argparse.ArgumentParser(description="Shellphish fuzzer interface") parser.add_argument('binary', help="the path to the target binary to fuzz") parser.add_argument('-g', '--grease-with', help="A directory of inputs to grease the fuzzer with when it gets stuck.") parser.add_argument('-d', '--driller_workers', help="When the fuzzer gets stuck, drill with N workers.", type=int) parser.add_argument('-f', '--force_interval', help="Force greaser/fuzzer assistance at a regular interval (in seconds).", type=float) parser.add_argument('-w', '--work-dir', help="The work directory for AFL.", default="/dev/shm/work/") parser.add_argument('-c', '--afl-cores', help="Number of AFL workers to spin up.", default=1, type=int) parser.add_argument('-C', '--first-crash', help="Stop on the first crash.", action='store_true', default=False) parser.add_argument('-t', '--timeout', help="Timeout (in seconds).", type=float) parser.add_argument('-i', '--ipython', help="Drop into ipython after starting the fuzzer.", action='store_true') parser.add_argument('-T', '--tarball', help="Tarball the resulting AFL workdir for further analysis to this file -- '{}' is replaced with the hostname.") parser.add_argument('-m', '--helper-module', help="A module that includes some helper scripts for seed selection and such.") parser.add_argument('--memory', help="Memory limit to pass to AFL (MB, or use k, M, G, T suffixes)", default="8G") parser.add_argument('--no-dictionary', help="Do not create a dictionary before fuzzing.", action='store_true', default=False) parser.add_argument('--logcfg', help="The logging configuration file.", default=".shellphuzz.ini") parser.add_argument('-s', '--seed-dir', action="append", help="Directory of files to seed fuzzer with") parser.add_argument('--run-timeout', help="Number of seconds permitted for each run of binary", type=int) parser.add_argument('--driller-timeout', help="Number of seconds to allow driller to run", type=int, default=10*60) parser.add_argument('--length-extension', help="Try extending inputs to driller by this many bytes", type=int) args = parser.parse_args() if os.path.isfile(os.path.join(os.getcwd(), args.logcfg)): logging.config.fileConfig(os.path.join(os.getcwd(), args.logcfg)) try: os.mkdir("/dev/shm/work/") except OSError: pass if args.helper_module: try: helper_module = importlib.import_module(args.helper_module) except (ImportError, TypeError): helper_module = imp.load_source('fuzzing_helper', args.helper_module) else: helper_module = None drill_extension = None grease_extension = None if args.grease_with: print ("[*] Greasing...") grease_extension = GreaseCallback( args.grease_with, grease_filter=helper_module.grease_filter if helper_module is not None else None, grease_sorter=helper_module.grease_sorter if helper_module is not None else None ) if args.driller_workers: print ("[*] Drilling...") drill_extension = driller.LocalCallback(num_workers=args.driller_workers, worker_timeout=args.driller_timeout, length_extension=args.length_extension) stuck_callback = ( (lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension else drill_extension or grease_extension ) seeds = None if args.seed_dir: seeds = [] print ("[*] Seeding...") for dirpath in args.seed_dir: for filename in os.listdir(dirpath): filepath = os.path.join(dirpath, filename) if not os.path.isfile(filepath): continue with open(filepath, 'rb') as seedfile: seeds.append(seedfile.read()) print ("[*] Creating fuzzer...") fuzzer = Phuzzer( args.binary, args.work_dir, afl_count=args.afl_cores, force_interval=args.force_interval, create_dictionary=not args.no_dictionary, stuck_callback=stuck_callback, time_limit=args.timeout, memory=args.memory, seeds=seeds, timeout=args.run_timeout, ) # start it! print ("[*] Starting fuzzer...") fuzzer.start() if args.ipython: print ("[!]") print ("[!] Launching ipython shell. Relevant variables:") print ("[!]") print ("[!] fuzzer") print ("[!] driller_extension") print ("[!] grease_extension") print ("[!]") import IPython; IPython.embed() try: print ("[*] Waiting for fuzzer completion (timeout: %s, first_crash: %s)." % (args.timeout, args.first_crash)) crash_seen = False while True: time.sleep(5) if not crash_seen and fuzzer.found_crash(): print ("[*] Crash found!") crash_seen = True if args.first_crash: break if fuzzer.timed_out(): print ("[*] Timeout reached.") break except KeyboardInterrupt: print ("[*] Aborting wait. Ctrl-C again for KeyboardInterrupt.") except Exception as e: print ("[*] Unknown exception received (%s). Terminating fuzzer." % e) fuzzer.kill() if drill_extension: drill_extension.kill() raise print ("[*] Terminating fuzzer.") fuzzer.kill() if drill_extension: drill_extension.kill() if args.tarball: print ("[*] Dumping results...") p = os.path.join("/tmp/", "afl_sync") try: shutil.rmtree(p) except (OSError, IOError): pass shutil.copytree(fuzzer.out_dir, p) tar_name = args.tarball.replace("{}", socket.gethostname()) tar = tarfile.open("/tmp/afl_sync.tar.gz", "w:gz") tar.add(p, arcname=socket.gethostname()+'-'+os.path.basename(args.binary)) tar.close() print ("[*] Copying out result tarball to %s" % tar_name) shutil.move("/tmp/afl_sync.tar.gz", tar_name)
def main(): parser = argparse.ArgumentParser(description="Shellphish fuzzer interface") parser.add_argument('binary', help="the path to the target binary to fuzz") parser.add_argument('-o', '--opts', nargs='+', help="Command line options", required=False) parser.add_argument( '-g', '--grease-with', help= "A directory of inputs to grease the fuzzer with when it gets stuck.") parser.add_argument( '-d', '--driller_workers', help="When the fuzzer gets stuck, drill with N workers.", type=int) parser.add_argument( '-f', '--force_interval', help= "Force greaser/fuzzer assistance at a regular interval (in seconds).", type=float) parser.add_argument('-w', '--work-dir', help="The work directory for AFL.", default="/dev/shm/work/") parser.add_argument('-c', '--afl-cores', help="Number of AFL workers to spin up.", default=1, type=int) parser.add_argument('-C', '--first-crash', help="Stop on the first crash.", action='store_true', default=False) parser.add_argument('-t', '--timeout', help="Timeout (in seconds).", type=float, default=None) parser.add_argument('-i', '--ipython', help="Drop into ipython after starting the fuzzer.", action='store_true') parser.add_argument( '-T', '--tarball', help= "Tarball the resulting AFL workdir for further analysis to this file -- '{}' is replaced with the hostname." ) parser.add_argument( '-m', '--helper-module', help= "A module that includes some helper scripts for seed selection and such." ) parser.add_argument( '--memory', help="Memory limit to pass to AFL (MB, or use k, M, G, T suffixes)", default="8G") parser.add_argument('-r', '--resume', help="Resume fuzzers, if possible.", action='store_true', default=False) parser.add_argument( '--technique', help="Prioritization technique for driller exploration.", default="unique") parser.add_argument('--classifier', help="Classifier for SyML exploration.") parser.add_argument('--no-dictionary', help="Do not create a dictionary before fuzzing.", action='store_true', default=False) parser.add_argument('--dictionary', help="Path to custom dictionary.") parser.add_argument('--logcfg', help="The logging configuration file.", default=".shellphuzz.ini") parser.add_argument('-s', '--seed-dir', action="append", help="Directory of files to seed fuzzer with") parser.add_argument( '--run-timeout', help="Number of milliseconds permitted for each run of binary", type=int, default=None) parser.add_argument('--driller-timeout', help="Number of seconds to allow driller to run", type=int, default=99999 * 60) parser.add_argument( '--length-extension', help="Try extending inputs to driller by this many bytes", type=int) args = parser.parse_args() status = { 'start_time': time.time(), 'abort_crash': False, 'abort_program': False, 'abort_tmout': False } if os.path.isfile(os.path.join(os.getcwd(), args.logcfg)): logging.config.fileConfig(os.path.join(os.getcwd(), args.logcfg)) helper_module = None if args.helper_module: try: helper_module = importlib.import_module(args.helper_module) except (ImportError, TypeError): helper_module = imp.load_source('fuzzing_helper', args.helper_module) seeds = None if args.seed_dir: print("[*] Seeding...") seeds = [ open(s, 'rb').read() for d in args.seed_dir for s in glob(f"{d}/*") if os.path.isfile(s) ] dictionary = None if args.dictionary: print(f"[*] Reading custom dictionary from file {args.dictionary}...") with open("jpeg.dict", "r", encoding='unicode_escape') as f: dictionary = f.read().encode('raw_unicode_escape').splitlines() print("[*] Creating fuzzer...") status['fuzzer'] = AFL(args.binary, target_opts=args.opts, work_dir=args.work_dir, seeds=seeds, afl_count=args.afl_cores, create_dictionary=not args.no_dictionary, dictionary=dictionary, timeout=args.timeout, memory=args.memory, run_timeout=args.run_timeout, resume=args.resume) ### STUCK CALLBACK ### drill_extension = None grease_extension = None if args.grease_with: print("[*] Greasing...") grease_extension = GreaseCallback( args.grease_with, grease_filter=helper_module.grease_filter if helper_module is not None else None, grease_sorter=helper_module.grease_sorter if helper_module is not None else None) if args.driller_workers: print("[*] Drilling...") print(f"[*] Using technique {args.technique}") technique = { "unique": UniqueSearch, "hard": HardestSearch, "syml": SyMLSearch }[args.technique] drill_extension = driller.LocalCallback( num_workers=args.driller_workers, worker_timeout=args.driller_timeout, length_extension=args.length_extension, technique=technique) stuck_callback = ((lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension else drill_extension or grease_extension) def _stuck_callback(): stuck_callback(status['fuzzer']) _timer = InfiniteTimer(args.force_interval, _stuck_callback) # start it! print("[*] Starting fuzzer...") status['fuzzer'].start() if args.force_interval: _timer.start() if args.classifier: os.system(f"mkdir -p {args.work_dir}/driller/") os.system( f"cp {args.classifier} {args.work_dir}/driller/classifier.pkl") print(f"[*] Using classifier {args.classifier}") ### STATUS CALLBACK ### def status_callback(status): elapsed_time = time.time() - status['start_time'] status_str = build_status_str(elapsed_time, args.first_crash, args.timeout, args.afl_cores, status['fuzzer']) print(status_str, end="\r") if args.first_crash and status['fuzzer'].found_crash(): status['abort_crash'] = True if "PROGRAM ABORT" in open( f"{status['fuzzer'].work_dir}/fuzzer-master.log").read(): status['abort_program'] = True if status['fuzzer'].timed_out(): status['abort_tmout'] = True def _status_callback(): try: status_callback(status) except: pass InfiniteTimer(1, _status_callback).start() if args.ipython: print("[!]") print("[!] Launching ipython shell. Relevant variables:") print("[!]") print("[!] fuzzer") print("[!] driller_extension") print("[!] grease_extension") print("[!]") import IPython IPython.embed() try: while True: time.sleep(1) if status['abort_crash']: print("\n[*] Crash found.") break if status['abort_program']: print("\n[*] Fuzzer aborted.") break if status['abort_tmout']: print("\n[*] Timeout reached.") break except KeyboardInterrupt: print("\n[*] Aborting wait. Ctrl-C again for KeyboardInterrupt.") except Exception as e: print("\n[*] Unknown exception received (%s). Terminating fuzzer." % e) status['fuzzer'].stop() if drill_extension: drill_extension.kill() raise print("[*] Terminating fuzzer.") status['fuzzer'].stop() if drill_extension: drill_extension.kill() if args.tarball: print("[*] Dumping results...") p = os.path.join("/tmp/", "afl_sync") try: shutil.rmtree(p) except (OSError, IOError): pass shutil.copytree(status['fuzzer'].work_dir, p) tar_name = args.tarball.replace("{}", socket.gethostname()) tar = tarfile.open("/tmp/afl_sync.tar.gz", "w:gz") tar.add(p, arcname=socket.gethostname() + '-' + os.path.basename(args.binary)) tar.close() print("[*] Copying out result tarball to %s" % tar_name) shutil.move("/tmp/afl_sync.tar.gz", tar_name) os.killpg(os.getpid(), signal.SIGTERM) # send signal to the process group
def main(): parser = argparse.ArgumentParser(description="Shellphish fuzzer interface") parser.add_argument('binary', help="the path to the target binary to fuzz") parser.add_argument( '-g', '--grease-with', help= "A directory of inputs to grease the fuzzer with when it gets stuck.") parser.add_argument( '-d', '--driller_workers', help="When the fuzzer gets stuck, drill with N workers.", type=int) parser.add_argument( '-f', '--force_interval', help= "Force greaser/fuzzer assistance at a regular interval (in seconds).", type=float) parser.add_argument('-w', '--work-dir', help="The work directory for AFL.", default="/dev/shm/work/") parser.add_argument( '-l', '--login-data', help="The json file from which to get the login information", default="") parser.add_argument('-c', '--afl-cores', help="Number of AFL workers to spin up.", default=1, type=int) parser.add_argument('-C', '--first-crash', help="Stop on the first crash.", action='store_true', default=False) parser.add_argument('-Q', '--use-qemu', help="Use qemu to trace binary.", action='store_true', default=False) parser.add_argument('-t', '--timeout', help="Timeout (in seconds).", type=float, default=None) parser.add_argument('-i', '--ipython', help="Drop into ipython after starting the fuzzer.", action='store_true') parser.add_argument( '-T', '--tarball', help= "Tarball the resulting AFL workdir for further analysis to this file -- '{}' is replaced with the hostname." ) parser.add_argument( '-m', '--helper-module', help= "A module that includes some helper scripts for seed selection and such." ) parser.add_argument( '-D', '--dictionary', default=None, help="Load the dictionary from a file, with each on a single line ") parser.add_argument( '--memory', help="Memory limit to pass to AFL (MB, or use k, M, G, T suffixes)", default="8G") parser.add_argument('--no-dictionary', help="Do not create a dictionary before fuzzing.", action='store_true', default=False) parser.add_argument('--logcfg', help="The logging configuration file.", default=".shellphuzz.ini") parser.add_argument('-s', '--seed-dir', action="append", help="Directory of files to seed fuzzer with") parser.add_argument( '--run-timeout', help="Number of milliseconds permitted for each run of binary", type=int, default=None) parser.add_argument('--driller-timeout', help="Number of seconds to allow driller to run", type=int, default=10 * 60) parser.add_argument( '--length-extension', help="Try extending inputs to driller by this many bytes", type=int) parser.add_argument('--target-opts', help="Options to pass to target.", default=None, nargs='+') parser.add_argument( '-r', '--resume', help="Resume prior run if possible and do not destroy work directory.", action='store_true', default=False) parser.add_argument('--reportdir', help="The directory to use for the reports.", default=".") parser.add_argument( '-p', '--phuzzer-type', '--fuzzer-type', help="Which phuzzer are you using, AFL, Witcher, AFL_MULTICB.", default=Phuzzer.AFL) parser.add_argument('-e', '--extra-crash-signals', '--extra_crash_signals', help="Use extra crash signals SIGABRT and SIGBUS", action='store_true', default=False) args = parser.parse_args() if os.path.isfile(os.path.join(os.getcwd(), args.logcfg)): logging.config.fileConfig(os.path.join(os.getcwd(), args.logcfg)) try: os.mkdir("/dev/shm/work/") except OSError: pass if args.helper_module: try: helper_module = importlib.import_module(args.helper_module) except (ImportError, TypeError): helper_module = imp.load_source('fuzzing_helper', args.helper_module) else: helper_module = None drill_extension = None grease_extension = None if args.grease_with: print("[*] Greasing...") grease_extension = GreaseCallback( args.grease_with, grease_filter=helper_module.grease_filter if helper_module is not None else None, grease_sorter=helper_module.grease_sorter if helper_module is not None else None) if args.driller_workers and DRILLER_EXISTS: print("[*] Drilling...") drill_extension = driller.LocalCallback( num_workers=args.driller_workers, worker_timeout=args.driller_timeout, length_extension=args.length_extension) stuck_callback = ((lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension else drill_extension or grease_extension) seeds = None if args.seed_dir: seeds = [] print("[*] Seeding...") for dirpath in args.seed_dir: for filename in os.listdir(dirpath): filepath = os.path.join(dirpath, filename) if not os.path.isfile(filepath): continue with open(filepath, 'rb') as seedfile: seeds.append(seedfile.read()) if args.dictionary: built_dict = open(args.dictionary, "rb").read().split(b"\n") else: built_dict = None print("[*] Creating fuzzer...") fuzzer = Phuzzer.phactory( phuzzer_type=args.phuzzer_type, target=args.binary, work_dir=args.work_dir, seeds=seeds, afl_count=args.afl_cores, create_dictionary=not args.no_dictionary, timeout=args.timeout, memory=args.memory, run_timeout=args.run_timeout, dictionary=built_dict, use_qemu=args.use_qemu, resume=args.resume, target_opts=args.target_opts, container_info={ "name": "hacrs/witcher", "iid": "35", "config_cmds": [["mkdir", "-p", f"/Crucible/scratch/35"], ["ln", "-s", "/Crucible_ro/firmae.config", "/Crucible"], ["ln", "-s", "/Crucible_ro/get_bin_data.py", "/Crucible"], ["ln", "-s", "/Crucible_ro/binaries", "/Crucible"], ["cp", "-a", f"/Crucible_ro/scratch/35", "/Crucible/scratch/"]], "env": { "HTTPREQR_LAUNCH_SCRIPT": "/Crucible/scratch/35/run.sh" } }) if args.extra_crash_signals: fuzzer.crashes(signals=(signal.SIGSEGV, signal.SIGILL, signal.SIGABRT, signal.SIGBUS)) # start it! print("[*] Starting fuzzer...") fuzzer.start() start_time = time.time() reporter = Reporter(args.binary, args.reportdir, args.afl_cores, args.first_crash, args.timeout, fuzzer.work_dir) reporter.start() if args.ipython: print("[!]") print("[!] Launching ipython shell. Relevant variables:") print("[!]") print("[!] fuzzer") if args.driller_workers and DRILLER_EXISTS: print("[!] driller_extension") if args.grease_with: print("[!] grease_extension") print("[!]") import IPython IPython.embed() try: loopcnt = 0 #print ("[*] Waiting for fuzzer completion (timeout: %s, first_crash: %s)." % (args.timeout, args.first_crash)) crash_seen = False reporter.enable_printing() while True: if not crash_seen and fuzzer.found_crash(): # print ("\n[*] Crash found!") crash_seen = True reporter.set_crash_seen() if args.first_crash: break if fuzzer.timed_out(): reporter.set_timeout_seen() print("\n[*] Timeout reached.") break time.sleep(1) loopcnt += 1 except KeyboardInterrupt: end_reason = "Keyboard Interrupt" print("\n[*] Aborting wait. Ctrl-C again for KeyboardInterrupt.") except Exception as e: end_reason = "Exception occurred" print("\n[*] Unknown exception received (%s). Terminating fuzzer." % e) fuzzer.stop() if drill_extension: drill_extension.kill() raise print("[*] Terminating fuzzer.") reporter.stop() fuzzer.stop() if drill_extension: drill_extension.kill() if args.tarball: print("[*] Dumping results...") p = os.path.join("/tmp/", "afl_sync") try: shutil.rmtree(p) except (OSError, IOError): pass shutil.copytree(fuzzer.work_dir, p) tar_name = args.tarball.replace("{}", socket.gethostname()) tar = tarfile.open("/tmp/afl_sync.tar.gz", "w:gz") tar.add(p, arcname=socket.gethostname() + '-' + os.path.basename(args.binary)) tar.close() print("[*] Copying out result tarball to %s" % tar_name) shutil.move("/tmp/afl_sync.tar.gz", tar_name)