def generate_report(self, output_file): Logger.log_verbose("Writing HTML report to file: %s" % output_file) # Results c = {} # # Fill the context # # Audit name c['audit_name'] = Config.audit_name # Start date start_time, stop_time = get_audit_times() c['start_date'] = str(datetime.datetime.fromtimestamp(start_time)) if start_time else "Unknown" c['end_date'] = str(datetime.datetime.fromtimestamp(stop_time)) if stop_time else "Interrupted" # Execution time if start_time and stop_time and start_time < stop_time: td = datetime.datetime.fromtimestamp(stop_time) - datetime.datetime.fromtimestamp(start_time) days = td.days hours = td.seconds // 3600 minutes = (td.seconds // 60) % 60 seconds = td.seconds c['execution_time'] = "%d days %d hours %d minutes %d seconds" % (days, hours, minutes, seconds) else: c['execution_time'] = "Unknown" # Targets # XXX FIXME: the HTML template only knows how to show URL targets! :( targets = Config.audit_scope.get_targets() targets = [ x.url for x in targets if x.data_type == x.TYPE_RESOURCE and (x.resource_type == x.RESOURCE_URL) ] c['targets'] = targets # Fill the vulnerabilities summary self.fill_summary_vulns(c) # Fill the info of the resources self.fill_content_resource(c) # Fill the info of the resources self.fill_content_vuln(c) # # Write the output # #m_rendered = t.render(c) with open(output_file, "w") as f: simplejson.dump(c, f)
def generate_report(self, output_file): Logger.log_verbose("Writing HTML report to file: %s" % output_file) # # configure django # import django.conf try: django.conf.settings.configure( TEMPLATE_DIRS = (join(dirname(__file__), './html_report'),) ) except RuntimeError: # Already configured django pass from django.template import Template, loader, Context from django.conf import settings c = Context() t = loader.get_template(template_name="template.html") # # Fill the context # # Audit name c['audit_name'] = Config.audit_name # Start date start_time, stop_time = get_audit_times() c['start_date'] = datetime.datetime.fromtimestamp(start_time) if start_time else "Unknown" c['end_date'] = datetime.datetime.fromtimestamp(stop_time) if stop_time else "Interrupted" # Execution time if start_time and stop_time and start_time < stop_time: td = datetime.datetime.fromtimestamp(stop_time) - datetime.datetime.fromtimestamp(start_time) days = td.days hours = td.seconds // 3600 minutes = (td.seconds // 60) % 60 seconds = td.seconds % 60 c['execution_time'] = "%d days %d hours %d minutes %d seconds" % (days, hours, minutes, seconds) else: c['execution_time'] = "Unknown" # Targets # XXX FIXME: the HTML template only knows how to show URL targets! :( targets = Config.audit_scope.get_targets() targets = [ x.url for x in targets if x.data_type == x.TYPE_RESOURCE and x.resource_type == x.RESOURCE_URL ] c['targets'] = targets # Fill the vulnerabilities summary self.fill_summary_vulns(c) # Fill the info of the resources self.fill_content_resource(c) # Fill the info of the resources self.fill_content_vuln(c) # # Write the output # m_rendered = t.render(c) f = open(output_file, "w") f.write("%s" % m_rendered.encode("utf-8")) f.close()
def generate_report(self, output_file): Logger.log_verbose( "Writing CSV report to file: %s" % output_file) # All rows have the same format but the first. # There's always 26 columns in every row. # Most columns are for Vulnerability objects, empty for other types. # Read the source code for more details, it's really simple. :) # Open the output file. with open(output_file, "w") as f: writer = csv.writer(f) # Write the first row, describing the report itself. report_time = datetime.utcnow() start_time, stop_time, run_time = parse_audit_times( *get_audit_times()) row = [ "GoLismero " + VERSION, 1, # format version Config.audit_name, start_time, stop_time, run_time, report_time, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, pickle.dumps(Config.audit_config, protocol=0).encode("hex"), pickle.dumps(Config.audit_scope, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row) # Used to convert the false_positive flag to a string value. fp = { True: 1, False: 0, None: -1, } # Just the vulnerabilities? if Config.audit_config.only_vulns: # Dump only Vulnerability objects that are not false positives. for vuln in self.__iterate_data( data_type=Data.TYPE_VULNERABILITY): if vuln.false_positive: continue target = vuln.target row = [ vuln.identity, vuln.data_type, vuln.data_subtype, None, vuln.display_name, vuln.plugin_id, vuln.tool_id, vuln.custom_id, vuln.level, vuln.risk, vuln.severity, vuln.impact, vuln.cvss_base, vuln.cvss_score, vuln.cvss_vector, fp[vuln.false_positive], target.identity, target.display_name, vuln.title, vuln.description, vuln.solution, "\n".join(vuln.references), "\n".join(vuln.taxonomies), str(target), pickle.dumps(vuln, protocol=0).encode("hex"), pickle.dumps(target, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row) # Full database dump? else: # Dump all objects in the database. for data in self.__iterate_data(): if data.data_type == Data.TYPE_VULNERABILITY: vuln = data target = vuln.target row = [ vuln.identity, vuln.data_type, vuln.data_subtype, None, vuln.display_name, vuln.plugin_id, vuln.tool_id, vuln.custom_id, vuln.level, vuln.risk, vuln.severity, vuln.impact, vuln.cvss_base, vuln.cvss_score, vuln.cvss_vector, fp[vuln.false_positive], target.identity, target.display_name, vuln.title, vuln.description, vuln.solution, "\n".join(vuln.references), "\n".join(vuln.taxonomies), str(target), pickle.dumps(vuln, protocol=0).encode("hex"), pickle.dumps(target, protocol=0).encode("hex"), ] else: row = [ data.identity, data.data_type, data.data_subtype, getattr(data, "category", None), data.display_name, None, None, None, None, None, None, None, None, None, None, 0, None, None, None, None, None, None, None, str(data), None, pickle.dumps(data, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row)
def write_report_to_open_file(self, f): """ Write the report into the given open file. :param f: Open file. :type f: file """ # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Print the main header. print >>f, "GoLismero Report" print >>f, "================" print >>f, "" print >>f, ".. title:: %s - GoLismero" % self.__format_rst(Config.audit_name) print >>f, "" print >>f, ".. footer:: Report generation date: %s UTC" % datetime.utcnow() print >>f, "" print >>f, ".. contents:: Table of Contents" print >>f, " :depth: 3" print >>f, " :backlinks: top" print >>f, "" # Print the summary. start_time, stop_time, run_time = parse_audit_times( *get_audit_times() ) print >>f, "Summary" print >>f, "-------" print >>f, "" print >>f, "- Audit name: " + self.__format_rst(Config.audit_name) print >>f, "- Start date: " + start_time print >>f, "- End date: " + stop_time print >>f, "- Execution time: " + run_time print >>f, "- Report type: " + ( "Full" if self.__full_report else "Brief") print >>f, "" # Print the audit scope. print >>f, "Audit Scope" print >>f, "-----------" print >>f, "" print >>f, "- IP Addresses: " for address in Config.audit_scope.addresses: print >>f, " + " + self.__format_rst(address) print >>f, "- Domains:" scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) for domain in scope_domains: print >>f, " + " + self.__format_rst(domain) print >>f, "- Web Pages:" for url in Config.audit_scope.web_pages: print >>f, " + " + self.__format_rst(url) print >>f, "" # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If it's a brief report and we have no vulnerabilities, # write a message and stop. if not datas and not self.__full_report: print >>f, "No vulnerabilities found." print >>f, "" return # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set() for ids in fp.itervalues(): self.__fp.update(ids) try: # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() # Report the vulnerabilities. if datas: self.__write_rst(f, datas, Data.TYPE_VULNERABILITY, "Vulnerabilities") try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__write_rst(f, datas, Data.TYPE_RESOURCE, "Resources" if self.__full_report else "Assets") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__write_rst(f, datas, Data.TYPE_INFORMATION, "Informations" if self.__full_report else "Evidences") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__write_rst(f, fp, Data.TYPE_VULNERABILITY, "False Positives")
def __write_report(self): # Header print >>self.__fd, "" print >>self.__fd, "--= %s =--" % self.__colorize("Report", "cyan") print >>self.__fd, "" # Summary start_time, stop_time, run_time = parse_audit_times( *get_audit_times() ) host_count = Database.count(Data.TYPE_RESOURCE, Resource.RESOURCE_DOMAIN) host_count += Database.count(Data.TYPE_RESOURCE, Resource.RESOURCE_IP) vuln_count = Database.count(Data.TYPE_VULNERABILITY) print >>self.__fd, "-# %s #- " % self.__colorize("Summary", "yellow") print >>self.__fd, "" print >>self.__fd, "Audit started: %s" % self.__colorize(start_time, "yellow") print >>self.__fd, "Audit ended: %s" % self.__colorize(stop_time, "yellow") print >>self.__fd, "Execution time: %s" % self.__colorize(run_time, "yellow") print >>self.__fd, "" print >>self.__fd, "Scanned hosts: %s" % self.__colorize(str(host_count), "yellow") print >>self.__fd, "Vulnerabilities: %s" % self.__colorize(str(vuln_count), "red" if vuln_count else "yellow") print >>self.__fd, "" # Audit scope if self.__show_data or not self.__console: table = Texttable() scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) if Config.audit_scope.addresses: table.add_row(("IP addresses", "\n".join(Config.audit_scope.addresses))) if scope_domains: table.add_row(("Domains", "\n".join(scope_domains))) if Config.audit_scope.web_pages: table.add_row(("Web pages", "\n".join(Config.audit_scope.web_pages))) if table._rows: self.__fix_table_width(table) print >>self.__fd, "-# %s #- " % self.__colorize("Audit Scope", "yellow") print >>self.__fd, "" print >>self.__fd, table.draw() print >>self.__fd, "" # Discovered hosts if self.__show_data: need_header = True for domain in self.__iterate(Data.TYPE_RESOURCE, Resource.RESOURCE_DOMAIN): table = Texttable() self.__add_related(table, domain, Data.TYPE_RESOURCE, Resource.RESOURCE_IP, "IP Address") self.__add_related(table, domain, Data.TYPE_INFORMATION, Information.INFORMATION_GEOLOCATION, "Location") self.__add_related(table, domain, Data.TYPE_INFORMATION, Information.INFORMATION_WEB_SERVER_FINGERPRINT, "Web Server") self.__add_related(table, domain, Data.TYPE_INFORMATION, Information.INFORMATION_OS_FINGERPRINT, "OS Fingerprint") if table._rows: if need_header: need_header = False print >>self.__fd, "-# %s #- " % self.__colorize("Hosts", "yellow") print >>self.__fd, "" table.header(("Domain Name", domain.hostname)) self.__fix_table_width(table) text = table.draw() if self.__color: text = colorize_substring(text, domain.hostname, "red" if domain.get_links(Data.TYPE_VULNERABILITY) else "green") print >>self.__fd, text print >>self.__fd, "" for ip in self.__iterate(Data.TYPE_RESOURCE, Resource.RESOURCE_IP): table = Texttable() self.__add_related(table, ip, Data.TYPE_RESOURCE, Resource.RESOURCE_DOMAIN, "Domain Name") self.__add_related(table, ip, Data.TYPE_INFORMATION, Information.INFORMATION_GEOLOCATION, "Location") self.__add_related(table, ip, Data.TYPE_INFORMATION, Information.INFORMATION_WEB_SERVER_FINGERPRINT, "Web Server") self.__add_related(table, ip, Data.TYPE_INFORMATION, Information.INFORMATION_OS_FINGERPRINT, "OS Fingerprint") self.__add_related(table, ip, Data.TYPE_INFORMATION, Information.INFORMATION_PORTSCAN, "Port Scan") self.__add_related(table, ip, Data.TYPE_INFORMATION, Information.INFORMATION_TRACEROUTE, "Network Route") if table._rows: if need_header: need_header = False print >>self.__fd, "-# %s #- " % self.__colorize("Hosts", "yellow") print >>self.__fd, "" table.header(("IP Address", ip.address)) self.__fix_table_width(table) text = table.draw() if self.__color: text = colorize_substring(text, ip.address, "red" if ip.get_links(Data.TYPE_VULNERABILITY) else "green") print >>self.__fd, text print >>self.__fd, "" # Web servers if self.__show_data and Database.count(Data.TYPE_RESOURCE, Resource.RESOURCE_BASE_URL): print >>self.__fd, "-# %s #- " % self.__colorize("Web Servers", "yellow") print >>self.__fd, "" crawled = defaultdict(list) vulnerable = [] for url in self.__iterate(Data.TYPE_RESOURCE, Resource.RESOURCE_URL): crawled[url.hostname].append(url.url) if self.__color and url.get_links(Data.TYPE_VULNERABILITY): vulnerable.append(url) for url in self.__iterate(Data.TYPE_RESOURCE, Resource.RESOURCE_BASE_URL): table = Texttable() table.header(("Base URL", url.url)) self.__add_related(table, url, Data.TYPE_INFORMATION, Information.INFORMATION_WEB_SERVER_FINGERPRINT, "Server") self.__add_related(table, url, Data.TYPE_INFORMATION, Information.INFORMATION_OS_FINGERPRINT, "Platform") urls = crawled[url.hostname] if urls: urls.sort() table.add_row(("Visited URLs", "\n".join(urls))) if table._rows: self.__fix_table_width(table) text = table.draw() if self.__color: p = text.find("\n") p = text.find("\n", p + 1) p = text.find("\n", p + 1) if p > 0: text = colorize_substring(text[:p], url.url, "red" if url.get_links(Data.TYPE_VULNERABILITY) else "green") + text[p:] for u in vulnerable: if u != url.url: text = colorize_substring(text, u, "red") print >>self.__fd, text print >>self.__fd, "" # Emails if self.__show_data: emails = { e.address: "red" if e.get_links(Data.TYPE_VULNERABILITY) else "green" for e in self.__iterate(Data.TYPE_RESOURCE, Resource.RESOURCE_EMAIL) } if emails: print >>self.__fd, "-# %s #- " % self.__colorize("Email Addresses", "yellow") print >>self.__fd, "" for e in sorted(emails): print >>self.__fd, "* " + self.__colorize(e, emails[e]) print >>self.__fd, "" # Vulnerabilities print >>self.__fd, "-# %s #- " % self.__colorize("Vulnerabilities", "yellow") print >>self.__fd, "" count = Database.count(Data.TYPE_VULNERABILITY) if count: if self.__show_data: print >>self.__fd, self.__colorize("%d vulnerabilities found!" % count, "red") print >>self.__fd, "" vuln_types = { v.display_name: v.vulnerability_type for v in self.__iterate(Data.TYPE_VULNERABILITY) } titles = vuln_types.keys() titles.sort() if "Uncategorized Vulnerability" in titles: titles.remove("Uncategorized Vulnerability") titles.append("Uncategorized Vulnerability") for title in titles: data_subtype = vuln_types[title] print >>self.__fd, "-- %s (%s) -- " % (self.__colorize(title, "cyan"), data_subtype) print >>self.__fd, "" for vuln in self.__iterate(Data.TYPE_VULNERABILITY, data_subtype): table = Texttable() table.header(("Occurrence ID", vuln.identity)) w = len(table.draw()) table.add_row(("Title", vuln.title)) targets = [str(x) for x in vuln.associated_resources] for info in vuln.associated_informations: targets.extend(str(x) for x in info.associated_resources) table.add_row(("Found By", get_plugin_name(vuln.plugin_id))) p = len(table.draw()) table.add_row(("Level", vuln.level)) table.add_row(("Impact", vuln.impact)) table.add_row(("Severity", vuln.severity)) table.add_row(("Risk", vuln.risk)) q = len(table.draw()) if vuln.cvss_base: table.add_row(("CVSS Base", vuln.cvss_base)) if vuln.cvss_base_vector: table.add_row(("CVSS Base Vector", vuln.cvss_base_vector)) if len(targets) > 1: targets.sort() table.add_row(("Locations", "\n".join(targets))) else: table.add_row(("Location", targets[0])) table.add_row(("Description", vuln.description)) table.add_row(("Solution", vuln.solution)) taxonomy = [] if vuln.bid: taxonomy.extend(vuln.bid) if vuln.cve: taxonomy.extend(vuln.cve) if vuln.cwe: taxonomy.extend(vuln.cwe) if vuln.osvdb: taxonomy.extend(vuln.osvdb) if vuln.sa: taxonomy.extend(vuln.sa) if vuln.sectrack: taxonomy.extend(vuln.sectrack) if vuln.xf: taxonomy.extend(vuln.xf) if taxonomy: table.add_row(("Taxonomy", "\n".join(taxonomy))) if vuln.references: table.add_row(("References", "\n".join(sorted(vuln.references)))) details = vuln.display_properties["Details"] if details: props = details.keys() props.sort() table.add_row(("Additional details", "\n".join(("%s: %s" % (x, details[x])) for x in props))) self.__fix_table_width(table) text = table.draw() if self.__color: text_1 = text[:w] text_3 = text[p:q] text_1 = colorize_substring(text_1, vuln.identity, vuln.level.lower()) for lvl in Vulnerability.VULN_LEVELS: if lvl in text_3: text_3 = colorize_substring(text_3, lvl, lvl.lower()) text = text_1 + text[w:p] + text_3 + text[q:] print >>self.__fd, text print >>self.__fd, "" else: print >>self.__fd, self.__colorize("No vulnerabilities found.", "green") print >>self.__fd, ""
def generate_report(self, output_file): Logger.log_verbose("Writing reStructured text report to file: %s" % output_file) # Open the output file. with open(output_file, "w") as f: # Print the main header. print >> f, "GoLismero Report" print >> f, "================" print >> f, "" print >> f, ".. title:: %s - GoLismero" % self.__format_rst( Config.audit_name) print >> f, "" print >> f, ".. footer:: Report generation date: %s" % datetime.now( ) print >> f, "" print >> f, ".. contents:: Table of Contents" print >> f, " :depth: 3" print >> f, " :backlinks: top" print >> f, "" # Print the summary. start_time, stop_time, run_time = parse_audit_times( *get_audit_times()) print >> f, "Summary" print >> f, "-------" print >> f, "" print >> f, "- Audit name: " + self.__format_rst(Config.audit_name) print >> f, "- Start date: " + start_time print >> f, "- End date: " + stop_time print >> f, "- Execution time: " + run_time print >> f, "" # Print the audit scope. print >> f, "Audit Scope" print >> f, "-----------" print >> f, "" print >> f, "- IP Addresses: " for address in Config.audit_scope.addresses: print >> f, " + " + self.__format_rst(address) print >> f, "- Domains:" scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) for domain in scope_domains: print >> f, " + " + self.__format_rst(domain) print >> f, "- Web Pages:" for url in Config.audit_scope.web_pages: print >> f, " + " + self.__format_rst(url) print >> f, "" # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If it's a brief report and we have no vulnerabilities, # write a message and stop. if not datas and not self.__full_report: print >> f, "No vulnerabilities found." print >> f, "" return # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set() for ids in fp.itervalues(): self.__fp.update(ids) try: # Report the vulnerabilities. self.__write_rst(f, datas, Data.TYPE_VULNERABILITY, "Vulnerabilities") # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__write_rst( f, datas, Data.TYPE_RESOURCE, "Resources" if self.__full_report else "Assets") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__write_rst( f, datas, Data.TYPE_INFORMATION, "Informations" if self.__full_report else "Evidences") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__write_rst(f, fp, Data.TYPE_VULNERABILITY, "False Positives") # Launch the build command, if any. command = Config.plugin_config.get("command", "") if command: Logger.log_verbose("Launching command: %s" % command) args = split(command) for i in xrange(len(args)): token = args[i] p = token.find("$1") while p >= 0: if p == 0 or (p > 0 and token[p - 1] != "$"): token = token[:p] + output_file + token[p + 2:] p = token.find("$1", p + len(output_file)) args[i] = token cwd = os.path.split(output_file)[0] log = lambda x: Logger.log_verbose(x[:-1] if x.endswith("\n") else x) run_external_tool(args[0], args[1:], cwd=cwd, callback=log)
def generate_report(self, output_file): Logger.log_verbose("Writing audit results to file: %s" % output_file) # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Parse the audit times. report_time = "%s UTC" % datetime.utcnow() start_time, stop_time = get_audit_times() start_time, stop_time, run_time = parse_audit_times( start_time, stop_time) # Create the root element. xml = ET.Element("golismero") xml.set("audit_name", Config.audit_name) if start_time: xml.set("start_time", start_time) if stop_time: xml.set("stop_time", stop_time) if run_time: xml.set("run_time", run_time) xml.set("report_time", report_time) xml.set("report_type", "full" if self.__full_report else "brief") # Create the audit scope element and subelements. xml_scope = ET.SubElement(xml, "audit_scope") for address in Config.audit_scope.addresses: xml_ip = ET.SubElement(xml_scope, "address") xml_ip.text = address for root_domain in Config.audit_scope.roots: xml_root = ET.SubElement(xml_scope, "root_domain") xml_root.text = root_domain for domain in Config.audit_scope.domains: xml_domain = ET.SubElement(xml_scope, "domain") xml_domain.text = domain for web_page in Config.audit_scope.web_pages: xml_web = ET.SubElement(xml_scope, "web_page") xml_web.text = web_page # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If we have vulnerabilities and/or it's a full report... if datas or self.__full_report: # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set(fp) try: # Report the vulnerabilities. if datas: xml_vulns = ET.SubElement(xml, "vulnerabilities") self.__add_to_xml(xml_vulns, datas, Data.TYPE_VULNERABILITY, "vulnerability") # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: xml_res = ET.SubElement(xml, "resources") self.__add_to_xml(xml_res, datas, Data.TYPE_RESOURCE, "resource") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: xml_info = ET.SubElement(xml, "informations") self.__add_to_xml(xml_info, datas, Data.TYPE_INFORMATION, "information") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: xml_fp = ET.SubElement(xml, "false_positives") self.__add_to_xml(xml_fp, fp, Data.TYPE_VULNERABILITY, "vulnerability") # Write the XML data to disk. tree = ET.ElementTree(xml) tree.write(output_file, encoding="utf-8") # Launch the build command, if any. self.launch_command(output_file)
def get_report_data(self): """ Get the data to be included in the report as a Python dictionary. There are two supported modes: "nice" and "dump". The output mode is taken directly from the plugin configuration. :returns: Data to include in the report. :rtype: dict(str -> *) """ # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Parse the audit times. report_time = str(datetime.utcnow()) start_time, stop_time = get_audit_times() start_time, stop_time, run_time = parse_audit_times( start_time, stop_time) # Get the output mode. mode = Config.plugin_args.get("mode", "dump") mode = mode.replace(" ", "") mode = mode.replace("\r", "") mode = mode.replace("\n", "") mode = mode.replace("\t", "") mode = mode.lower() if mode not in ("dump", "nice"): Logger.log_error("Invalid output mode: %s" % mode) mode = "dump" self.__dumpmode = (mode == "dump") Logger.log_more_verbose("Output mode: %s" % ("dump" if self.__dumpmode else "nice")) # Create the root element. root = dict() # Add the GoLismero version property. if self.__dumpmode: root["version"] = "GoLismero " + VERSION else: root["GoLismero Version"] = "GoLismero " + VERSION # Add the report type property. if self.__dumpmode: root["report_type"] = "full" if self.__full_report else "brief" else: root["Report Type"] = "Full" if self.__full_report else "Brief" # Add the summary element. if self.__dumpmode: root["summary"] = { "audit_name": Config.audit_name, "start_time": start_time, "stop_time": stop_time, "run_time": run_time, "report_time": report_time, } else: root["Summary"] = { "Audit Name": Config.audit_name, "Start Time": start_time, "Stop Time": stop_time, "Run Time": run_time, "Report Time": report_time, } # Add the audit scope element. if self.__dumpmode: wildcards = [ "*." + x for x in Config.audit_scope.roots ] root["audit_scope"] = { "addresses": Config.audit_scope.addresses, "roots": wildcards, "domains": Config.audit_scope.domains, "web_pages": Config.audit_scope.web_pages, } else: domains = [ "*." + x for x in Config.audit_scope.roots ] domains.extend(Config.audit_scope.domains) domains.sort() root["Audit Scope"] = { "IP Addresses": Config.audit_scope.addresses, "Domains": domains, "Web Pages": Config.audit_scope.web_pages, } # Create the elements for the data. key_vuln = "vulnerabilities" if self.__dumpmode else "Vulnerabilities" key_res = "resources" if self.__dumpmode else "Assets" key_info = "informations" if self.__dumpmode else "Evidences" key_fp = "false_positives" if self.__dumpmode else "False Positives" root[key_vuln] = dict() root[key_res] = dict() root[key_info] = dict() root[key_fp] = dict() # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If we have vulnerabilities and/or it's a full report... if datas or self.__full_report: # Collect the false positives. # In brief mode, this is used to eliminate # the references to them. fp = self.__collect_vulns(True) self.__fp = set(fp) try: # Report the vulnerabilities. if datas: self.__add_data( root[key_vuln], datas, Data.TYPE_VULNERABILITY) # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__add_data( root[key_res], datas, Data.TYPE_RESOURCE) # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__add_data( root[key_info], datas, Data.TYPE_INFORMATION) finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__add_data( root[key_fp], fp, Data.TYPE_VULNERABILITY) finally: self.__vulnerable.clear() # Return the data. return root
def write_report_to_open_file(self, f): """ Write the report into the given open file. :param f: Open file. :type f: file """ # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Print the main header. print >> f, "GoLismero Report" print >> f, "================" print >> f, "" print >> f, ".. title:: %s - GoLismero" % self.__format_rst( Config.audit_name) print >> f, "" print >> f, ".. footer:: Report generation date: %s UTC" % datetime.utcnow( ) print >> f, "" print >> f, ".. contents:: Table of Contents" print >> f, " :depth: 3" print >> f, " :backlinks: top" print >> f, "" # Print the summary. start_time, stop_time, run_time = parse_audit_times(*get_audit_times()) print >> f, "Summary" print >> f, "-------" print >> f, "" print >> f, "- Audit name: " + self.__format_rst(Config.audit_name) print >> f, "- Start date: " + start_time print >> f, "- End date: " + stop_time print >> f, "- Execution time: " + run_time print >> f, "- Report type: " + ("Full" if self.__full_report else "Brief") print >> f, "" # Print the audit scope. print >> f, "Audit Scope" print >> f, "-----------" print >> f, "" print >> f, "- IP Addresses: " for address in Config.audit_scope.addresses: print >> f, " + " + self.__format_rst(address) print >> f, "- Domains:" scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) for domain in scope_domains: print >> f, " + " + self.__format_rst(domain) print >> f, "- Web Pages:" for url in Config.audit_scope.web_pages: print >> f, " + " + self.__format_rst(url) print >> f, "" # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If it's a brief report and we have no vulnerabilities, # write a message and stop. if not datas and not self.__full_report: print >> f, "No vulnerabilities found." print >> f, "" return # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set() for ids in fp.itervalues(): self.__fp.update(ids) try: # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() # Report the vulnerabilities. if datas: self.__write_rst(f, datas, Data.TYPE_VULNERABILITY, "Vulnerabilities") try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__write_rst( f, datas, Data.TYPE_RESOURCE, "Resources" if self.__full_report else "Assets") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__write_rst( f, datas, Data.TYPE_INFORMATION, "Informations" if self.__full_report else "Evidences") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__write_rst(f, fp, Data.TYPE_VULNERABILITY, "False Positives")
def __write_report(self): # Header print >>self.__fd, "" print >>self.__fd, "--= %s =--" % self.__colorize("Report", "cyan") print >>self.__fd, "" # Summary start_time, stop_time, run_time = parse_audit_times( *get_audit_times() ) host_count = Database.count(Data.TYPE_RESOURCE, Domain.data_subtype) host_count += Database.count(Data.TYPE_RESOURCE, IP.data_subtype) vuln_count = Database.count(Data.TYPE_VULNERABILITY) print >>self.__fd, "-# %s #- " % self.__colorize("Summary", "yellow") print >>self.__fd, "" print >>self.__fd, "Audit started: %s" % self.__colorize(start_time, "yellow") print >>self.__fd, "Audit ended: %s" % self.__colorize(stop_time, "yellow") print >>self.__fd, "Execution time: %s" % self.__colorize(run_time, "yellow") print >>self.__fd, "" print >>self.__fd, "Scanned hosts: %s" % self.__colorize(str(host_count), "yellow") print >>self.__fd, "Vulnerabilities: %s" % self.__colorize(str(vuln_count), "red" if vuln_count else "yellow") print >>self.__fd, "" # Audit scope if self.__show_data or not self.__console: table = Texttable() scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) if Config.audit_scope.addresses: table.add_row(("IP addresses", "\n".join(Config.audit_scope.addresses))) if scope_domains: table.add_row(("Domains", "\n".join(scope_domains))) if Config.audit_scope.web_pages: table.add_row(("Web pages", "\n".join(Config.audit_scope.web_pages))) if table._rows: self.__fix_table_width(table) print >>self.__fd, "-# %s #- " % self.__colorize("Audit Scope", "yellow") print >>self.__fd, "" print >>self.__fd, table.draw() print >>self.__fd, "" # Discovered hosts if self.__show_data: need_header = True for domain in self.__iterate(Data.TYPE_RESOURCE, Domain.data_subtype): table = Texttable() self.__add_related(table, domain, Data.TYPE_RESOURCE, IP.data_subtype, "IP Address") self.__add_related(table, domain, Data.TYPE_INFORMATION, Geolocation.data_subtype, "Location") self.__add_related(table, domain, Data.TYPE_INFORMATION, WebServerFingerprint.data_subtype, "Web Server") self.__add_related(table, domain, Data.TYPE_INFORMATION, OSFingerprint.data_subtype, "OS Fingerprint") if table._rows: if need_header: need_header = False print >>self.__fd, "-# %s #- " % self.__colorize("Hosts", "yellow") print >>self.__fd, "" table.header(("Domain Name", domain.hostname)) self.__fix_table_width(table) text = table.draw() if self.__color: text = colorize_substring(text, domain.hostname, "red" if domain.get_links(Data.TYPE_VULNERABILITY) else "green") print >>self.__fd, text print >>self.__fd, "" for ip in self.__iterate(Data.TYPE_RESOURCE, IP.data_subtype): table = Texttable() self.__add_related(table, ip, Data.TYPE_RESOURCE, Domain.data_subtype, "Domain Name") self.__add_related(table, ip, Data.TYPE_RESOURCE, MAC.data_subtype, "MAC Address") self.__add_related(table, ip, Data.TYPE_RESOURCE, BSSID.data_subtype, "WiFi 802.11 BSSID") self.__add_related(table, ip, Data.TYPE_INFORMATION, Geolocation.data_subtype, "Location") self.__add_related(table, ip, Data.TYPE_INFORMATION, WebServerFingerprint.data_subtype, "Web Server") self.__add_related(table, ip, Data.TYPE_INFORMATION, OSFingerprint.data_subtype, "OS Fingerprint") self.__add_related(table, ip, Data.TYPE_INFORMATION, ServiceFingerprint.data_subtype, "Service") self.__add_related(table, ip, Data.TYPE_INFORMATION, Portscan.data_subtype, "Port Scan") self.__add_related(table, ip, Data.TYPE_INFORMATION, Traceroute.data_subtype, "Network Route") if table._rows: if need_header: need_header = False print >>self.__fd, "-# %s #- " % self.__colorize("Hosts", "yellow") print >>self.__fd, "" table.header(("IP Address", ip.address)) self.__fix_table_width(table) text = table.draw() if self.__color: text = colorize_substring(text, ip.address, "red" if ip.get_links(Data.TYPE_VULNERABILITY) else "green") print >>self.__fd, text print >>self.__fd, "" # Web servers if self.__show_data and Database.count(Data.TYPE_RESOURCE, BaseURL.data_subtype): print >>self.__fd, "-# %s #- " % self.__colorize("Web Servers", "yellow") print >>self.__fd, "" crawled = defaultdict(list) vulnerable = [] for url in self.__iterate(Data.TYPE_RESOURCE, URL.data_subtype): crawled[url.hostname].append(url.url) if self.__color and url.get_links(Data.TYPE_VULNERABILITY): vulnerable.append(url) for url in self.__iterate(Data.TYPE_RESOURCE, BaseURL.data_subtype): table = Texttable() table.header(("Base URL", url.url)) self.__add_related(table, url, Data.TYPE_INFORMATION, WebServerFingerprint.data_subtype, "Server") self.__add_related(table, url, Data.TYPE_INFORMATION, OSFingerprint.data_subtype, "Platform") urls = crawled[url.hostname] if urls: urls.sort() table.add_row(("Visited URLs", "\n".join(urls))) if table._rows: self.__fix_table_width(table) text = table.draw() if self.__color: p = text.find("\n") p = text.find("\n", p + 1) p = text.find("\n", p + 1) if p > 0: text = colorize_substring(text[:p], url.url, "red" if url.get_links(Data.TYPE_VULNERABILITY) else "green") + text[p:] for u in vulnerable: if u != url.url: text = colorize_substring(text, u, "red") print >>self.__fd, text print >>self.__fd, "" # Emails if self.__show_data: emails = { e.address: "red" if e.get_links(Data.TYPE_VULNERABILITY) else "green" for e in self.__iterate(Data.TYPE_RESOURCE, Email.data_subtype) } if emails: print >>self.__fd, "-# %s #- " % self.__colorize("Email Addresses", "yellow") print >>self.__fd, "" for e in sorted(emails): print >>self.__fd, "* " + self.__colorize(e, emails[e]) print >>self.__fd, "" # Vulnerabilities print >>self.__fd, "-# %s #- " % self.__colorize("Vulnerabilities", "yellow") print >>self.__fd, "" count = Database.count(Data.TYPE_VULNERABILITY) if count: if self.__show_data: print >>self.__fd, self.__colorize("%d vulnerabilities found!" % count, "red") print >>self.__fd, "" vuln_types = { v.display_name: v.vulnerability_type for v in self.__iterate(Data.TYPE_VULNERABILITY) } titles = vuln_types.keys() titles.sort() if "Uncategorized Vulnerability" in titles: titles.remove("Uncategorized Vulnerability") titles.append("Uncategorized Vulnerability") for title in titles: data_subtype = vuln_types[title] print >>self.__fd, "-- %s (%s) -- " % (self.__colorize(title, "cyan"), data_subtype) print >>self.__fd, "" for vuln in self.__iterate(Data.TYPE_VULNERABILITY, data_subtype): table = Texttable() table.header(("Occurrence ID", vuln.identity)) w = len(table.draw()) table.add_row(("Title", vuln.title)) ##targets = self.__gather_vulnerable_resources(vuln) targets = [vuln.target] table.add_row(("Found By", get_plugin_name(vuln.plugin_id))) p = len(table.draw()) table.add_row(("Level", vuln.level)) #table.add_row(("Impact", vuln.impact)) #table.add_row(("Severity", vuln.severity)) #table.add_row(("Risk", vuln.risk)) q = len(table.draw()) if vuln.cvss_base: table.add_row(("CVSS Base", vuln.cvss_base)) if vuln.cvss_score: table.add_row(("CVSS Score", vuln.cvss_score)) if vuln.cvss_vector: table.add_row(("CVSS Vector", vuln.cvss_vector)) if len(targets) > 1: targets.sort() table.add_row(("Locations", "\n".join(targets))) elif targets: table.add_row(("Location", targets[0])) table.add_row(("Description", vuln.description)) table.add_row(("Solution", vuln.solution)) taxonomy = [] if vuln.bid: taxonomy.extend(vuln.bid) if vuln.cve: taxonomy.extend(vuln.cve) if vuln.cwe: taxonomy.extend(vuln.cwe) if vuln.osvdb: taxonomy.extend(vuln.osvdb) if vuln.sa: taxonomy.extend(vuln.sa) if vuln.sectrack: taxonomy.extend(vuln.sectrack) if vuln.xf: taxonomy.extend(vuln.xf) if taxonomy: table.add_row(("Taxonomy", "\n".join(taxonomy))) if vuln.references: table.add_row(("References", "\n".join(sorted(vuln.references)))) details = vuln.display_properties.get("Details") if details: props = details.keys() props.sort() table.add_row(("Additional details", "\n".join(("%s: %s" % (x, details[x])) for x in props))) self.__fix_table_width(table) text = table.draw() if self.__color: text_1 = text[:w] text_3 = text[p:q] text_1 = colorize_substring(text_1, vuln.identity, vuln.level.lower()) for lvl in Vulnerability.VULN_LEVELS: if lvl in text_3: text_3 = colorize_substring(text_3, lvl, lvl.lower()) text = text_1 + text[w:p] + text_3 + text[q:] print >>self.__fd, text print >>self.__fd, "" else: print >>self.__fd, self.__colorize("No vulnerabilities found.", "green") print >>self.__fd, ""
def generate_report(self, output_file): Logger.log_verbose("Writing HTML report to file: %s" % output_file) # # configure django # import django.conf django.conf.settings.configure( TEMPLATE_DIRS=(join(dirname(__file__), './html_report'), )) from django.template import Template, loader, Context from django.conf import settings c = Context() t = loader.get_template(template_name="template.html") # # Fill the context # # Audit name c['audit_name'] = Config.audit_name # Start date start_time, stop_time = get_audit_times() c['start_date'] = datetime.datetime.fromtimestamp( start_time) if start_time else "Unknown" c['end_date'] = datetime.datetime.fromtimestamp( stop_time) if stop_time else "Interrupted" # Execution time if start_time and stop_time and start_time < stop_time: td = datetime.datetime.fromtimestamp( stop_time) - datetime.datetime.fromtimestamp(start_time) days = td.days hours = td.seconds // 3600 minutes = (td.seconds // 60) % 60 seconds = td.seconds c['execution_time'] = "%d days %d hours %d minutes %d seconds" % ( days, hours, minutes, seconds) else: c['execution_time'] = "Unknown" # Targets # XXX FIXME: the HTML template only knows how to show URL targets! :( targets = Config.audit_scope.get_targets() targets = [ x.url for x in targets if x.data_type == x.TYPE_RESOURCE and x.resource_type == x.RESOURCE_URL ] c['targets'] = targets # Fill the vulnerabilities summary self.fill_summary_vulns(c) # Fill the info of the resources self.fill_content_resource(c) # Fill the info of the resources self.fill_content_vuln(c) # # Write the output # m_rendered = t.render(c) f = open(output_file, "w") f.write("%s" % m_rendered.encode("utf-8")) f.close()
def get_report_data(self): """ Get the data to be included in the report as a Python dictionary. There are two supported modes: "nice" and "dump". The output mode is taken directly from the plugin configuration. :returns: Data to include in the report. :rtype: dict(str -> *) """ # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Parse the audit times. report_time = str(datetime.utcnow()) start_time, stop_time = get_audit_times() start_time, stop_time, run_time = parse_audit_times( start_time, stop_time) # Get the output mode. mode = Config.plugin_args.get("mode", "dump") mode = mode.replace(" ", "") mode = mode.replace("\r", "") mode = mode.replace("\n", "") mode = mode.replace("\t", "") mode = mode.lower() if mode not in ("dump", "nice"): Logger.log_error("Invalid output mode: %s" % mode) mode = "dump" self.__dumpmode = (mode == "dump") Logger.log_more_verbose("Output mode: %s" % ("dump" if self.__dumpmode else "nice")) # Create the root element. root = dict() # Add the GoLismero version property. if self.__dumpmode: root["version"] = "GoLismero " + VERSION else: root["GoLismero Version"] = "GoLismero " + VERSION # Add the report type property. if self.__dumpmode: root["report_type"] = "full" if self.__full_report else "brief" else: root["Report Type"] = "Full" if self.__full_report else "Brief" # Add the summary element. if self.__dumpmode: root["summary"] = { "audit_name": Config.audit_name, "start_time": start_time, "stop_time": stop_time, "run_time": run_time, "report_time": report_time, } else: root["Summary"] = { "Audit Name": Config.audit_name, "Start Time": start_time, "Stop Time": stop_time, "Run Time": run_time, "Report Time": report_time, } # Add the audit scope element. if self.__dumpmode: wildcards = ["*." + x for x in Config.audit_scope.roots] root["audit_scope"] = { "addresses": Config.audit_scope.addresses, "roots": wildcards, "domains": Config.audit_scope.domains, "web_pages": Config.audit_scope.web_pages, } else: domains = ["*." + x for x in Config.audit_scope.roots] domains.extend(Config.audit_scope.domains) domains.sort() root["Audit Scope"] = { "IP Addresses": Config.audit_scope.addresses, "Domains": domains, "Web Pages": Config.audit_scope.web_pages, } # Create the elements for the data. key_vuln = "vulnerabilities" if self.__dumpmode else "Vulnerabilities" key_res = "resources" if self.__dumpmode else "Assets" key_info = "informations" if self.__dumpmode else "Evidences" key_fp = "false_positives" if self.__dumpmode else "False Positives" root[key_vuln] = dict() root[key_res] = dict() root[key_info] = dict() root[key_fp] = dict() # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If we have vulnerabilities and/or it's a full report... if datas or self.__full_report: # Collect the false positives. # In brief mode, this is used to eliminate # the references to them. fp = self.__collect_vulns(True) self.__fp = set(fp) try: # Report the vulnerabilities. if datas: self.__add_data(root[key_vuln], datas, Data.TYPE_VULNERABILITY) # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__add_data(root[key_res], datas, Data.TYPE_RESOURCE) # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__add_data(root[key_info], datas, Data.TYPE_INFORMATION) finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__add_data(root[key_fp], fp, Data.TYPE_VULNERABILITY) finally: self.__vulnerable.clear() # Return the data. return root
def generate_report(self, output_file): Logger.log_verbose("Writing audit results to file: %s" % output_file) # Parse the audit times. start_time, stop_time = get_audit_times() run_time = stop_time - start_time # Create the root element. xml = ET.Element("golismero") xml.set("output_time", str(datetime.now())) xml.set("audit_name", Config.audit_name) if start_time: xml.set("start_time", str(start_time)) if stop_time: xml.set("stop_time", str(stop_time)) if run_time: xml.set("run_time", str(run_time)) # Create the audit scope element and subelements. xml_scope = ET.SubElement(xml, "audit_scope") for address in Config.audit_scope.addresses: xml_ip = ET.SubElement(xml_scope, "address") xml_ip.text = address for root_domain in Config.audit_scope.roots: xml_root = ET.SubElement(xml_scope, "root_domain") xml_root.text = root_domain for domain in Config.audit_scope.domains: xml_domain = ET.SubElement(xml_scope, "domain") xml_domain.text = domain for web_page in Config.audit_scope.web_pages: xml_web = ET.SubElement(xml_scope, "web_page") xml_web.text = web_page # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If we have vulnerabilities and/or it's a full report... if datas or self.__full_report: # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set(fp) try: # Report the vulnerabilities. if datas: xml_vulns = ET.SubElement(xml, "vulnerabilities") self.__add_to_xml(xml_vulns, datas, Data.TYPE_VULNERABILITY, "vulnerability") # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: xml_res = ET.SubElement(xml, "resources") self.__add_to_xml(xml_res, datas, Data.TYPE_RESOURCE, "resource") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: xml_info = ET.SubElement(xml, "informations") self.__add_to_xml(xml_info, datas, Data.TYPE_INFORMATION, "information") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: xml_fp = ET.SubElement(xml, "false_positives") self.__add_to_xml(xml_fp, fp, Data.TYPE_VULNERABILITY, "vulnerability") # Write the XML data to disk. tree = ET.ElementTree(xml) tree.write(output_file) # Launch the build command, if any. command = Config.plugin_config.get("command", "") if command: Logger.log_verbose("Launching command: %s" % command) args = split(command) for i in xrange(len(args)): token = args[i] p = token.find("$1") while p >= 0: if p == 0 or (p > 0 and token[p-1] != "$"): token = token[:p] + output_file + token[p+2:] p = token.find("$1", p + len(output_file)) args[i] = token cwd = os.path.split(output_file)[0] log = lambda x: Logger.log_verbose(x[:-1] if x.endswith("\n") else x) run_external_tool(args[0], args[1:], cwd=cwd, callback=log)
def generate_report(self, output_file): Logger.log_verbose("Writing CSV report to file: %s" % output_file) # All rows have the same format but the first. # There's always 26 columns in every row. # Most columns are for Vulnerability objects, empty for other types. # Read the source code for more details, it's really simple. :) # Open the output file. with open(output_file, "w") as f: writer = csv.writer(f) # Write the first row, describing the report itself. report_time = datetime.utcnow() start_time, stop_time, run_time = parse_audit_times( *get_audit_times()) row = [ "GoLismero " + VERSION, 1, # format version Config.audit_name, start_time, stop_time, run_time, report_time, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, pickle.dumps(Config.audit_config, protocol=0).encode("hex"), pickle.dumps(Config.audit_scope, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row) # Used to convert the false_positive flag to a string value. fp = { True: 1, False: 0, None: -1, } # Just the vulnerabilities? if Config.audit_config.only_vulns: # Dump only Vulnerability objects that are not false positives. for vuln in self.__iterate_data( data_type=Data.TYPE_VULNERABILITY): if vuln.false_positive: continue target = vuln.target row = [ vuln.identity, vuln.data_type, vuln.data_subtype, None, vuln.display_name, vuln.plugin_id, vuln.tool_id, vuln.custom_id, vuln.level, vuln.risk, vuln.severity, vuln.impact, vuln.cvss_base, vuln.cvss_score, vuln.cvss_vector, fp[vuln.false_positive], target.identity, target.display_name, vuln.title, vuln.description, vuln.solution, "\n".join(vuln.references), "\n".join(vuln.taxonomies), str(target), pickle.dumps(vuln, protocol=0).encode("hex"), pickle.dumps(target, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row) # Full database dump? else: # Dump all objects in the database. for data in self.__iterate_data(): if data.data_type == Data.TYPE_VULNERABILITY: vuln = data target = vuln.target row = [ vuln.identity, vuln.data_type, vuln.data_subtype, None, vuln.display_name, vuln.plugin_id, vuln.tool_id, vuln.custom_id, vuln.level, vuln.risk, vuln.severity, vuln.impact, vuln.cvss_base, vuln.cvss_score, vuln.cvss_vector, fp[vuln.false_positive], target.identity, target.display_name, vuln.title, vuln.description, vuln.solution, "\n".join(vuln.references), "\n".join(vuln.taxonomies), str(target), pickle.dumps(vuln, protocol=0).encode("hex"), pickle.dumps(target, protocol=0).encode("hex"), ] else: row = [ data.identity, data.data_type, data.data_subtype, getattr(data, "category", None), data.display_name, None, None, None, None, None, None, None, None, None, None, 0, None, None, None, None, None, None, None, str(data), None, pickle.dumps(data, protocol=0).encode("hex"), ] row = [to_utf8(x) if x is not None else "" for x in row] writer.writerow(row)
def generate_report(self, output_file): Logger.log_verbose("Writing reStructured text report to file: %s" % output_file) # Open the output file. with open(output_file, "w") as f: # Print the main header. print >>f, "GoLismero Report" print >>f, "================" print >>f, "" print >>f, ".. title:: %s - GoLismero" % self.__format_rst(Config.audit_name) print >>f, "" print >>f, ".. footer:: Report generation date: %s" % datetime.now() print >>f, "" print >>f, ".. contents:: Table of Contents" print >>f, " :depth: 3" print >>f, " :backlinks: top" print >>f, "" # Print the summary. start_time, stop_time, run_time = parse_audit_times( *get_audit_times() ) print >>f, "Summary" print >>f, "-------" print >>f, "" print >>f, "- Audit name: " + self.__format_rst(Config.audit_name) print >>f, "- Start date: " + start_time print >>f, "- End date: " + stop_time print >>f, "- Execution time: " + run_time print >>f, "" # Print the audit scope. print >>f, "Audit Scope" print >>f, "-----------" print >>f, "" print >>f, "- IP Addresses: " for address in Config.audit_scope.addresses: print >>f, " + " + self.__format_rst(address) print >>f, "- Domains:" scope_domains = ["*." + r for r in Config.audit_scope.roots] scope_domains.extend(Config.audit_scope.domains) for domain in scope_domains: print >>f, " + " + self.__format_rst(domain) print >>f, "- Web Pages:" for url in Config.audit_scope.web_pages: print >>f, " + " + self.__format_rst(url) print >>f, "" # Determine the report type. self.__full_report = not Config.audit_config.only_vulns # Collect the vulnerabilities that are not false positives. datas = self.__collect_vulns(False) # If it's a brief report and we have no vulnerabilities, # write a message and stop. if not datas and not self.__full_report: print >>f, "No vulnerabilities found." print >>f, "" return # Collect the false positives. # In brief mode, this is used to eliminate the references to them. fp = self.__collect_vulns(True) self.__fp = set() for ids in fp.itervalues(): self.__fp.update(ids) try: # Report the vulnerabilities. self.__write_rst(f, datas, Data.TYPE_VULNERABILITY, "Vulnerabilities") # This dictionary tracks which data to show # and which not to in brief report mode. self.__vulnerable = set() try: # Show the resources in the report. datas = self.__collect_data(Data.TYPE_RESOURCE) if datas: self.__write_rst(f, datas, Data.TYPE_RESOURCE, "Resources" if self.__full_report else "Assets") # Show the informations in the report. datas = self.__collect_data(Data.TYPE_INFORMATION) if datas: self.__write_rst(f, datas, Data.TYPE_INFORMATION, "Informations" if self.__full_report else "Evidences") finally: self.__vulnerable.clear() finally: self.__fp.clear() # Show the false positives in the full report. if self.__full_report and fp: self.__write_rst(f, fp, Data.TYPE_VULNERABILITY, "False Positives") # Launch the build command, if any. command = Config.plugin_config.get("command", "") if command: Logger.log_verbose("Launching command: %s" % command) args = split(command) for i in xrange(len(args)): token = args[i] p = token.find("$1") while p >= 0: if p == 0 or (p > 0 and token[p-1] != "$"): token = token[:p] + output_file + token[p+2:] p = token.find("$1", p + len(output_file)) args[i] = token cwd = os.path.split(output_file)[0] log = lambda x: Logger.log_verbose(x[:-1] if x.endswith("\n") else x) run_external_tool(args[0], args[1:], cwd=cwd, callback=log)