def parse_results(openvas_results, ip=None): """ Convert the OpenVAS scan results to the GoLismero data model. :param openvas_results: OpenVAS scan results. :type openvas_results: list(OpenVASResult) :param ip: (Optional) IP address to link the vulnerabilities to. :type ip: IP | None :returns: Scan results converted to the GoLismero data model. :rtype: list(Data) """ # This is where we'll store the results. results = [] # Remember the hosts we've seen so we don't create them twice. hosts_seen = {} # Maps of OpenVAS levels to GoLismero levels. LEVELS = { 'debug': 'informational', 'log': 'informational', 'low': "low", 'medium': 'middle', 'high': "high", } RISKS = { 'none': 0, 'debug': 0, 'log': 0, 'low': 1, 'medium': 2, 'high': 3, 'critical': 4 } # Do we have the OpenVAS plugin database? if not os.path.exists(openvas_db): Logger.log_error( "OpenVAS plugin not initialized, please run setup.py") return # Load the database. with open(openvas_db, "rb") as f: use_openvas_db = Pickler.load(f) # Get the configuration. import_log = Config.audit_config.boolean( Config.plugin_args.get("import_log", "no")) import_debug = Config.audit_config.boolean( Config.plugin_args.get("import_debug", "no")) # For each OpenVAS result... for opv in openvas_results: try: # Get the host. host = opv.host # Skip if we don't have a target host. if host is None: continue # Get the threat level. threat = getattr(opv, "threat", "log").lower() # Discard log and debug entries, keep only the vulnerabilities. if threat == "log" and not import_log: continue if threat == "debug" and not import_debug: continue # Get or create the vulnerable resource. target = ip if host in hosts_seen: target = hosts_seen[host] elif not ip or ip.address != host: try: target = IP(host) except ValueError: target = Domain(host) hosts_seen[host] = target results.append(target) # Extract the relevant information from the results. nvt = opv.nvt vid = opv.id oid = int(nvt.oid.split(".")[-1]) name = getattr(nvt, "name", None) cvss_base = getattr(nvt, "cvss_base", None) level = LEVELS.get(threat, "informational") risk = RISKS.get( getattr(opv.nvt, "risk_factor", "none").lower(), 0) # Get the vulnerability description. description = opv.raw_description if not description: description = nvt.description if not description: description = nvt.summary if not description: description = None # Extract the CVEs and Bugtraq IDs. cve = nvt.cve.split(", ") if nvt.cve else [] if "NOCVE" in cve: cve.remove("NOCVE") bid = [] if nvt.bid: bid.extend("BID-" + x for x in nvt.bid.split(", ")) if nvt.bugtraq: bid.extend("BID-" + x for x in nvt.bugtraq.split(", ")) if "NOBID" in bid: cve.remove("NOBID") # Extract the notes and add them to the description text. if opv.notes and description is not None: description += "\n" + "\n".join(" - " + note.text for note in opv.notes) # Extract the reference URLs from the description text. references = [] if description is not None: p = description.find("URL:") while p >= 0: p += 4 q2 = description.find("\n", p) q1 = description.find(",", p, q2) if q1 > p: q = q1 else: q = q2 if q < p: q = len(description) url = description[p:q].strip() try: url = parse_url(url).url references.append(url) except Exception: Logger.log_error(format_exc()) pass p = description.find("URL:", q) # Prepare the vulnerability properties. kwargs = { "title": name, "description": description, "references": references, "level": level, "risk": risk, "severity": risk, "impact": risk, "cvss_base": cvss_base, "cve": cve, "bid": bid, "tool_id": "openvas_plugin_%s" % oid, "custom_id": vid, } # If we have the OpenVAS plugin database, look up the plugin ID # that reported this vulnerability and create the vulnerability # using a specific class. Otherwise use the vulnerability class # for uncategorized vulnerabilities. classname = "UncategorizedVulnerability" if oid in use_openvas_db: classname = use_openvas_db[oid][0][0] # Create the Vulnerability object. try: clazz = globals()[classname] vuln = clazz(target, **kwargs) except Exception, e: t = format_exc() Logger.log_error_more_verbose( "Could not load vulnerability of type: %s" % classname) Logger.log_error_more_verbose(t) vuln = UncategorizedVulnerability(target, **kwargs) results.append(vuln) # Skip this result on error. except Exception, e: t = format_exc() Logger.log_error_verbose("Error parsing OpenVAS results: %s" % str(e)) Logger.log_error_more_verbose(t)
def parse_nikto_results(info, output_filename): """ Convert the output of a Nikto scan to the GoLismero data model. :param info: Data object to link all results to (optional). :type info: BaseUrl :param output_filename: Path to the output filename. The format should always be CSV. :type output_filename: :returns: Results from the Nikto scan, and the vulnerability count. :rtype: list(Data), int """ # Parse the scan results. # On error log the exception and continue. results = [] vuln_count = 0 hosts_seen = set() urls_seen = {} try: with open(output_filename, "rU") as f: csv_reader = reader(f) for row in csv_reader: try: # Each row (except for the first) has always # the same 7 columns, but some may be empty. if len(row) < 7: continue host, ip, port, vuln_tag, method, path, text = row[:7] # Report domain names and IP addresses. if ( (info is None or host != info.hostname) and host not in hosts_seen ): hosts_seen.add(host) if host in Config.audit_scope: results.append( Domain(host) ) if ip not in hosts_seen: hosts_seen.add(ip) if ip in Config.audit_scope: results.append( IP(ip) ) # Skip rows not informing of vulnerabilities. if not vuln_tag: continue # Calculate the vulnerable URL. if info is not None: target = urljoin(info.url, path) else: if port == 443: target = urljoin("https://%s/" % host, path) else: target = urljoin("http://%s/" % host, path) # Skip if out of scope. if target not in Config.audit_scope: continue # Report the URLs. if (target, method) not in urls_seen: url = Url(target, method) urls_seen[ (target, method) ] = url results.append(url) else: url = urls_seen[ (target, method) ] # Get the reference URLs. refs = extract_from_text(text) refs.difference_update(urls_seen.itervalues()) # Report the vulnerabilities. if vuln_tag == "OSVDB-0": kwargs = {"level": "informational"} else: kwargs = extract_vuln_ids( "%s: %s" % (vuln_tag, text)) kwargs["description"] = text if text else None kwargs["references"] = refs if "osvdb" in kwargs and "OSVDB-0" in kwargs["osvdb"]: tmp = list(kwargs["osvdb"]) tmp.remove("OSVDB-0") if tmp: kwargs["osvdb"] = tuple(tmp) else: del kwargs["osvdb"] if vuln_tag == "OSVDB-0": vuln = UncategorizedVulnerability(**kwargs) vuln.add_resource(url) else: vuln = VulnerableWebApp(url, **kwargs) results.append(vuln) vuln_count += 1 # On error, log the exception and continue. except Exception, e: Logger.log_error_verbose(str(e)) Logger.log_error_more_verbose(format_exc()) # On error, log the exception. except Exception, e: Logger.log_error_verbose(str(e)) Logger.log_error_more_verbose(format_exc())
def parse_nikto_results(info, output_filename): """ Convert the output of a Nikto scan to the GoLismero data model. :param info: Data object to link all results to (optional). :type info: BaseUrl :param output_filename: Path to the output filename. The format should always be CSV. :type output_filename: :returns: Results from the Nikto scan, and the vulnerability count. :rtype: list(Data), int """ # Parse the scan results. # On error log the exception and continue. results = [] vuln_count = 0 hosts_seen = set() urls_seen = {} try: with open(output_filename, "rU") as f: csv_reader = reader(f) for row in csv_reader: try: # Each row (except for the first) has always # the same 7 columns, but some may be empty. if len(row) < 7: continue host, ip, port, vuln_tag, method, path, text = row[:7] # Report domain names and IP addresses. if ((info is None or host != info.hostname) and host not in hosts_seen): hosts_seen.add(host) if host in Config.audit_scope: results.append(Domain(host)) if ip not in hosts_seen: hosts_seen.add(ip) if ip in Config.audit_scope: results.append(IP(ip)) # Skip rows not informing of vulnerabilities. if not vuln_tag: continue # Calculate the vulnerable URL. if info is not None: target = urljoin(info.url, path) else: if port == 443: target = urljoin("https://%s/" % host, path) else: target = urljoin("http://%s/" % host, path) # Skip if out of scope. if target not in Config.audit_scope: continue # Report the URLs. if (target, method) not in urls_seen: url = Url(target, method) urls_seen[(target, method)] = url results.append(url) else: url = urls_seen[(target, method)] # Get the reference URLs. refs = extract_from_text(text) refs.difference_update(urls_seen.itervalues()) # Report the vulnerabilities. if vuln_tag == "OSVDB-0": kwargs = {"level": "informational"} else: kwargs = extract_vuln_ids("%s: %s" % (vuln_tag, text)) kwargs["description"] = text if text else None kwargs["references"] = refs if "osvdb" in kwargs and "OSVDB-0" in kwargs["osvdb"]: tmp = list(kwargs["osvdb"]) tmp.remove("OSVDB-0") if tmp: kwargs["osvdb"] = tuple(tmp) else: del kwargs["osvdb"] if vuln_tag == "OSVDB-0": vuln = UncategorizedVulnerability(**kwargs) vuln.add_resource(url) else: vuln = VulnerableWebApp(url, **kwargs) results.append(vuln) vuln_count += 1 # On error, log the exception and continue. except Exception, e: Logger.log_error_verbose(str(e)) Logger.log_error_more_verbose(format_exc()) # On error, log the exception. except Exception, e: Logger.log_error_verbose(str(e)) Logger.log_error_more_verbose(format_exc())
def parse_results(openvas_results, ip = None): """ Convert the OpenVAS scan results to the GoLismero data model. :param openvas_results: OpenVAS scan results. :type openvas_results: list(OpenVASResult) :param ip: (Optional) IP address to link the vulnerabilities to. :type ip: IP | None :returns: Scan results converted to the GoLismero data model. :rtype: list(Data) """ # This is where we'll store the results. results = [] # Remember the hosts we've seen so we don't create them twice. hosts_seen = {} # Map of OpenVAS levels to GoLismero levels. OPV_LEVELS_TO_GLM_LEVELS = { 'debug' : 'informational', 'log' : 'informational', 'low' : "low", 'medium': 'middle', 'high' : "high", } # For each OpenVAS result... for opv in openvas_results: try: # Get the host. host = opv.host # Get or create the vulnerable resource. target = ip if host in hosts_seen: target = hosts_seen[host] elif not ip or ip.address != host: try: target = IP(host) except ValueError: target = Domain(host) hosts_seen[host] = target results.append(target) # Get the threat level. try: level = opv.threat.lower() except Exception: level = "informational" # Get the metadata. nvt = opv.nvt ##references = nvt.xrefs ##cvss = nvt.cvss ##cve = nvt.cve ##vulnerability_type = nvt.category # Get the vulnerability description. description = opv.description if not description: description = nvt.description if not description: description = nvt.summary if not description: description = None if opv.notes: description += "\n" + "\n".join( " - " + note.text for note in opv.notes ) # Prepare the vulnerability properties. kwargs = { "level": OPV_LEVELS_TO_GLM_LEVELS[level.lower()], "description": description, ##"cvss": cvss, ##"cve": cve, ##"references": references.split("\n"), } # Create the vulnerability instance. vuln = UncategorizedVulnerability(**kwargs) ##vuln.vulnerability_type = vulnerability_type # Link the vulnerability to the resource. if target is not None: target.add_vulnerability(vuln) # Skip on error. except Exception, e: t = format_exc() Logger.log_error_verbose( "Error parsing OpenVAS results: %s" % str(e)) Logger.log_error_more_verbose(t) continue # Add the vulnerability. results.append(vuln)