From d14814e5a2bc901248663f17528f2b7751953395 Mon Sep 17 00:00:00 2001 From: pwnslinger Date: Wed, 27 Dec 2017 03:08:51 +0000 Subject: [PATCH] set AFL_PATH to point to the correct afl_tracer --- fuzzer/fuzzer.py | 55 +++++++++++++++++++++++++++++++++----------- shellphuzz | 24 ++++++++++++++----- tests/test_fuzzer.py | 38 ++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/fuzzer/fuzzer.py b/fuzzer/fuzzer.py index 2e7fd59..f73fcd0 100644 --- a/fuzzer/fuzzer.py +++ b/fuzzer/fuzzer.py @@ -7,7 +7,7 @@ import threading import subprocess import shellphish_afl - +from elftools.elf import elffile import logging l = logging.getLogger("fuzzer.fuzzer") @@ -157,24 +157,51 @@ def __init__( self.qemu_name = 'TODO' else: - p = angr.Project(binary_path) + # when CLE doesn't support specific arch then get arch using + # elftools and set the approporiate AFL_PATH environment variable + # https://github.com/eliben/pyelftools/blob/master/elftools/elf/enums.py + try: + p = angr.Project(binary_path) + except RuntimeError: + l.debug("CLE doesn't support this arch for now, so it means you can only use AFL_FUZZ without driller") + self.binary = elffile.ELFFile(open(self.binary_path,'r')) + self.e_machine = self.binary.header.e_machine + if self.e_machine == 'EM_SH': + self.afl_path_var = shellphish_afl.afl_path_var('sh4') + elif self.e_machine == 'EM_S390': + self.afl_path_var = shellphish_afl.afl_path_var('s390x') + elif self.e_machine == 'EM_ALPHA' or self.e_machine == 36902: + self.afl_path_var = shellphish_afl.afl_path_var('alpha') + elif self.e_machine == "EM_PARISC": + self.afl_path_var = shellphish_afl.afl_path_var('hppa') + elif self.e_machine == "EM_CRIS": + self.afl_path_var = shellphish_afl.afl_path_var('cris') + elif self.e_machine == "EM_MICROBLAZE": + self.afl_path_var = shellphish_afl.afl_path_var('microblaze') + elif self.e_machine == "EM_68HC12": + self.afl_path_var = shellphish_afl.afl_path_var('m68k') + + try: + self.os = p.loader.main_object.os - self.os = p.loader.main_object.os + self.afl_dir = shellphish_afl.afl_dir(self.os) - self.afl_dir = shellphish_afl.afl_dir(self.os) + # the path to AFL capable of calling driller + self.afl_path = shellphish_afl.afl_bin(self.os) - # the path to AFL capable of calling driller - self.afl_path = shellphish_afl.afl_bin(self.os) + if self.os == 'cgc': + self.afl_path_var = shellphish_afl.afl_path_var('cgc') + else: + self.afl_path_var = shellphish_afl.afl_path_var(p.arch.qemu_name) + # set up libraries + self._export_library_path(p) - if self.os == 'cgc': - self.afl_path_var = shellphish_afl.afl_path_var('cgc') - else: - self.afl_path_var = shellphish_afl.afl_path_var(p.arch.qemu_name) - # set up libraries - self._export_library_path(p) + # the name of the qemu port used to run these binaries + self.qemu_name = p.arch.qemu_name - # the name of the qemu port used to run these binaries - self.qemu_name = p.arch.qemu_name + except NameError: + self.afl_dir = shellphish_afl.afl_dir('unix') + self.afl_path = shellphish_afl.afl_bin('unix') self.qemu_dir = self.afl_path_var diff --git a/shellphuzz b/shellphuzz index c00f11b..8f7df12 100755 --- a/shellphuzz +++ b/shellphuzz @@ -12,6 +12,7 @@ import tarfile import argparse import importlib import logging.config +from elftools.elf import elffile if __name__ == "__main__": parser = argparse.ArgumentParser(description="Shellphish fuzzer interface") @@ -23,6 +24,7 @@ if __name__ == "__main__": 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('-M', '--memory', help="Memory limitation") 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.") @@ -46,6 +48,7 @@ if __name__ == "__main__": drill_extension = None grease_extension = None + start_driller = True if args.grease_with: print "[*] Greasing..." @@ -54,18 +57,27 @@ if __name__ == "__main__": 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) + if args.driller_workers: + binary = elffile.ELFFile(open(args.binary,'r')) + e_machine = binary.header.e_machine + if e_machine in ('EM_SH', 'EM_S390', 'EM_ALPHA', 'EM_PARISC', 'EM_CRIS','EM_MICROBLAZE','EM_68HC12'): + start_driller = False + print "[-] Driller cannot guide fuzzing on this binary..." + else: + print "[*] Drilling..." + drill_extension = driller.LocalCallback(num_workers=args.driller_workers) + + # FIXME: if binary not supported so start_driller = False and + # drill_extension = None stuck_callback = ( - (lambda f: (grease_extension(f), drill_extension(f))) if drill_extension and grease_extension - else drill_extension or grease_extension + (lambda f: (grease_extension(f), drill_extension(f))) if (drill_extension and start_driller) and grease_extension + else drill_extension if is not None or grease_extension ) print "[*] Creating fuzzer..." fuzzer = fuzzer.Fuzzer( - args.binary, args.work_dir, afl_count=args.afl_cores, force_interval=args.force_interval, + args.binary, args.work_dir, memory=args.memory, afl_count=args.afl_cores, force_interval=args.force_interval, create_dictionary=not args.no_dictionary, stuck_callback=stuck_callback, time_limit=args.timeout ) diff --git a/tests/test_fuzzer.py b/tests/test_fuzzer.py index 3fd42eb..daa6dcb 100644 --- a/tests/test_fuzzer.py +++ b/tests/test_fuzzer.py @@ -3,6 +3,7 @@ import tempfile import subprocess import fuzzer +import glob import logging l = logging.getLogger("fuzzer.tests.test_fuzzer") @@ -66,6 +67,43 @@ def test_showmap(): for te in true_dict.keys(): nose.tools.assert_equal(true_dict[te], smap[te]) +def test_fuzzer_other_arch(): + """ + Test that fuzzer works fine on other archs + """ + + import logging + logging.getLogger("fuzzer").setLevel("DEBUG") + + binary = os.path.join(bin_location, "tests/") + archs = [f for f in os.listdir(binary) if os.path.isdir(os.path.join(binary,f))] + for arch in archs: + arch_path = os.path.join(binary,arch) + binaries = [os.path.join(arch_path,b) for b in os.listdir(arch_path) if os.path.isfile(os.path.join(arch_path,b))] + if len(binaries) == 0: + depth_path = glob.glob(os.path.join(arch_path,'*/*/')) + dirs = filter(lambda f: os.path.isdir(f), depth_path) + if len(dirs) == 0: + continue + binaries = [[os.path.join(d,b) for b in os.listdir(d) if os.path.isfile(os.path.join(d,b))] for d in dirs] + if len(binaries) == 0: + continue + print "[*] Testing fuzzer on {0} for {1} binaries\n".format(arch, len(binaries)) + + f = fuzzer.Fuzzer(binaries, "bazinga") + f.start() + + for _ in range(15): + if f.alive: + break + time.sleep(1) + + nose.tools.assert_true(f.alive) + + if f.alive: + f.kill() + + def test_fuzzer_spawn(): """ Test that the fuzzer spawns correctly