def do_replay(self): """ This function replays the last Session. This function will later implement also probes to test when the process is crashing """ log.info("Starting the full Replay") with open(self.project.project_dir + "/frida_fuzzer.history") as fp: for line in fp: pkt_file, seed = line.split("|") try: # if libradamsa is not used, we call it as a subprocess and won't cache file contents if not use_libradamsa(): fuzz_pkt = check_output( ["radamsa", "-s", str(seed.strip()), pkt_file]) # kind of arbitrary size limit, probably change this if you're fuzzing something # else than Bluetooth protocols if len(fuzz_pkt) > 672: fuzz_pkt = fuzz_pkt[:672] else: if pkt_file not in self.corpus_cache: input_pkt_data = b'' with open(pkt_file, 'rb') as input_pkt_file: self.corpus_cache[ pkt_file] = input_pkt_file.read() fuzz_pkt = radamsa_mutate(self.corpus_cache[pkt_file], 672, int(seed)) # do any protocol or target specific transformations on the fuzzing payload # if the user did not specify this function it will just return the untouched # payload fuzz_pkt = binascii.unhexlify( self.frida_script.process_payload(fuzz_pkt.hex())) if self.project.debug: open(self.project.debug_dir + "/history", "a").write("file: {} seed: {} \n{}\n".format( pkt_file, seed, fuzz_pkt, )) coverage = self.get_coverage_of_payload( fuzz_pkt, pkt_file, None) log.info("Current iteration: " + time.strftime("%Y-%m-%d %H:%M:%S") + " [seed=%d] [file=%s]" % (int(seed.strip()), pkt_file)) except (frida.TransportError, frida.InvalidOperationError) as e: log.success("doReplay: Got a frida error: " + str(e)) log.success("Current iteration: " + time.strftime("%Y-%m-%d %H:%M:%S") + " [seed=%d] [file=%s]" % (int(seed.strip()), pkt_file)) log.success("Server Crashed! Lets narrow it down") # crash_file = self.crash_dir + time.strftime("/%Y%m%d_%H%M%S_crash") # with open(crash_file, "wb") as f: # f.write(fuzz_pkt) # log.info("Payload is written to " + crash_file) return False if coverage is None: log.warn("No coverage was generated for [%d] %s!" % (seed, pkt_file)) log.info("Sending Empty Package to verify the crashing server") try: coverage = self.get_coverage_of_payload(b'FOOBAR') except (frida.TransportError, frida.InvalidOperationError) as e: log.success("Server Crashed! Lets narrow it down") # TODO # Rabbit Mode here log.warn( "History did not crash the Server! Might be due to some race conditions." ) return False
def do_iteration(self, seed=None, corpus=None): if seed is None: seed = self.project.seed if corpus is None: corpus = self.corpus start_time = time.time() for pkt_file in corpus: # log.update("[seed=%d] " % seed + time.strftime("%Y-%m-%d %H:%M:%S") + " %s" % pkt_file) #log.info(time.strftime("%Y-%m-%d %H:%M:%S") + " %s" % pkt_file) start = ms_time_now() if not use_libradamsa(): fuzz_pkt = check_output(["radamsa", "-s", str(seed), pkt_file]) if len(fuzz_pkt) > 672: fuzz_pkt = fuzz_pkt[:672] else: if pkt_file not in self.corpus_cache: log.finish_update("%s not in cache" % pkt_file) input_pkt_data = b'' with open(pkt_file, 'rb') as input_pkt_file: self.corpus_cache[pkt_file] = input_pkt_file.read() (fuzz_pkt, fuzz_pkt_len) = radamsa_mutate(self.corpus_cache[pkt_file], 672, seed) fuzz_pkt = fuzz_pkt[:fuzz_pkt_len] end = ms_time_now() self.mutation_time += end - start # do any protocol or target specific transformations on the fuzzing payload # if the user did not specify this function it will just return the untouched # payload try: start = ms_time_now() fuzz_bin = self.frida_script.process_payload(fuzz_pkt.hex()) fuzz_pkt = binascii.unhexlify(fuzz_bin) end = ms_time_now() self.process_payload_time += end - start except: pass # Writing History file for replaying open(self.project.project_dir + "/frida_fuzzer.history", "a").write(str(pkt_file) + "|" + str(seed) + "\n") try: start = ms_time_now() coverage = self.get_coverage_of_payload( fuzz_pkt, pkt_file, corpus) end = ms_time_now() self.get_coverage_of_payload_time += end - start except (frida.TransportError, frida.InvalidOperationError) as e: log.warn("doIteration: Got a frida error: " + str(e)) truncated_payload = str(binascii.hexlify(fuzz_pkt))[:25] log.warn("had payload: " + truncated_payload + " [...]") log.info("Current iteration: " + time.strftime("%Y-%m-%d %H:%M:%S") + " [seed=%d] [file=%s]" % (seed, pkt_file)) crash_file = self.project.crash_dir + time.strftime( "/%Y%m%d_%H%M%S_crash") with open(crash_file + "_" + str(self.project.pid), "wb") as f: f.write(fuzz_pkt) log.info("Payload is written to " + crash_file) self.project.crashes += 1 return False if coverage is None: log.warn("No coverage was generated for [%d] %s!" % (seed, pkt_file)) continue if not coverage.issubset(self.accumulated_coverage): # New basic blocks covered! log.info("Found new path: [%d] %s" % (seed, pkt_file)) newfile = open( self.project.corpus_dir + "/" + str(seed) + "_" + pkt_file.split("/")[-1], "wb") newfile.write(fuzz_pkt) newfile.close() cov_file = self.project.coverage_dir + "/" + pkt_file.split( "/")[-1] write_drcov_file(self.modules, coverage, cov_file) write_drcov_file( self.modules, coverage.difference(self.accumulated_coverage), cov_file + "_diff") self.project.last_new_path = seed self.accumulated_coverage = self.accumulated_coverage.union( coverage) self.total_executions += 1 end_time = time.time() speed = len(corpus) / (end_time - start_time) avg_speed = self.total_executions / (end_time - self.start_time) self.current_speed_avg = avg_speed log.finish_update( "[seed=%d] speed=[%3d exec/sec (avg: %d)] coverage=[%d bblocks] corpus=[%d files] " "last new path: [%d] crashes: [%d]" % (seed, speed, avg_speed, len(self.accumulated_coverage), len(corpus), self.project.last_new_path, self.project.crashes)) return True