def choose_afl(self): """ Chooses the right AFL and sets up some environment. """ # set up the AFL path p = angr.Project(self.target) target_os = p.loader.main_object.os afl_dir = shellphish_afl.afl_dir(target_os) if target_os == 'cgc': afl_path_var = shellphish_afl.afl_path_var('cgc') else: afl_path_var = shellphish_afl.afl_path_var(p.arch.qemu_name) directory = None if p.arch.qemu_name == "aarch64": directory = "arm64" if p.arch.qemu_name == "i386": directory = "i386" if p.arch.qemu_name == "x86_64": directory = "x86_64" if p.arch.qemu_name == "mips": directory = "mips" if p.arch.qemu_name == "mipsel": directory = "mipsel" if p.arch.qemu_name == "ppc": directory = "powerpc" if p.arch.qemu_name == "arm": # some stuff qira uses to determine the which libs to use for arm with open(self.target, "rb") as f: progdata = f.read(0x800) if "/lib/ld-linux.so.3" in progdata: directory = "armel" elif "/lib/ld-linux-armhf.so.3" in progdata: directory = "armhf" if directory is None: l.warning("architecture \"%s\" has no installed libraries", p.arch.qemu_name) else: libpath = os.path.join(afl_dir, "..", "fuzzer-libs", directory) l.debug("exporting QEMU_LD_PREFIX of '%s'", libpath) os.environ['QEMU_LD_PREFIX'] = libpath # set environment variable for the AFL_PATH os.environ['AFL_PATH'] = afl_path_var # return the AFL path return shellphish_afl.afl_bin(target_os)
def __init__(self, binary_path, work_dir, afl_count=1, library_path=None, time_limit=None, target_opts=None, extra_opts=None, create_dictionary=False, seeds=None, crash_mode=False, never_resume=False): ''' :param binary_path: path to the binary to fuzz. List or tuple for multi-CB. :param work_dir: the work directory which contains fuzzing jobs, our job directory will go here :param afl_count: number of AFL jobs total to spin up for the binary :param library_path: library path to use, if none is specified a default is chosen :param timelimit: amount of time to fuzz for, has no effect besides returning True when calling timed_out :param seeds: list of inputs to seed fuzzing with :param target_opts: extra options to pass to the target :param extra_opts: extra options to pass to AFL when starting up :param crash_mode: if set to True AFL is set to crash explorer mode, and seed will be expected to be a crashing input :param never_resume: never resume an old fuzzing run, even if it's possible ''' self.binary_path = binary_path self.work_dir = work_dir self.afl_count = afl_count self.time_limit = time_limit self.library_path = library_path self.target_opts = [ ] if target_opts is None else target_opts self.crash_mode = crash_mode Fuzzer._perform_env_checks() if isinstance(binary_path,basestring): self.is_multicb = False self.binary_id = os.path.basename(binary_path) elif isinstance(binary_path,(list,tuple)): self.is_multicb = True self.binary_id = os.path.basename(binary_path[0]) else: raise ValueError("Was expecting either a string or a list/tuple for binary_path! It's {} instead.".format(type(binary_path))) # sanity check crash mode if self.crash_mode: if seeds is None: raise ValueError("Seeds must be specified if using the fuzzer in crash mode") l.info("AFL will be started in crash mode") self.seeds = ["fuzz"] if seeds is None or len(seeds) == 0 else seeds self.job_dir = os.path.join(self.work_dir, self.binary_id) self.in_dir = os.path.join(self.job_dir, "input") self.out_dir = os.path.join(self.job_dir, "sync") # sanity check extra opts self.extra_opts = extra_opts if self.extra_opts is not None: if not isinstance(self.extra_opts, list): raise ValueError("extra_opts must be a list of command line arguments") # base of the fuzzer package self.base = Fuzzer._get_base() self.start_time = int(time.time()) # create_dict script self.create_dict_path = os.path.join(self.base, "bin", "create_dict.py") # afl dictionary self.dictionary = None # processes spun up self.procs = [ ] # start the fuzzer ids at 0 self.fuzz_id = 0 # test if we're resuming an old run self.resuming = bool(os.listdir(self.out_dir)) if os.path.isdir(self.out_dir) else False # has the fuzzer been turned on? self._on = False if never_resume and self.resuming: l.info("could resume, but starting over upon request") shutil.rmtree(self.job_dir) self.resuming = False if self.is_multicb: # Where cgc/setup's Dockerfile checks it out # NOTE: 'afl/fakeforksrv' serves as 'qemu', as far as AFL is concerned # Will actually invoke 'fakeforksrv/multicb-qemu' # This QEMU cannot run standalone (always speaks the forkserver "protocol"), # but 'fakeforksrv/run_via_fakeforksrv' allows it. # XXX: There is no driller/angr support, and probably will never be. self.afl_path = shellphish_afl.afl_bin('multi-cgc') self.afl_path_var = shellphish_afl.afl_path_var('multi-cgc') else: p = angr.Project(binary_path) self.os = p.loader.main_bin.os 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) self.afl_path_var = shellphish_afl.afl_path_var(p.arch.qemu_name) # set up libraries self._export_library_path(p) self.qemu_dir = self.afl_path_var l.debug("self.start_time: %r", self.start_time) l.debug("self.afl_path: %s", self.afl_path) l.debug("self.afl_path_var: %s", self.afl_path_var) l.debug("self.qemu_dir: %s", self.qemu_dir) l.debug("self.binary_id: %s", self.binary_id) l.debug("self.work_dir: %s", self.work_dir) l.debug("self.resuming: %s", self.resuming) # if we're resuming an old run set the input_directory to a '-' if self.resuming: l.info("[%s] resuming old fuzzing run", self.binary_id) self.in_dir = "-" else: # create the work directory and input directory try: os.makedirs(self.in_dir) except OSError: l.warning("unable to create in_dir \"%s\"", self.in_dir) # populate the input directory self._initialize_seeds() # look for a dictionary dictionary_file = os.path.join(self.job_dir, "%s.dict" % self.binary_id) if os.path.isfile(dictionary_file): self.dictionary = dictionary_file # if a dictionary doesn't exist and we aren't resuming a run, create a dict elif not self.resuming: # call out to another process to create the dictionary so we can # limit it's memory if create_dictionary: if self._create_dict(dictionary_file): self.dictionary = dictionary_file else: # no luck creating a dictionary l.warning("[%s] unable to create dictionary", self.binary_id) # set environment variable for the AFL_PATH os.environ['AFL_PATH'] = self.afl_path_var
import shutil import hashlib #import tarfile import subprocess import shellphish_afl if __name__ == "__main__": # minimizing code p = os.path.join("/tmp/", "afl_seeds") try: os.mkdir(p) except OSError: pass afl_path_var = shellphish_afl.afl_path_var('cgc') afl_path = shellphish_afl.afl_bin('cgc') BIN = sys.argv[1] IN_DIR = sys.argv[2] OUT_DIR = sys.argv[3] os.environ['AFL_PATH'] = afl_path_var # set afl-showmap (super hacky) shutil.copy2(os.path.join(afl_path_var, "../../afl-showmap"), afl_path_var) # run afl-cmin print "### cmin time (binary %s)" % BIN args = [os.path.join(os.path.dirname(__file__), "../afl-cmin")] print "collecting seeds" if os.path.exists("/home/angr/cmin-input"):
def choose_afl(self): """ Chooses the right AFL and sets up some environment. """ # set up the AFL path self.proj = self.proj or angr.Project(self.target, auto_load_libs=False) self.target_os = self.proj.loader.main_object.os self.target_arch = self.proj.arch.qemu_name afl_dir = shellphish_afl.afl_dir(self.target_os) afl_path_var = shellphish_afl.afl_path_var(self.target_arch) directory = None if self.target_arch == "i386": directory = "i386" qemu_base = 0x40000000 if self.target_arch == "x86_64": directory = "x86_64" qemu_base = 0x4000000000 if directory is None: l.warning("architecture \"%s\" has no installed libraries", self.target_arch) elif False: # for now, avoid mixing up libs libpath = os.path.join(afl_dir, "..", "fuzzer-libs", directory) l.debug("exporting QEMU_LD_PREFIX=%s", libpath) os.environ['QEMU_LD_PREFIX'] = libpath l.debug("exporting AFL_PATH=%s", afl_path_var) os.environ['AFL_PATH'] = afl_path_var libcompcovpath = os.path.join(afl_dir, "libcompcov.so") libdislocatorpath = os.path.join(afl_dir, "libdislocator.so") afl_preload = " ".join([libcompcovpath, libdislocatorpath]) afl_preload = f"'{afl_preload}'" l.debug("exporting AFL_PRELOAD=%s", afl_preload) os.environ['AFL_PRELOAD'] = afl_preload l.debug("exporting AFL_COMPCOV_LEVEL=2") os.environ[ 'AFL_COMPCOV_LEVEL'] = "2" # CompareCoverage instrumentation # set entrypoint main = self.proj.loader.find_symbol('main') entrypoint = main.rebased_addr if main else self.proj.entry if self.proj.loader.main_object.pic: entrypoint = self.proj.loader.main_object.addr_to_offset( entrypoint) entrypoint += qemu_base #l.debug("exporting QEMU_SET_ENV=%s", f"QEMU_GUEST_BASE={hex(qemu_base)}") os.environ['QEMU_SET_ENV'] = f"QEMU_GUEST_BASE={hex(qemu_base)}" l.debug("exporting AFL_ENTRYPOINT=%s", hex(entrypoint)) os.environ['AFL_ENTRYPOINT'] = hex(entrypoint) #if not self.proj.loader.main_object.pic: #l.debug("exporting AFL_QEMU_PERSISTENT_ADDR=%s", hex(entrypoint)) #os.environ['AFL_QEMU_PERSISTENT_ADDR'] = hex(entrypoint) #os.environ['AFL_QEMU_PERSISTENT_GPR'] = "1" # return the AFL path return shellphish_afl.afl_bin(self.target_os)
def choose_afl(self): os.environ['AFL_PATH'] = shellphish_afl.afl_path_var('multi-cgc') return shellphish_afl.afl_bin('multi-cgc')
def __init__(self, targets, **kwargs): super().__init__(targets[0], **kwargs) self.afl_path = shellphish_afl.afl_bin('multi-cgc') self.afl_path_var = shellphish_afl.afl_path_var('multi-cgc') self.timeout = 1000 * len(targets) self.target_opts = targets[1:]