def __init__(self, config): self.config = config if self.config.argument_values['e']: self.start_time = time.time() if os.path.exists(self.config.argument_values['work_dir'] + "/evaluation/data.csv"): last = "" with open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "rb") as f: first = f.readline() f.seek(-2, 2) while f.read(1) != b"\n": f.seek(-2, 1) last = f.readline() self.time_offset = float(last.split(";")[0]) log_eval("[EVAL]\tTime offset for evaluation file is " + str(self.time_offset)) self.performance_file = open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "a") else: self.time_offset = 0.0 self.performance_file = open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "w") self.__write_plot_file() self.__write_converter_file() self.enabled = True else: self.enabled = False self.state = GlobalState()
def __init__(self, comm, initial=True): self.comm = comm #self.state = MapserverState() self.state = GlobalState() self.hash_set = set() self.preliminary_set = set() self.hash_list = set() self.crash_list = [] self.shadow_map = set() self.last_hash = "" self.post_sync_master_tag = None self.effector_map = [] self.new_findings = 0 self.redqueen_sync = False self.effector_initial_bitmap = None self.effector_sync = False self.performance = 0 self.post_sync = False self.pre_sync = False self.verification_sync = False self.round_counter = 0 self.round_counter_redqueen_sync = 0 self.round_counter_effector_sync = 0 self.round_counter_master_post = 0 self.round_counter_master_pre = 0 self.round_counter_verification_sync = 0 self.config = FuzzerConfiguration() self.enable_graphviz = self.config.argument_values['g'] self.abortion_threshold = self.config.config_values[ 'ABORTION_TRESHOLD'] self.preliminary_mode = False self.ring_buffers = [] for e in range(self.config.argument_values['p']): self.ring_buffers.append(collections.deque(maxlen=30)) if self.config.load_old_state: self.load_data() self.treemap = KaflTree.load_data( enable_graphviz=self.enable_graphviz) else: msg = recv_msg(self.comm.to_mapserver_queue) self.state["pending"] = len(msg.data) self.treemap = KaflTree(msg.data, enable_graphviz=self.enable_graphviz)
def __init__(self, process_num, fancy=True, inline_log=True, redqueen=False): if not fancy: self.HLINE = '-' self.VLINE = '|' self.VLLINE = '+' self.VRLINE = '+' self.LBEDGE = '+' self.RBEDGE = '+' self.HULINE = '+' self.HDLINE = '+' self.LTEDGE = '+' self.RTEDGE = '+' self.HR = '+' self.redqueen = redqueen self.print_findings = False print(self.REALCLRSCR).encode('utf-8') self.process_num = process_num self.state = None self.__loading_screen() self.state = GlobalState() self.target_name = os.path.basename( FuzzerConfiguration().argument_values['executable']) if self.target_name.endswith("_fuzz"): self.target_name = self.target_name[:-5] self.target_name = self.target_name[:15] if len(self.target_name) != 15: self.target_name += ' ' * (15 - len(self.target_name)) self.target_name = self.BOLD + self.target_name + self.ENDC self.size_ok = True self.sighandler_lock = False self.old_signal_handler = signal.getsignal(signal.SIGWINCH) self.blacklist_timer = None self.blacklist_counter = 0 self.blacklist_tcounter = 0 self.inline_log = inline_log if self.inline_log: self.MIN_HEIGHT += 14
class FuzzerUI(): HEADER = '\033[95m' OKBLUE = '\033[94m' OKGREEN = '\033[92m' WARNING = '\033[0;33m' FAIL = '\033[91m' ENDC = '\033[0m' CLRSCR = '\x1b[1;1H' REALCLRSCR = '\x1b[2J' BOLD = '\033[1m' HLINE = unichr(0x2500) VLINE = unichr(0x2502) VLLINE = unichr(0x2524) VRLINE = unichr(0x251c) LBEDGE = unichr(0x2514) RBEDGE = unichr(0x2518) HULINE = unichr(0x2534) HDLINE = unichr(0x252c) LTEDGE = unichr(0x250c) RTEDGE = unichr(0x2510) HR = unichr(0x253c) approx_equal = lambda self, a, b, t: abs(a - b) < t TARGET_FIELD_LEN = 14 INTERFACE_FIELD_LEN = 10 TECHNIQUE_FIELD_LEN = 14 BEST_PERFORMANCE = 1000 BEST_PERFORMANCE_BAR_LEN = 14 TECHNIQUE_BAR_LEN = 15 MIN_WIDTH = 72 MIN_HEIGHT = 27 current_max_performance = 100 def __init__(self, process_num, fancy=True, inline_log=True, redqueen=False): if not fancy: self.HLINE = '-' self.VLINE = '|' self.VLLINE = '+' self.VRLINE = '+' self.LBEDGE = '+' self.RBEDGE = '+' self.HULINE = '+' self.HDLINE = '+' self.LTEDGE = '+' self.RTEDGE = '+' self.HR = '+' self.redqueen = redqueen self.print_findings = False print(self.REALCLRSCR).encode('utf-8') self.process_num = process_num self.state = None self.__loading_screen() self.state = GlobalState() self.target_name = os.path.basename( FuzzerConfiguration().argument_values['executable']) if self.target_name.endswith("_fuzz"): self.target_name = self.target_name[:-5] self.target_name = self.target_name[:15] if len(self.target_name) != 15: self.target_name += ' ' * (15 - len(self.target_name)) self.target_name = self.BOLD + self.target_name + self.ENDC self.size_ok = True self.sighandler_lock = False self.old_signal_handler = signal.getsignal(signal.SIGWINCH) self.blacklist_timer = None self.blacklist_counter = 0 self.blacklist_tcounter = 0 self.inline_log = inline_log if self.inline_log: self.MIN_HEIGHT += 14 def __del__(self): print(self.REALCLRSCR + self.CLRSCR + self.FAIL + \ "[!] Data saved! Bye!" + self.ENDC + "\n").encode('utf-8') #def update_state(self, state): # self.state = state def refresh(self): self.__redraw_ui() def install_sighandler(self): signal.signal(signal.SIGWINCH, self.__sigwinch_handler) def uninstall_signhandler(self): signal.signal(signal.SIGWINCH, self.old_signal_handler) def __hexdump(self, src, length=16, max_length=64): if len(src) < max_length: src += '\x00' * (max_length - len(src)) FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) lines = [] for c in xrange(0, len(src), length): chars = src[c:c + length] hex = ' '.join(["%02x" % ord(x) for x in chars]) printable = ''.join([ "%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars ]) lines.append("%04x %-*s %s\n" % (c, length * 3, hex, printable)) return ''.join(lines) def __sigwinch_handler(self, signum, frame): self.size_ok = self.__win_size() try: print(self.REALCLRSCR).encode('utf-8') self.__redraw_ui() except: pass def __win_size(self): try: rows, columns = subprocess.check_output(['stty', 'size']).split(" ") if int(columns) > self.MIN_WIDTH and int(rows) > self.MIN_HEIGHT: return True else: return False except ValueError: return True def __get_logs(self): tmp = get_rbuf_content() #print(tmp) content = ("\n " + self.VLINE + " " + " " * 65 + "|") * 10 content += ("\n" + 70 * " ") * 4 try: content += "\033[15A" + "\n" for e in tmp: content += "\n " + self.VLINE + " " + e[:65] + ( 65 - len(e[:65]) ) * ' ' + self.VLINE + "\r" + "\033[68C\033[K" + self.VLINE return content + "\n" except: return content + "\n" def __redraw_ui(self): if self.size_ok and not self.state["loading"]: #ui = self.REALCLRSCR ui = "" ui += self.CLRSCR ui += self.__get_logo() ui += self.__get_ui_line1() ui += self.__get_ui_line2() ui += self.__get_ui_line3() ui += self.__get_ui_line4() ui += self.__get_ui_line5() ui += self.__get_ui_line6() ui += self.__get_ui_line7() ui += self.__get_ui_line8() ui += self.__get_ui_line9() ui += self.__get_ui_line10() ui += self.__get_ui_line11() ui += self.__get_ui_line12() ui += self.__get_ui_line13() ui += self.__get_ui_line14() ui += self.__get_ui_line15() if self.inline_log: ui += "\n kAFL Logs:\n " + self.LTEDGE + ( 66 * self.HLINE) + self.RTEDGE ui += self.__get_logs() ui += " " + self.LBEDGE + (66 * self.HLINE) + self.RBEDGE + "\n" print(ui).encode('utf-8') elif self.size_ok and self.state["loading"]: self.__loading_screen() else: print(self.REALCLRSCR + self.CLRSCR + self.FAIL + \ "[!] Please resize your terminal window!" + self.ENDC + "\n").encode('utf-8') def __loading_screen(self): print( self.CLRSCR + self.__get_logo(loading_screen=True) + " " + self.VLINE + " Loading QEMU processes... " + self.VLINE).encode('utf-8') print(" " + self.VRLINE + (66 * self.HLINE) + self.VLLINE).encode('utf-8') if self.state: print(" " + self.VLINE + " Progress:" + self.__get_progress_bar(39, (self.state["slaves_ready"] / (self.process_num * 1.0))) + " (" + self.__get_printable_integer(self.state["slaves_ready"]) + " / " + self.__get_printable_integer(self.process_num) + ") " + self.VLINE + self.ENDC).encode('utf-8') else: print(" " + self.VLINE + " Progress:" + self.__get_progress_bar(39, 0.0) + " (" + self.__get_printable_integer(0) + " / " + self.__get_printable_integer(self.process_num) + ") " + self.VLINE + self.ENDC).encode('utf-8') print(" " + self.LBEDGE + 66 * self.HLINE + self.RBEDGE).encode('utf-8') def __get_logo(self, loading_screen=False): # Slant ascii font :) if not loading_screen: HDLINE = self.HDLINE HR = self.HR HULINE = self.HULINE else: HDLINE = self.HLINE HR = self.HLINE HULINE = self.HLINE if not self.state or loading_screen: new_findings = " " imports = " " else: imports = self.VLINE + " Imports: " + self.__get_printable_integer( self.state["imports"]) + " " + self.VLINE num = self.state["preliminary"] if num != 0: self.print_findings = True new_findings = " New Findings: " + self.__get_printable_integer( num, color=(self.WARNING + self.BOLD)) + " " else: new_findings = " New Findings: " + self.__get_printable_integer( num, color=(self.BOLD)) + " " #if self.print_findings: #else: # new_findings = " " template = " __ __ ___ ________ \n" + \ " / /_____ _________ ___ / / / | / ____/ / \n" + \ " / //_/ _ \/ ___/ __ \/ _ \/ / / /| | / /_ / / \n" + \ " / ,< / __/ / / / / / __/ / / ___ |/ __/ / /___ \n" + \ " /_/|_|\___/_/ /_/ /_/\___/_/ /_/ |_/_/ /_____/ \n" + \ " " + self.LTEDGE + (25 * self.HLINE) + HDLINE + (23 * self.HLINE) + HDLINE + (16 * self.HLINE)+ self.RTEDGE + " \n" template += " " + self.VLINE + new_findings + \ imports + " " + \ " " + self.__get_printable_integer(self.process_num)[1:] + " Processes " + self.VLINE + " \n" + \ " " + self.VRLINE + (25 * self.HLINE) + HR + (23 * self.HLINE) + HULINE + (16 * self.HLINE) + self.VLLINE + "\n" return template def __get_ui_line1(self): template = template = " " + self.VLINE + " Runtime: " + self.__get_diff_time(self.state["runtime"]) + \ " " + self.VLINE + " Performance: <PERFORMANCE_BAR> <PERFORMANCE_VALUE> t/s " + self.VLINE + "\n" if len(self.state["interface_str"]) > self.INTERFACE_FIELD_LEN: interface = self.state["interface_str"][:( self.INTERFACE_FIELD_LEN - 1)] + "." else: interface = self.state["interface_str"] interface = ( (self.INTERFACE_FIELD_LEN - len(interface)) * ' ') + interface self.state["performance"] = self.state.get_performance() if self.state["performance"] > self.state.get_max_performance(): #self.current_max_performance = self.state.performance performance_float = 1.0 #if self.state.performance >= self.BEST_PERFORMANCE: # performance_float = 1.0 elif self.state.get_max_performance() == 0: performance_float = 0.0 else: performance_float = self.state["performance"] / ( self.state.get_max_performance() * 1.0) #performance_float = self.state["performance"] / (self.BEST_PERFORMANCE * 1.0) if self.state["technique"] == "PRE-SAMPLING" or self.state[ "technique"] == "POST-SAMPLING" or self.state[ "technique"] == "BENCHMARKING": performance_bar = self.__get_progress_bar( self.BEST_PERFORMANCE_BAR_LEN, performance_float) return template.replace("<INTERFACE>", interface) \ .replace("<PERFORMANCE_BAR>", performance_bar) \ .replace("<PERFORMANCE_VALUE>", " - ") else: performance_bar = self.__get_progress_bar( self.BEST_PERFORMANCE_BAR_LEN, performance_float) performance_value = self.__get_printable_integer( self.state["performance"]) return template.replace("<INTERFACE>", interface) \ .replace("<PERFORMANCE_BAR>", performance_bar) \ .replace("<PERFORMANCE_VALUE>", performance_value) def __get_ui_line2(self): template = " " + self.VLINE + " Last Path: " + self.__get_diff_time(self.state["last_hash_time"]) + \ " " + self.VRLINE + 40 * self.HLINE + "" + self.VLLINE + "\n" if len(self.state["target_str"]) > self.TARGET_FIELD_LEN: target = self.state["target_str"][:self.TARGET_FIELD_LEN - 1] + "." else: target = self.state["target_str"] target = ((self.TARGET_FIELD_LEN - len(target)) * ' ') + target return template.replace("<TARGET>", target) def __get_ui_line3(self): if self.redqueen: if self.state["progress_requeen_amount"] == 0: requeen_rate = 0.0 else: try: requeen_rate = float( self.state["progress_redqueen"]) / float( self.state["progress_requeen_amount"]) except: requeen_rate = 0.0 if self.approx_equal(1.0, requeen_rate, 0.001): use_color = False requeen_rate = 1.0 else: use_color = True bits = str(self.__get_printable_float( self.state["ratio_bits"])).replace("%", "b") cov = self.__get_printable_float(self.state["ratio_coverage"]) if self.state["ratio_coverage"] > 50.00: cov = self.FAIL + self.BOLD + cov + self.ENDC elif self.state["ratio_coverage"] > 10.00: cov = self.FAIL + self.WARNING + cov + self.ENDC template = " " + self.VLINE + " Bitmap: " + bits + "/ " + cov + \ " " + self.VLINE + " Redqueen: " + \ self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, requeen_rate, color=use_color, specific_char='*', technique_color=True) + \ " " + self.__get_printable_integer(self.state["progress_requeen_amount"]) + " " + self.VLINE + " \n" else: template = " " + self.VLINE + " Bitmap: " + str(self.__get_printable_float(self.state["ratio_bits"])).replace("%", "b") + "/ " + \ self.__get_printable_float(self.state["ratio_coverage"]) + \ " " + self.VLINE + " Fuzzing Technique Progress " + self.VLINE + "\n" return template def __get_ui_line4(self): if self.state["progress_bitflip_amount"] == 0: bitflip_rate = 0.0 else: bitflip_rate = float(self.state["progress_bitflip"]) / float( self.state["progress_bitflip_amount"]) if self.approx_equal(1.0, bitflip_rate, 0.001): use_color = False else: use_color = True template = " " + self.VLINE + " Blacklisted: " + self.__get_printable_integer(self.blacklist_tcounter) + "/" + self.__get_printable_integer(self.blacklist_counter) + \ " " + self.VLINE + " Bitflipping: " + \ self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, bitflip_rate, color=use_color, specific_char='*', technique_color=True) + \ " " + self.__get_printable_integer(self.state["progress_bitflip_amount"]) + " " + self.VLINE + " \n" return template def __get_ui_line5(self): if self.state["progress_arithmetic_amount"] == 0: arithmetic_rate = 0.0 else: try: arithmetic_rate = float( self.state["progress_arithmetic"]) / float( self.state["progress_arithmetic_amount"]) except: arithmetic_rate = 0.0 if self.approx_equal(1.0, arithmetic_rate, 0.001): use_color = False else: use_color = True template = " " + self.VRLINE + (25 * self.HLINE) + self.VLLINE + " Arithmetic: " + \ self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, arithmetic_rate, color=use_color, specific_char='*', technique_color=True) \ + " " + self.__get_printable_integer(self.state["progress_arithmetic_amount"]) +" " + self.VLINE + "\n" return template def __get_ui_line6(self): if self.state["progress_interesting_amount"] == 0: interesting_rate = 0.0 else: interesting_rate = float( self.state["progress_interesting"]) / float( self.state["progress_interesting_amount"]) if self.approx_equal(1.0, interesting_rate, 0.001): use_color = False else: use_color = True if self.state["cycles"] != 0: cycles = self.WARNING + self.BOLD + self.__get_printable_integer( self.state["cycles"]) + self.ENDC else: cycles = self.__get_printable_integer(self.state["cycles"]) template = " " + self.VLINE + " Cycles: " + cycles + \ " " + self.VLINE + " Interesting: " + \ self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, interesting_rate, color=use_color, specific_char='*', technique_color=True) + \ " " + self.__get_printable_integer(self.state["progress_interesting_amount"]) + " " + self.VLINE + "\n" return template def __get_ui_line7(self): if self.state["progress_havoc_amount"] == 0: havoc_rate = 0.0 else: havoc_rate = float(self.state["progress_havoc"]) / float( self.state["progress_havoc_amount"]) if self.approx_equal(1.0, havoc_rate, 0.001): use_color = False else: use_color = True template = " " + self.VLINE + " Level: " + self.__get_printable_integer(self.state["level"]) + "/" + self.__get_printable_integer(self.state["max_level"]) \ + " " + self.VLINE + " Havoc: " + \ self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, havoc_rate, color=use_color, specific_char='*', technique_color=True) \ + " " + self.__get_printable_integer(self.state["progress_havoc_amount"]) + " " + self.VLINE + "\n" return template def __get_ui_line8(self): if self.state["progress_specific_amount"] == 0: specific_rate = 0.0 else: try: specific_rate = float(self.state["progress_specific"]) / float( self.state["progress_specific_amount"]) except: specific_rate = 0.0 if self.approx_equal(1.0, specific_rate, 0.001): use_color = False else: use_color = True tmp_fav_ratio = 0.0 if self.state["hashes"] != 0: tmp_fav_ratio = 100.0 * (float(self.state["favorites"]) / float(self.state["hashes"])) template = " " + self.VLINE + " Favs: " + self.__get_printable_integer(self.state["favorites"]) + "/" + \ self.__get_printable_integer(self.state["hashes"]) + " " + self.__get_printable_float(tmp_fav_ratio, brackets=True) +\ " " + self.VLINE + " Radamsa: " + self.__get_progress_bar(self.TECHNIQUE_BAR_LEN, specific_rate, color=use_color, specific_char='*', technique_color=True) + \ " " + self.__get_printable_integer(self.state["progress_specific_amount"]) + " " + self.VLINE + "\n" return template def __get_ui_line9(self): fav_pending = int(self.state["fav_pending"]) path_pending = int(self.state["path_pending"]) color_a = "" color_b = "" if self.print_findings and fav_pending == 0: color_a = (self.WARNING + self.BOLD) if self.print_findings and path_pending == 0: color_b = (self.WARNING + self.BOLD) template = " " + self.VLINE + " Pending: " +\ self.__get_printable_integer(fav_pending, color=color_a) + "/" +\ self.__get_printable_integer(path_pending, color=color_b) + \ " " + self.VRLINE + (23 * self.HLINE) + self.HDLINE + (16 * self.HLINE) + self.VLLINE + "\n" return template def __get_ui_line10(self): cpu_usage = self.__get_cpu_usage() fav_pending = int(self.state["fav_pending"]) path_pending = int(self.state["path_pending"]) fav_skipped = int(self.state["fav_unfinished"]) path_skipped = int(self.state["path_unfinished"]) color_a = "" color_b = "" if self.print_findings and fav_pending == 0 and fav_skipped == 0: color_a = (self.WARNING + self.BOLD) if self.print_findings and path_pending == 0 and path_skipped == 0: color_b = (self.WARNING + self.BOLD) if self.state["crash"] != 0: panics = self.__get_printable_integer(self.state["crash"], color=(self.FAIL + self.BOLD)) + " " + \ self.__get_printable_integer(self.state["crash_unique"], brackets=True, color=(self.FAIL + self.BOLD)) else: panics = self.__get_printable_integer( 0) + " " + self.__get_printable_integer(0, brackets=True) template = " " + self.VLINE + " Skipped: " + self.__get_printable_integer(fav_skipped, color=color_a) + "/" + \ self.__get_printable_integer(path_skipped, color=color_b) + \ " " + self.VLINE + " Panic: " + panics + \ " " + self.VLINE + " CPU: " + self.__get_printable_float(cpu_usage * 100.0, colored=True) + " " + self.VLINE + "\n" return template def __get_ui_line11(self): mem_usage = self.__get_mem_usage() if self.state["kasan_unique"] != 0: kasan = self.__get_printable_integer(self.state["kasan"], color=(self.FAIL + self.BOLD)) + " " + \ self.__get_printable_integer(self.state["kasan_unique"], brackets=True, color=(self.FAIL + self.BOLD)) else: kasan = self.__get_printable_integer( 0) + " " + self.__get_printable_integer(0, brackets=True) template = " " + self.VLINE + " Payload-Size: " + self.__get_printable_integer(self.state["payload_size"]) + \ "B " + self.VLINE + " KASan: " + kasan + " " + self.VLINE + " RAM: " + \ " " + self.__get_printable_float(mem_usage * 100.0, colored=True) + " " + self.VLINE + "\n" return template def __get_ui_line12(self): if self.state["timeout_unique"] != 0: reloads = self.__get_printable_integer(self.state["timeout"], color=(self.WARNING + self.BOLD)) + " " + \ self.__get_printable_integer(self.state["timeout_unique"], brackets=True, color=(self.WARNING + self.BOLD)) else: reloads = self.__get_printable_integer( 0) + " " + self.__get_printable_integer(0, brackets=True) if len(self.state["technique"]) > self.TECHNIQUE_FIELD_LEN: technique = self.state["technique"][:(self.TECHNIQUE_FIELD_LEN - 1)] + "." else: technique = self.state["technique"] technique = ( (self.TECHNIQUE_FIELD_LEN - len(technique)) * ' ') + technique template = " " + self.VLINE + " Total: " + self.__get_printable_integer(self.state["total"]) + \ " " + self.VLINE + " Timeout: " + reloads + \ " " + self.VLINE + " " + technique + " " + self.VLINE + "\n" return template def __get_ui_line13(self): return " " + self.VRLINE + (25 * self.HLINE) + self.HR + ( 23 * self.HLINE) + self.HR + (16 * self.HLINE) + self.VLLINE + "\n" def __get_ui_line14(self): return " " + self.VLINE + " Target: " + self.target_name + " " + self.VLINE + "\n" def __get_ui_line15(self): return " " + self.LBEDGE + (25 * self.HLINE) + self.RBEDGE + "\n" \ + "\n" + (47 * ' ') + "\n" + "\n" + self.__hexdump(self.state["payload"][0:0x60], max_length=0x60) + "\n" def __get_printable_integer(self, value, brackets=False, color=""): if value >= 1000000000000: ret = str(value / 1000000000000.0)[:3] if ret[len(ret) - 2] == '.': ret = ret[:-2] + 'T' elif value >= 1000000000: ret = str(value / 1000000000.0)[:3] + "G" if ret[len(ret) - 2] == '.': ret = ret[:-2] + 'G' elif value >= 1000000: ret = str(value / 1000000.0)[:3] + "M" if ret[len(ret) - 2] == '.': ret = ret[:-2] + 'M' elif value >= 1000: ret = str(value / 1000.0)[:3] + "K" if ret[len(ret) - 2] == '.': ret = ret[:-2] + 'K' else: ret = str(value) if brackets: return ((4 - len(ret)) * ' ') + "(" + color + ret + self.ENDC + ")" return ((4 - len(ret)) * ' ') + color + ret + self.ENDC def __get_printable_payload_size(self, value): if value >= 1 << 40: ret = str(value >> 40) + "T" elif value >= 1 << 30: ret = str(value >> 30) + "G" elif value >= 1 << 20: ret = str(value >> 20) + "M" elif value >= 1 << 10: ret = str(value >> 10) + "K" else: ret = str(value) + ' ' return ((4 - len(ret)) * ' ') + ret def __get_progress_bar(self, char_num, percent, specific_char='|', color=True, negativ=False, technique_color=False): progress_bar = "" progress_chars = int(char_num * percent) if progress_chars > char_num: progress_chars = char_num elif progress_chars == 0: if not self.approx_equal(percent, 0.0, 0.001): progress_chars = 1 progress_bar += progress_chars * specific_char progress_bar += (char_num - progress_chars) * ' ' if color: if technique_color: color_code = self.WARNING else: if percent < 0.25: if negativ: color_code = self.OKGREEN else: color_code = self.FAIL elif percent < 0.50: color_code = self.WARNING else: if negativ: color_code = self.FAIL else: color_code = self.OKGREEN else: color_code = self.ENDC return "[" + color_code + progress_bar + self.ENDC + "]" def __get_diff_time(self, time_b): diff = time.gmtime(time.time() - time_b) days = int(time.strftime('%j', diff)) - 1 days = ((3 - len(str(days))) * '0') + str(days) return days + time.strftime(':%H:%M:%S', diff) def __get_cpu_usage(self): return (100.0 - psutil.cpu_times_percent(interval=0.1).idle) / 100.0 def __get_mem_usage(self): return psutil.virtual_memory().percent / 100.0 def __get_printable_float(self, float_value, brackets=False, colored=False): color_value = "" if colored: if float_value <= 25.0: color_value = self.OKGREEN elif 25.0 < float_value <= 75.0: color_value = self.WARNING else: color_value = self.FAIL if float_value > 100.0: float_value = 100.0 if self.approx_equal(100.0, float_value, 0.01): if brackets: return " (" + color_value + "100%" + self.ENDC + ")" return color_value + " 100%" + self.ENDC else: str_value = "%0.1f" % float_value if len(str_value) < 4: if brackets: return "(" + color_value + "0" + str_value + "%" + self.ENDC + ")" return color_value + "0" + str_value + "%" + self.ENDC if brackets: return "(" + color_value + str_value + "%" + self.ENDC + ")" return color_value + str_value + "%" + self.ENDC
class Evaluation: def __init__(self, config): self.config = config if self.config.argument_values['e']: self.start_time = time.time() if os.path.exists(self.config.argument_values['work_dir'] + "/evaluation/data.csv"): last = "" with open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "rb") as f: first = f.readline() f.seek(-2, 2) while f.read(1) != b"\n": f.seek(-2, 1) last = f.readline() self.time_offset = float(last.split(";")[0]) log_eval("[EVAL]\tTime offset for evaluation file is " + str(self.time_offset)) self.performance_file = open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "a") else: self.time_offset = 0.0 self.performance_file = open( self.config.argument_values['work_dir'] + "/evaluation/data.csv", "w") self.__write_plot_file() self.__write_converter_file() self.enabled = True else: self.enabled = False self.state = GlobalState() def __del__(self): self.performance_file.close() def __write_converter_file(self): script = "require 'csv'\n" +\ "last_time = nil\n" +\ "first_time = nil\n" +\ "acc = nil\n" +\ "count = 0\n" +\ "CSV.open('converted.csv', 'wb') do |csv|\n" +\ " CSV.foreach('data.csv',col_sep: \";\") do |row|\n" +\ " time,*data = *row\n" +\ " time = time.to_i\n" +\ " data = data.map(&:to_i)\n" +\ " first_time = time unless first_time\n" +\ " acc ||= data.map{0}\n" +\ " acc.each_index{|i| acc[i]+=data[i]}\n" +\ " count += 1\n" +\ " if !last_time || time - last_time > 2\n" +\ " csv << [time-first_time, *(acc.map{|v| v/count.to_f})]\n" +\ " last_time = time\n" +\ " acc = acc.map{0}\n" +\ " count = 0\n" +\ " end\n" +\ " end\n" +\ "end\n" f = open( self.config.argument_values['work_dir'] + "/evaluation/convert.rb", "w") f.write(script) f.close() def __write_plot_file(self): script = "reset\n" +\ "system(\"ruby convert.rb\")\n" +\ "set terminal wxt size 1200,800\n" +\ "set multiplot\n" +\ "set grid xtics linetype 0 linecolor rgb '#d0d0d0'\n" +\ "set grid ytics linetype 0 linecolor rgb '#d0d0d0'\n" +\ "set border linecolor rgb '#50c0f0'\n" +\ "set tics textcolor rgb '#000000'\n" +\ "set key outside\n" +\ "set size 1, 0.25\n" +\ "set datafile separator ','\n" +\ "set xdata time\n" +\ "set format x \"Day %j\\n %H:%M\"\n" +\ "set timefmt '%s'\n" +\ "set style line 2\n" +\ "set style data line\n" +\ "set origin 0.0,0.75\n" +\ "plot 'converted.csv' using 1:2 title 'Performance' with line linecolor rgb '#0090ff' linewidth 2 smooth bezier, \\\n" +\ "'' using 1:2 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder,\n" +\ "set origin 0.0,0.5\n" +\ "plot 'converted.csv' \\\n" +\ " using 1:4 title 'Pending' with lines linecolor rgb '#404040' linewidth 3, \\\n" +\ "'' using 1:14 title 'Pending Favs' with lines linecolor rgb '#808080' linewidth 3, \\\n" +\ "'' using 1:3 title 'Findings' with lines linecolor rgb '#C0C0C0' linewidth 2, \\\n" +\ "'' using 1:5 title 'Favorites' with lines linecolor rgb '#FF0000' linewidth 2, \\\n" +\ "'' using 1:3 with filledcurve x1 title '' linecolor rgb '#C0C0C0' fillstyle transparent solid 0.3 noborder, \\\n" +\ "'' using 1:4 with filledcurve x1 title '' linecolor rgb '#808080' fillstyle transparent solid 0.5 noborder, \\\n" +\ "'' using 1:14 with filledcurve x1 title '' linecolor rgb '#404040' fillstyle transparent solid 0.5 noborder\n" +\ "set origin 0.0,0.25\n" +\ "plot 'converted.csv' \\\n" +\ " using 1:7 title 'Unique Panics' with lines, \\\n" +\ "'' using 1:9 title 'KASan Unique' with lines, \\\n" +\ "'' using 1:11 title 'Timeout Unique' with lines\n" +\ "set origin 0.0,0.0\n" +\ "plot 'converted.csv' using 0:15 title 'Blacklisted BB' with lines\n" +\ "pause 2\n" +\ "unset multiplot\n" +\ "reread\n" f = open( self.config.argument_values['work_dir'] + "/evaluation/plot.gnu", "w") f.write(script) f.close() def write_data(self, blacklisted): # Format: Time; Performance; Paths, Pending; Favorites; Panics; Panics Unique; Kasan; Kasan Unique; Timeout; Timeout Unique; Level; Cycles; Total if self.enabled: self.performance_file.write(\ str(((time.time()-self.start_time)+self.time_offset)) + ";" + \ str(self.state.get_performance()) + ";" + \ str(self.state["hashes"]) + ";" + \ str(self.state["path_pending"]) + ";" + \ str(self.state["favorites"]) + ";" + \ str(self.state["crash"]) + ";" + \ str(self.state["crash_unique"]) + ";" + \ str(self.state["kasan"]) + ";" + \ str(self.state["kasan_unique"]) + ";" + \ str(self.state["timeout"]) + ";" + \ str(self.state["timeout_unique"]) + ";" +\ str(self.state["level"]) + ";" +\ str(self.state["cycles"]) + ";" +\ str(self.state["fav_pending"]) + ";" +\ str(blacklisted)+ \ str(self.state["total"]) + ";" +\ "\n") self.performance_file.flush()
def __write_eval_results(self): with open(FuzzerConfiguration().argument_values['work_dir']+"/evaluation/findings.csv",'ab') as f: f.write("%s\n"%json.dumps([time.time()-GlobalState().values["inittime"], self.__get_filename()] ))
class MapserverProcess: def __init__(self, comm, initial=True): self.comm = comm #self.state = MapserverState() self.state = GlobalState() self.hash_set = set() self.preliminary_set = set() self.hash_list = set() self.crash_list = [] self.shadow_map = set() self.last_hash = "" self.post_sync_master_tag = None self.effector_map = [] self.new_findings = 0 self.redqueen_sync = False self.effector_initial_bitmap = None self.effector_sync = False self.performance = 0 self.post_sync = False self.pre_sync = False self.verification_sync = False self.round_counter = 0 self.round_counter_redqueen_sync = 0 self.round_counter_effector_sync = 0 self.round_counter_master_post = 0 self.round_counter_master_pre = 0 self.round_counter_verification_sync = 0 self.config = FuzzerConfiguration() self.enable_graphviz = self.config.argument_values['g'] self.abortion_threshold = self.config.config_values[ 'ABORTION_TRESHOLD'] self.preliminary_mode = False self.ring_buffers = [] for e in range(self.config.argument_values['p']): self.ring_buffers.append(collections.deque(maxlen=30)) if self.config.load_old_state: self.load_data() self.treemap = KaflTree.load_data( enable_graphviz=self.enable_graphviz) else: msg = recv_msg(self.comm.to_mapserver_queue) self.state["pending"] = len(msg.data) self.treemap = KaflTree(msg.data, enable_graphviz=self.enable_graphviz) def __save_ring_buffer(self, slave_id, target): if "block" in dir(lz4): data = [] for payload in self.ring_buffers[slave_id]: data.append(base64.b64encode(payload)) with open(target, 'w') as outfile: outfile.write(lz4.block.compress(json.dumps(data))) def __check_hash(self, new_hash, bitmap, payload, crash, timeout, kasan, slave_id, reloaded, performance, qid, pos, methode): self.ring_buffers[slave_id].append(str(payload)) if self.preliminary_mode: hash_was_new = True else: hash_was_new = False if new_hash != self.last_hash: if len(self.hash_list) == 0: hash_was_new = True if new_hash not in self.hash_list and new_hash not in self.shadow_map: hash_was_new = True if crash or kasan or timeout: if crash: state_str = "crash" node_type = KaflNodeType.crash elif kasan: state_str = "kasan" node_type = KaflNodeType.kasan elif timeout: state_str = "timeout" node_type = KaflNodeType.timeout if self.treemap.append(payload, bitmap, methode, node_type=node_type): if not self.preliminary_mode: log_mapserver("Unique " + state_str + " submited by slave #" + str(slave_id) + " ...") self.__save_ring_buffer( slave_id, self.config.argument_values['work_dir'] + "/rbuf/" + state_str + "_" + str(self.state[state_str + "_unique"]) + ".rbuf") self.state[state_str] += 1 self.state[state_str + "_unique"] += 1 else: self.state["preliminary"] += 1 log_mapserver("Unique " + state_str + " submited by slave #" + str(slave_id) + " [preliminary]...") else: if not self.preliminary_mode: self.state[state_str] += 1 path = FuzzerConfiguration().argument_values[ 'work_dir'] + "/findings/non_uniq/" + state_str + "_non_uniq_" + str( self.state[state_str]) with open(path, "w") as f: f.write(payload) with open( FuzzerConfiguration().argument_values['work_dir'] + "/evaluation/findings.csv", 'ab') as f: f.write("%s\n" % json.dumps([ time.time() - GlobalState().values["inittime"], path ])) elif hash_was_new: if self.treemap.append(payload, bitmap, methode, performance=performance): if not self.preliminary_mode: if methode.get_type() == METHODE_IMPORT: self.state["imports"] += 1 self.hash_list.add(new_hash) self.new_findings += 1 self.state["last_hash_time"] = time.time() self.__update_state() else: self.state["preliminary"] += 1 else: if not self.preliminary_mode: self.shadow_map.add(new_hash) if reloaded: self.ring_buffers[slave_id].clear() def __update_state(self): self.state["ratio_coverage"], self.state[ "ratio_bits"] = self.treemap.get_bitmap_values() self.state["cycles"] = self.treemap.cycles self.state["hashes"] = self.treemap.paths self.state[ "path_pending"] = self.treemap.paths - self.treemap.paths_finished - self.treemap.paths_in_progress self.state["path_unfinished"] = self.treemap.paths_in_progress self.state["favorites"] = self.treemap.favorites self.state[ "fav_pending"] = self.treemap.favorites - self.treemap.favorites_finished - self.treemap.favorites_in_progress self.state["fav_unfinished"] = self.treemap.favorites_in_progress def __post_sync_handler(self): if self.round_counter_master_post == self.round_counter: self.treemap.resort_favs() if self.post_sync_master_tag == KAFL_TAG_NXT_UNFIN: data = self.treemap.get_next(self.performance, finished=False) else: data = self.treemap.get_next(self.performance, finished=True) self.__update_state() self.state["level"] = data.level + 1 if self.state["level"] > self.state["max_level"]: self.state["max_level"] = self.state["level"] state = data.node_state if state == KaflNodeState.in_progress or state == KaflNodeState.finished: send_msg(KAFL_TAG_NXT_UNFIN, data, self.comm.to_master_from_mapserver_queue) else: send_msg(KAFL_TAG_NXT_FIN, data, self.comm.to_master_from_mapserver_queue) self.round_counter = 0 return True return False def __pre_sync_handler(self): log_mapserver("__pre_sync_handler: " + str(self.round_counter_master_pre) + " / " + str(self.round_counter)) if (self.round_counter_master_pre == self.round_counter ): # or self.abortion_alredy_sent: send_msg(KAFL_TAG_UNTOUCHED_NODES, self.treemap.get_num_of_untouched_nodes(), self.comm.to_master_from_mapserver_queue) return True return False def __effector_sync_handler(self): if (self.round_counter_effector_sync == self.round_counter): send_msg(KAFL_TAG_GET_EFFECTOR, self.effector_map, self.comm.to_master_from_mapserver_queue) return True return False def __redqueen_sync_handler(self): if (self.round_counter_redqueen_sync == self.round_counter): send_msg(KAFL_TAG_REDQUEEN_SYNC, 0, self.comm.to_master_from_mapserver_queue) return True return False def __verification_sync_handler(self): log_mapserver("__verificatiom_sync_handler: " + str(self.round_counter_verification_sync) + " / " + str(self.round_counter)) if (self.round_counter_verification_sync == self.round_counter): send_msg(KAFL_TAG_REQ_VERIFY_SYNC, 0, self.comm.to_master_from_mapserver_queue) return True return False def __result_tag_handler(self, request): self.comm.slave_locks_B[request.source].acquire() results = request.data payloads = [] bitmaps = [] payload_shm = self.comm.get_mapserver_payload_shm(request.source) bitmap_shm = self.comm.get_bitmap_shm(request.source) bitmap_hashes = [] for result in results: if result.new_bits and result.bitmap_hash and result.bitmap_hash: bitmap_shm.seek(result.pos * self.comm.get_bitmap_shm_size()) payload_shm.seek(result.pos * self.comm.get_mapserver_payload_shm_size()) length = payload_shm.read(4) data_len = (ord(length[3]) << 24) + (ord(length[2]) << 16) + ( ord(length[1]) << 8) + (ord(length[0])) payloads.append(payload_shm.read(data_len)) bitmaps.append(bitmap_shm.read( self.comm.get_bitmap_shm_size())) bitmap_hashes.append(result.bitmap_hash) else: payloads.append(None) bitmaps.append(None) bitmap_hashes.append(None) self.comm.slave_locks_A[request.source].release() for i in range(len(results)): if bitmap_hashes[i] is not None and results[i].new_bits: self.__check_hash(bitmap_hashes[i], bitmaps[i], payloads[i], results[i].crash, results[i].timeout, results[i].kasan, results[i].slave_id, results[i].reloaded, results[i].performance, results[i].qid, results[i].pos, results[i].methode) self.last_hash = bitmap_hashes[i] self.round_counter += 1 if self.effector_initial_bitmap: if self.effector_initial_bitmap != bitmap_hashes[i]: for j in results[i].affected_bytes: log_mapserver("affected_bytes: " + str(j)) if not self.effector_map[j]: self.effector_map[j] = True else: self.round_counter += 1 def __next_tag_handler(self, request): self.post_sync_master_tag = request.tag self.post_sync = True self.round_counter_master_post = request.data[0] self.performance = request.data[1] log_mapserver("Performance: " + str(self.performance)) def __pre_abort_tag_handler(self, request): self.round_counter_master_pre = request.data self.pre_sync = True def __post_abort_tag_handler(self, request): self.round_counter_master_post = self.round_counter_master_pre + request.data self.pre_sync = False def __untouched_tag_handler(self, request): self.round_counter_master_pre = request.data self.pre_sync = True def __req_effector_tag_handler(self, request): log_mapserver("New Effector Map (" + str(len(request.data)) + ")") self.effector_initial_bitmap = mmh3.hash64(request.data) for i in range(self.config.config_values['PAYLOAD_SHM_SIZE']): self.effector_map.append(False) def __get_effector_tag_handler(self, request): self.round_counter_effector_sync = request.data self.effector_sync = True def __fin_redqueen_tag_handler(self, request): self.round_counter_redqueen_sync = request.data self.redqueen_sync = True def __fin_verification_tag_handler(self, request): log_mapserver("__fin_verification_tag_handler: " + str(request.data)) self.round_counter_verification_sync = request.data self.verification_sync = True def __fin_preliminary_tag_handler(self, request): # Todo flush shadow map if self.preliminary_mode != request.data: self.preliminary_mode = request.data if self.preliminary_mode: self.state["preliminary"] = 0 self.last_hash = "" log_mapserver("Preliminary Mode: " + str(self.preliminary_mode)) send_msg(KAFL_TAG_REQ_PRELIMINARY, self.treemap.toggle_preliminary_mode(request.data), self.comm.to_master_from_mapserver_queue) def __sync_handler(self): if self.redqueen_sync: if self.__redqueen_sync_handler(): self.redqueen_sync = False self.round_counter = 0 if self.effector_sync: if self.__effector_sync_handler(): self.effector_sync = False self.effector_initial_bitmap = None self.effector_map = [] if self.verification_sync: if self.__verification_sync_handler(): self.verification_sync = False if self.pre_sync: if self.__pre_sync_handler(): self.pre_sync = False self.round_counter_master_pre = 0 log_mapserver("ShadowMap Size: " + str(len(self.shadow_map))) if self.post_sync: if self.__post_sync_handler(): self.post_sync = False self.round_counter_master_post = 0 self.round_counter = 0 def loop(self): while True: self.__sync_handler() request = recv_msg(self.comm.to_mapserver_queue) if request.tag == KAFL_TAG_RESULT: self.__result_tag_handler(request) elif request.tag == KAFL_TAG_NXT_FIN or request.tag == KAFL_TAG_NXT_UNFIN: self.__next_tag_handler(request) elif request.tag == KAFL_TAG_UNTOUCHED_NODES: self.__untouched_tag_handler(request) elif request.tag == KAFL_TAG_REQ_EFFECTOR: self.__req_effector_tag_handler(request) elif request.tag == KAFL_TAG_GET_EFFECTOR: self.__get_effector_tag_handler(request) elif request.tag == KAFL_TAG_REDQUEEN_SYNC: self.__fin_redqueen_tag_handler(request) elif request.tag == KAFL_TAG_REQ_PRELIMINARY: self.__fin_preliminary_tag_handler(request) elif request.tag == KAFL_TAG_REQ_VERIFY_SYNC: self.__fin_verification_tag_handler(request) def save_data(self): return """ Method to store an entire master state to JSON file... """ dump = {} for key, value in self.__dict__.iteritems(): if key == "state": dump[key] = self.state.save_data() elif key == "enable_graphviz" or key == "last_hash": dump[key] = self.enable_graphviz elif key == "hash_list" or key == "shadow_map": tmp = [] for e in value: tmp.append(e) dump[key] = tmp with open(self.config.argument_values['work_dir'] + "/mapserver.json", 'w') as outfile: json.dump(dump, outfile, default=json_dumper, cls=SetEncoder, indent=4) def load_data(self): """ Method to load an entire master state from JSON file... """ with open( FuzzerConfiguration().argument_values['work_dir'] + "/mapserver.json", 'r') as infile: dump = json.load(infile) for key, value in dump.iteritems(): if key == "hash_list" or key == "shadow_map": tmp = set() for e in value: tmp.add(tuple(e)) setattr(self, key, tmp) elif key == "state": tmp = MapserverState() tmp.load_data(value) setattr(self, key, tmp) else: setattr(self, key, value)
def __check_hash(self, new_hash, bitmap, payload, crash, timeout, kasan, slave_id, reloaded, performance, qid, pos, methode): self.ring_buffers[slave_id].append(str(payload)) if self.preliminary_mode: hash_was_new = True else: hash_was_new = False if new_hash != self.last_hash: if len(self.hash_list) == 0: hash_was_new = True if new_hash not in self.hash_list and new_hash not in self.shadow_map: hash_was_new = True if crash or kasan or timeout: if crash: state_str = "crash" node_type = KaflNodeType.crash elif kasan: state_str = "kasan" node_type = KaflNodeType.kasan elif timeout: state_str = "timeout" node_type = KaflNodeType.timeout if self.treemap.append(payload, bitmap, methode, node_type=node_type): if not self.preliminary_mode: log_mapserver("Unique " + state_str + " submited by slave #" + str(slave_id) + " ...") self.__save_ring_buffer( slave_id, self.config.argument_values['work_dir'] + "/rbuf/" + state_str + "_" + str(self.state[state_str + "_unique"]) + ".rbuf") self.state[state_str] += 1 self.state[state_str + "_unique"] += 1 else: self.state["preliminary"] += 1 log_mapserver("Unique " + state_str + " submited by slave #" + str(slave_id) + " [preliminary]...") else: if not self.preliminary_mode: self.state[state_str] += 1 path = FuzzerConfiguration().argument_values[ 'work_dir'] + "/findings/non_uniq/" + state_str + "_non_uniq_" + str( self.state[state_str]) with open(path, "w") as f: f.write(payload) with open( FuzzerConfiguration().argument_values['work_dir'] + "/evaluation/findings.csv", 'ab') as f: f.write("%s\n" % json.dumps([ time.time() - GlobalState().values["inittime"], path ])) elif hash_was_new: if self.treemap.append(payload, bitmap, methode, performance=performance): if not self.preliminary_mode: if methode.get_type() == METHODE_IMPORT: self.state["imports"] += 1 self.hash_list.add(new_hash) self.new_findings += 1 self.state["last_hash_time"] = time.time() self.__update_state() else: self.state["preliminary"] += 1 else: if not self.preliminary_mode: self.shadow_map.add(new_hash) if reloaded: self.ring_buffers[slave_id].clear()