def get_item(vuln, test): finding = Finding( test=test, unique_id_from_tool=vuln["id"], nb_occurences=1, ) # Defining variables location = vuln["location"] # Endpoint # using url if "url" in location and location["url"] and location["url"] != "None": endpoint = Endpoint.from_uri(location["url"]) # fallback to using old way of creating endpoints elif "domain" in location and location["domain"] and location["domain"] != "None": endpoint = Endpoint(host=str(location["domain"])) else: # no domain, use ip instead if "ip" in location and location["ip"] and location["ip"] != "None": endpoint = Endpoint(host=str(location["ip"])) # check for protocol if ( "applicationProtocol" in location and location["applicationProtocol"] and location["applicationProtocol"] != "None" ): endpoint.protocol = location["applicationProtocol"] # check for port if ( "port" in location and location["port"] in location and location["port"] != "None" ): endpoint.port = location["port"] finding.unsaved_endpoints = [endpoint] # assigning endpoint # Title finding.title = vuln["name"] # Description + CVEs description = vuln["classification"] cves = "no match" if "CVE-NO-MATCH" not in vuln["kb"]["cves"]: finding.cve = vuln["kb"]["cves"][0] cves = "" for cve in vuln["kb"]["cves"]: cves += f"{cve}, " cves = cves[: len(cves) - 2] # removing the comma and the blank space finding.description = description + "; CVEs: " + cves finding.severity = vuln["severity"].title() # Date date_str = vuln["createdOn"] date_str = date_str[: len(date_str) - 3] + date_str[-2:] finding.date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%f%z") # Component Name and Version if ( "applicationCpe" in location and location["applicationCpe"] and location["applicationCpe"] != "None" ): cpe = CPE(location["applicationCpe"]) component_name = cpe.get_vendor()[0] + ":" if len( cpe.get_vendor()) > 0 else "" component_name += cpe.get_product()[0] if len( cpe.get_product()) > 0 else "" finding.component_name = component_name if component_name else None finding.component_version = ( cpe.get_version()[0] if len(cpe.get_version()) > 0 else None ) return finding
def get_items(self, tree, vulns, test): x = list() for nodes in tree.iter('nodes'): for node in nodes.iter('node'): host = dict() host['name'] = node.get('address') host['hostnames'] = set() host['os'] = "" host['services'] = list() host['vulns'] = self.parse_tests_type(node, vulns) for names in node.iter('names'): for name in list(names): host['hostnames'].add(name.text) for endpoints in node.iter('endpoints'): for endpoint in list(endpoints): svc = { 'protocol': endpoint.get('protocol'), 'port': endpoint.get('port'), 'status': endpoint.get('status'), } for services in endpoint.iter('services'): for service in list(services): svc['name'] = service.get('name') svc['vulns'] = self.parse_tests_type( service, vulns) for configs in service.iter('configurations'): for config in list(configs): if "banner" in config.get('name'): svc['version'] = config.get('name') host['services'].append(svc) x.append(host) dupes = {} for item in x: for service in item['services']: for vuln in service['vulns']: dupe_key = vuln['severity'] + vuln['name'] find = self.findings(dupe_key, dupes, test, vuln) endpoint = Endpoint(host=item['name']) if 'port' in service: endpoint.port = int(service['port']) find.unsaved_endpoints.append(endpoint) find.unsaved_tags = list() find.unsaved_tags = vuln['tags'] # manage findings by node only for vuln in host['vulns']: dupe_key = vuln['severity'] + vuln['name'] find = self.findings(dupe_key, dupes, test, vuln) find.unsaved_tags = list() find.unsaved_tags = vuln['tags'] return list(dupes.values())
def get_findings(self, filename, test: Test): content = filename.read() if type(content) is bytes: content = content.decode('utf-8') csv.field_size_limit(int(sys.maxsize / 10)) # the request/resp are big reader = csv.DictReader(io.StringIO(content)) dupes = dict() for row in reader: # manage severity from two possible columns 'Severity' and 'Risk' severity = 'Info' if 'Severity' in row: severity = self._convert_severity(row.get('Severity')) elif 'Risk' in row: severity = self._convert_severity(row.get('Risk')) # manage title from two possible columns 'Nme' and 'Plugin Name' title = row.get('Name') if title is None and 'Plugin Name' in row: title = row.get('Plugin Name') # special case to skip empty titles if not title: continue description = row.get('Synopsis') mitigation = str(row.get('Solution')) impact = row.get('Description', 'N/A') references = row.get('See Also', 'N/A') dupe_key = severity + title + row.get('Host', 'No host') + str( row.get('Port', 'No port')) + row.get('Synopsis', 'No synopsis') detected_cve = self._format_cve(str(row.get('CVE'))) cve = None if detected_cve: # FIXME support more than one CVE in Nessus CSV parser cve = detected_cve[0] if len(detected_cve) > 1: LOGGER.warning( "more than one CVE for a finding. NOT supported by Nessus CSV parser" ) if dupe_key in dupes: find = dupes[dupe_key] if 'Plugin Output' in row: find.description += row.get('Plugin Output') else: if 'Plugin Output' in row: description = description + str(row.get('Plugin Output')) find = Finding(title=title, test=test, cve=cve, description=description, severity=severity, mitigation=mitigation, impact=impact, references=references) # manage CVSS vector (only v3.x for now) if 'CVSS V3 Vector' in row and '' != row.get('CVSS V3 Vector'): find.cvssv3 = CVSS3('CVSS:3.0/' + str(row.get('CVSS V3 Vector')) ).clean_vector(output_prefix=False) # manage CPE data detected_cpe = self._format_cpe(str(row.get('CPE'))) if detected_cpe: # FIXME support more than one CPE in Nessus CSV parser if len(detected_cpe) > 1: LOGGER.warning( "more than one CPE for a finding. NOT supported by Nessus CSV parser" ) cpe_decoded = CPE(detected_cpe[0]) find.component_name = cpe_decoded.get_product()[0] if len( cpe_decoded.get_product()) > 0 else None find.component_version = cpe_decoded.get_version( )[0] if len(cpe_decoded.get_version()) > 0 else None find.unsaved_endpoints = list() dupes[dupe_key] = find # manage endpoints endpoint = Endpoint(host='localhost') if 'Host' in row: endpoint.host = row.get('Host') elif 'IP Address' in row: endpoint.host = row.get('IP Address') endpoint.port = row.get('Port') if 'Protocol' in row: endpoint.protocol = row.get('Protocol').lower() find.unsaved_endpoints.append(endpoint) return list(dupes.values())
def get_findings(self, file, test): tree = parse(file) root = tree.getroot() dupes = dict() if 'nmaprun' not in root.tag: raise ValueError("This doesn't seem to be a valid Nmap xml file.") report_date = None try: report_date = datetime.datetime.fromtimestamp( int(root.attrib['start'])) except ValueError: pass for host in root.findall("host"): host_info = "### Host\n\n" ip = host.find("address[@addrtype='ipv4']").attrib['addr'] if ip is not None: host_info += "**IP Address:** %s\n" % ip fqdn = host.find( "hostnames/hostname[@type='PTR']").attrib['name'] if host.find( "hostnames/hostname[@type='PTR']") is not None else None if fqdn is not None: host_info += "**FQDN:** %s\n" % fqdn host_info += "\n\n" for os in host.iter("os"): for os_match in os.iter("osmatch"): if 'name' in os_match.attrib: host_info += "**Host OS:** %s\n" % os_match.attrib[ 'name'] if 'accuracy' in os_match.attrib: host_info += "**Accuracy:** {0}%\n".format( os_match.attrib['accuracy']) host_info += "\n\n" for port_element in host.findall("ports/port"): protocol = port_element.attrib['protocol'] endpoint = Endpoint(host=ip, fqdn=fqdn, protocol=protocol) if 'portid' in port_element.attrib and port_element.attrib[ 'portid'].isdigit(): endpoint.port = int(port_element.attrib['portid']) # filter on open ports if 'open' != port_element.find("state").attrib.get('state'): continue title = "Open port: %s/%s" % (endpoint.port, endpoint.protocol) description = host_info description += "**Port/Protocol:** %s/%s\n" % ( endpoint.port, endpoint.protocol) service_info = "\n\n" if port_element.find('service') is not None: if 'product' in port_element.find('service').attrib: service_info += "**Product:** %s\n" % port_element.find( 'service').attrib['product'] if 'version' in port_element.find('service').attrib: service_info += "**Version:** %s\n" % port_element.find( 'service').attrib['version'] if 'extrainfo' in port_element.find('service').attrib: service_info += "**Extra Info:** %s\n" % port_element.find( 'service').attrib['extrainfo'] description += service_info description += "\n\n" # manage some script like https://github.com/vulnersCom/nmap-vulners for script_element in port_element.findall( 'script[@id="vulners"]'): self.manage_vulner_script(test, dupes, script_element, endpoint, report_date) severity = "Info" dupe_key = "nmap:" + str(endpoint.port) if dupe_key in dupes: find = dupes[dupe_key] if description is not None: find.description += description else: find = Finding( title=title, test=test, description=description, severity=severity, mitigation="N/A", impact="No impact provided", ) find.unsaved_endpoints = list() dupes[dupe_key] = find if report_date: find.date = report_date find.unsaved_endpoints.append(endpoint) return list(dupes.values())