def test_sync_service_from_host_name_to_host(self): self.init_db() workspace_str = "unittest" # Set up database with self._engine.session_scope() as session: host1 = self.create_host(session=session, workspace_str=workspace_str, address="192.168.1.1") host2 = self.create_host(session=session, workspace_str=workspace_str, address="::1") host_name1 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test1.com", scope=ScopeType.all) host_name2 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test.com", scope=ScopeType.all) session.add(Service(host_name=host_name1, protocol=ProtocolType.tcp, port=80, state=ServiceState.Open)) session.add(Service(host_name=host_name2, protocol=ProtocolType.tcp, port=80, state=ServiceState.Open)) self._domain_utils.add_host_host_name_mapping(session=session, host=host1, host_name=host_name1, mapping_type=DnsResourceRecordType.a | DnsResourceRecordType.ns) self._domain_utils.add_host_host_name_mapping(session=session, host=host2, host_name=host_name2, mapping_type=DnsResourceRecordType.aaaa | DnsResourceRecordType.ptr) with self._engine.session_scope() as session: result = session.query(Host).filter_by(address="192.168.1.1").one() self.assertEqual(1, len(result.services)) self.assertEqual(ProtocolType.tcp, result.services[0].protocol) self.assertEqual(80, result.services[0].port) result = session.query(Host).filter_by(address="::1").one() self.assertEqual(1, len(result.services)) self.assertEqual(ProtocolType.tcp, result.services[0].protocol) self.assertEqual(80, result.services[0].port)
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, user: str = None, password: str = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] url = service.get_urlparse() if url: os_command = [ command, '--color=never', '-v', '-a', '4', '--no-errors' ] if self._user_agent: os_command.extend(['--user-agent', self._user_agent]) else: os_command.extend( ['--user-agent', self._default_user_agent_string]) if self._cookies: os_command.extend(['--cookie', self._cookies[0]]) if self._http_proxy: os_command.extend(['--proxy', self.http_proxy.geturl()]) if user: password = password if password else "" os_command.append('-u={}:{}'.format(user, password)) os_command.append(service.get_urlparse().geturl()) collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, has_move: bool, user: str = None, password: str = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] address = service.address if address: os_command = [command, '-cleanup'] if has_move: os_command.append("-move") if user: password = password if password else "" os_command.extend(["-auth", "{}:{}".format(user, password)]) os_command.extend(['-url', service.get_urlparse().geturl()]) collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def create_service_commands( self, session: Session, service: Service, collector_name: CollectorName) -> List[BaseCollector]: """This method creates and returns a list of commands based on the given service. This method determines whether the command exists already in the database. If it does, then it does nothing, else, it creates a new Collector entry in the database for each new command as well as it creates a corresponding operating system command and attaches it to the respective newly created Collector class. :param session: Sqlalchemy session that manages persistence operations for ORM-mapped objects :param service: The service based on which commands shall be created. :param collector_name: The name of the collector as specified in table collector_name :return: List of Collector instances that shall be processed. """ result = [] if self.match_nmap_service_name(service): json_file = self.create_json_file_path(service=service) result = self._create_commands( session=session, service=service, collector_name=collector_name, protocol=ChangeProtocol.http, json_file=json_file, target=service.get_urlparse().geturl()) return result
def _extract_rpc_info(self, port_tag) -> None: """This method determines additional services disclosed by rpcinfo""" script = port_tag.findall("*/[@id='{}']".format( RpcInfoExtraInfoExtraction.RPC_INFO)) if len(script) > 0: tmp = XmlUtils.get_xml_attribute("output", script[0].attrib).split( os.linesep) for item in tmp: match = self._re_process.match(item) if match: port = match.group("port") protocol = match.group("protocol") protocol = Service.get_protocol_type(protocol) service_name = match.group("service") service = self._domain_utils.add_service( session=self._session, port=port, protocol_type=protocol, host=self._service.host, state=ServiceState.Internal, source=self._source_rpc_info, report_item=self._report_item) if service: service.nmap_service_name = service_name if not service.nmap_service_name \ else service.nmap_service_name service.state = ServiceState.Internal if service.state != ServiceState.Open else service.state
def _get_commands( self, session: Session, service: Service, collector_name: CollectorName, command: str, wordlists: List[str], user: str = None, password: str = None, additional_arguments: List[str] = []) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] url = service.get_urlparse() number_threads = 1 if self._delay.sleep_active() else 10 if url: for wordlist in wordlists: if not os.path.isfile(wordlist): raise FileNotFoundError( "word list '{}' does not exist!".format(wordlist)) os_command = [ command, self._mode, '-z', '-t', number_threads, '-w', wordlist ] os_command += additional_arguments # Add additional settings, if available if self._user_agent: os_command.extend(['-a', '{}'.format(self._user_agent)]) else: os_command.extend( ['-a', '{}'.format(self._default_user_agent_string)]) if self._cookies: os_command.extend(['-c', "; ".join(self._cookies)]) else: os_command.append("-k") if self._http_proxy: os_command.extend(['-p', self.http_proxy.geturl()]) if user: os_command.extend(['-U', user]) if password: os_command.extend(['-P', password]) os_command += ['-u', service.get_urlparse().geturl()] collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _create_test_data(self, session: Session, workspace_str: str = "unittest") -> Host: source = self.create_source(session=session, source_str="dnshost") self.create_network(session=session, network="192.168.1.0/24", scope=ScopeType.all, workspace_str=workspace_str) host1 = self.create_host(session=session, workspace_str=workspace_str, address="192.168.1.1") host2 = self.create_host(session=session, workspace_str=workspace_str, address="192.168.1.2") session.add( Service(host=host1, protocol=ProtocolType.tcp, port=80, state=ServiceState.Open)) session.add( Service(host=host2, protocol=ProtocolType.tcp, port=80, state=ServiceState.Open)) # self.create_service(session=session, workspace_str=workspace_str, address="192.168.1.1", port=80) host_name1 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test1.com", scope=ScopeType.all) host_name2 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test.com", scope=ScopeType.all) self._domain_utils.add_host_host_name_mapping( session=session, host=host1, host_name=host_name1, source=source, mapping_type=DnsResourceRecordType.a | DnsResourceRecordType.ns) self._domain_utils.add_host_host_name_mapping( session=session, host=host2, host_name=host_name2, source=source, mapping_type=DnsResourceRecordType.ptr)
def test_delete_service(self): self.init_db() workspace_str = "unittest" # Set up database with self._engine.session_scope() as session: host1 = self.create_host(session=session, workspace_str=workspace_str, address="192.168.1.1") host2 = self.create_host(session=session, workspace_str=workspace_str, address="::1") self.create_service(session=session, workspace_str=workspace_str, address="10.0.0.1", port=443) host_name1 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test1.com", scope=ScopeType.all) host_name2 = self.create_hostname(session=session, workspace_str=workspace_str, host_name="www.test.com", scope=ScopeType.all) session.add(Service(host_name=host_name1, protocol=ProtocolType.tcp, port=80, state=ServiceState.Open)) session.add(Service(host=host2, protocol=ProtocolType.tcp, port=8080, state=ServiceState.Open)) self._domain_utils.add_host_host_name_mapping(session=session, host=host1, host_name=host_name1, mapping_type=DnsResourceRecordType.a | DnsResourceRecordType.ns) self._domain_utils.add_host_host_name_mapping(session=session, host=host2, host_name=host_name2, mapping_type=DnsResourceRecordType.aaaa | DnsResourceRecordType.ptr) # Delete services with self._engine.session_scope() as session: result = session.query(Service) \ .join(Host) \ .filter(Host.address == "192.168.1.1").one() session.delete(result) result = session.query(Service) \ .join((HostName, Service.host_name)) \ .join((DomainName, HostName.domain_name)) \ .filter(HostName.name == "www").filter(DomainName.name == "test.com").filter(Service.port == 8080).one() session.delete(result) # Check database with self._engine.session_scope() as session: result = session.query(Service).all() self.assertEqual(1, len(result)) self.assertEqual(443, result[0].port) self.assertIsNotNone(result[0].host) self.assertEqual("10.0.0.1", result[0].host.address)
def test_service_primary_key_update(self): self.init_db() # Setup database with self._engine.session_scope() as session: host = self.create_host(session=session) session.add(Service(host=host, port=80, protocol=ProtocolType.tcp, state=ServiceState.Open)) session.add(Service(host=host, port=443, protocol=ProtocolType.tcp, state=ServiceState.Open)) session.add(Service(host=host, port=8080, protocol=ProtocolType.tcp, state=ServiceState.Open)) # Update port with self.assertRaises(Exception): with self._engine.session_scope() as session: service = session.query(Service).filter_by(port=80, protocol=ProtocolType.tcp).one() service.port = 161 # Update protocol with self.assertRaises(Exception): with self._engine.session_scope() as session: service = session.query(Service).filter_by(port=80, protocol=ProtocolType.tcp).one() service.protocol = ProtocolType.udp # Update both with self.assertRaises(Exception): with self._engine.session_scope() as session: service = session.query(Service).filter_by(port=80, protocol=ProtocolType.tcp).one() service.port = 161 service.protocol = ProtocolType.udp # Perform legit update with self._engine.session_scope() as session: service = session.query(Service).filter_by(port=80, protocol=ProtocolType.tcp).one() service.state = ServiceState.Closed service.nmap_service_name = "https" service.nmap_service_confidence = 1 service.nmap_service_name_original = "https?" service.nmap_service_state_reason = "reason" service.nmap_product = "nmap_product" service.nmap_version = "nmap_version" service.nmap_extra_info = "nmap_extra_info" service.nmap_os_type = "nmap_os_type" service.nmap_tunnel = "nmap_tunnel" service.nessus_service_name = "nessus_service_name" service.nessus_service_confidence = 1
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, user_file: str = None, password_file: str = None, user: str = None, password: str = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] url = service.get_urlparse() if url: os_command = [ command, '--no-banner', '--disable-tls-checks', '-t', '5', '-e', 'vp,vt' ] if self._user_agent: os_command.extend(['--user-agent', self._user_agent]) else: os_command.extend( ['--user-agent', self._default_user_agent_string]) if self._cookies: os_command.extend(['--cookie', self._cookies[0]]) if self._http_proxy: os_command.extend(['-r', self.http_proxy.geturl()]) if user_file: os_command.extend(['--usernames', user_file]) if password_file: os_command.extend(['--wordlist', password_file]) os_command.extend(['--url', service.get_urlparse().geturl()]) collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _analyze_fingerprint(self, service: Service, port_tag: str) -> None: """ This method analyzes the results of the NSE script fingerprint and updates the given service accordingly """ script = port_tag.findall("*/[@id='fingerprint-strings']") if script and service.nmap_service_name not in ["http", "https"]: output = DatabaseImporter.get_xml_attribute( "output", script[0].attrib) if self._re_http_response.findall(output): print("[I] update service name '{}' of {}:{} ({}) to 'http'". format(service.nmap_service_name, service.host.address, service.port, service.protocol.name.lower()), file=self._stdout) service.nmap_service_name = "https" if service.tls else "http"
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, user: str = None, password: str = None, output_file: str = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] url = service.get_urlparse().geturl() url = url if url[-1] == "/" else url + "/" if url: os_command = [ command, "--scope", "url", "--scan-force", "normal", "--format", "txt", "--no-bugreport", "--flush-attacks", "--flush-session" ] if self._user_agent: os_command += ['--user-agent', '{}'.format(self._user_agent)] else: os_command += [ '--user-agent', '{}'.format(self._default_user_agent_string) ] if user: password = password if password else "" os_command += [ "--auth-type", "basic", "--auth-cred", "{}%{}".format(user, password) ] if self._http_proxy: os_command += ['--proxy', self.http_proxy.geturl()] if output_file: os_command += [ "--output", ExecutionInfoType.binary_output_file.argument ] os_command += ["-u", url] collector = self._get_or_create_command(session, os_command, collector_name, service=service, binary_file=output_file) collectors.append(collector) return collectors
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] wordlists = self._wordlist_files if self._wordlist_files else [ self._wordlist_kiterunner ] for wordlist in wordlists: os_command = [ command, 'scan', '--output', 'text', '--kitebuilder-full-scan', '-q', '-w', wordlist, '-x', 10, '--user-agent', self._user_agent if self._user_agent else self.default_user_agent, service.get_urlparse().geturl() ] collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, user: str = None, password: str = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] if (service.host and service.host.version == 4) or service.host_name: url = service.get_urlparse() os_command = [command] if self._user_agent: os_command.extend( ['-useragent', '{}'.format(self._user_agent)]) else: os_command.extend([ '-useragent', '{}'.format(self._default_user_agent_string) ]) if user: password = password if password else "" os_command.extend(["-id", "{}:{}".format(user, password)]) if self._cookies: os_command.extend(['-c', self._cookies]) if service.nmap_tunnel == 'ssl': os_command.append('-ssl') if self._http_proxy: os_command.extend(['-useproxy', self.http_proxy.geturl()]) os_command.extend([ '-Tuning', '12357b', '-no404', '-nointeractive', '-host', url.geturl() ]) collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _get_commands(self, session: Session, service: Service, collector_name: CollectorName, command: str, user: str=None, password: str=None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] address = service.address if address: os_command = [command, '--batch', '--disable-coloring', '--forms', '--threads', '2', '--risk', '3', '--level', '5', '--time-sec', '10', '--crawl', '5', '--technique', 'BEUSTQ', '-u', service.get_urlparse().geturl()] if self._user_agent: os_command.append('--user-agent={}'.format(self._user_agent)) else: os_command.append('--user-agent={}'.format(self._default_user_agent_string)) if user: password = password if password else "" os_command.extend(["--auth-type=Basic", "--auth-cred={}:{}".format(user, password)]) if self._cookies: os_command.append('--cookie={}'.format(self._cookies[0])) if self._http_proxy: os_command.append('--proxy={}'.format(self.http_proxy.geturl())) collector = self._get_or_create_command(session, os_command, collector_name, service=service) collectors.append(collector) return collectors
def _get_commands(self, session: Session, collector_name: CollectorName, workspace: Workspace, output_path: str, input_file: str = None, host: Host = None, network: Network = None, host_name: HostName = None, email: Email = None, company: Company = None, service: Service = None) -> List[BaseCollector]: """Returns a list of commands based on the provided information.""" collectors = [] python3_command = self._path_python3 kisimport_command = self._path_kisimport if not self.api_credentials_available(): logger.warning("api keys not set in config file '{}' for " "collector {}".format(self._api_config.full_path, collector_name.name)) return collectors if host: target = host.address elif network: target = network.network elif host_name: target = host_name.domain_name.name elif email: target = email.email_address elif company: target = company.name elif service: target = service.get_urlparse().geturl() else: raise ValueError("parameter host, host_name, email, company, or service is required") if not os.path.isfile(kisimport_command): raise FileNotFoundError("script '{}' does not exist".format(kisimport_command)) # Create command os_command = [python3_command, kisimport_command, "kiscollect", '-w', workspace.name, "-O", ExecutionInfoType.output_path.argument, "--id", ExecutionInfoType.command_id.argument] if input_file: os_command += [self._argument_name, ExecutionInfoType.input_file.argument] else: os_command += [self._argument_name, target] # Add command to database command = self._get_or_create_command(session, os_command, collector_name, host=host, network=network, host_name=host_name, email=email, company=company, output_path=output_path, service=service, input_file=input_file) command.execution_info[ExecutionInfoType.command_id.name] = str(command.id) collectors.append(command) return collectors
def import_content(self, xml_content: str) -> None: """ This method imports the given XML content into the database. :param xml_content: The XML content :return: """ try: root = ET.fromstring(xml_content) except xml.etree.ElementTree.ParseError: root = ET.fromstring(xml_content + "</nmaprun>") source = Engine.get_or_create(self._session, Source, name=self._source) re_domain = re.compile("^Domain: (?P<domain>.+?), Site: .*$") for host_tag in root.findall('host'): host = None ipv4_address = None ipv6_address = None mac_address = None status_tag = host_tag.findall("status") host_up = None host_up_reason = None if status_tag: host_up = DatabaseImporter.get_xml_attribute( "state", status_tag[0].attrib) == "up" host_up_reason = DatabaseImporter.get_xml_attribute( "reason", status_tag[0].attrib) port_tags = host_tag.findall('*/port') for addr in host_tag.findall('address'): type = DatabaseImporter.get_xml_attribute( "addrtype", addr.attrib) if type == "ipv4": ipv4_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) resource_type = DnsResourceRecordType.a if type == "ipv6": ipv6_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) resource_type = DnsResourceRecordType.aaaa if type == "mac": mac_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) if not host_up: print("[I] host '{}' is down and thus, is not imported.". format(ipv4_address), file=self._stdout) continue if ipv4_address and ipv6_address: raise NotImplementedError( "case IPv4 and IPv6 address available at the same time is not implemented" ) host_created = False for port in port_tags: port_state_tag = port.findall("state[1]")[0].attrib port_state = DatabaseImporter.get_xml_attribute( "state", port_state_tag) extra_reason = DatabaseImporter.get_xml_attribute( "reason", port_state_tag) service_protocol = DatabaseImporter.get_xml_attribute( "protocol", port.attrib) service_protocol = Service.get_protocol_type(service_protocol) port_state = Service.get_service_state(port_state) if port_state in self._service_states: if not host_created: host_created = True # at least one service exists and therefore, we create the host host = self._create_host(source, host_up, host_up_reason, host_tag, ipv4_address, ipv6_address, mac_address) service_port = DatabaseImporter.get_xml_attribute( "portid", port.attrib) service = self._domain_utils.add_service( session=self._session, port=service_port, protocol_type=service_protocol, state=port_state, host=host, source=source, report_item=self._report_item) service.nmap_service_state_reason = extra_reason services = port.findall("service[1]") if len(services) == 1: service_tag = services[0] nmap_service_confidence = DatabaseImporter.get_xml_attribute( "conf", service_tag.attrib) nmap_service_confidence = int(nmap_service_confidence) \ if nmap_service_confidence is not None else None service_name = DatabaseImporter.get_xml_attribute( "name", service_tag.attrib) service.nmap_service_name_original = service_name tunnel = DatabaseImporter.get_xml_attribute( "tunnel", service_tag.attrib) if service_name == "http" and tunnel == "ssl": service_name = DatabaseImporter.HTTPS_SERVICE_NAME[ 0] service.nmap_service_name = service_name service.nmap_service_confidence = nmap_service_confidence service.nmap_product = DatabaseImporter.get_xml_attribute( "product", service_tag.attrib) service.nmap_version = DatabaseImporter.get_xml_attribute( "version", service_tag.attrib) service.nmap_os_type = DatabaseImporter.get_xml_attribute( "ostype", service_tag.attrib) service.nmap_tunnel = DatabaseImporter.get_xml_attribute( "tunnel", service_tag.attrib) if service.nmap_os_type and host.os_family is None: os = service.nmap_os_type.lower() host.os_family = "windows" if " windows " in os else os if not service.nmap_tunnel and service_name == DatabaseImporter.HTTPS_SERVICE_NAME[ 0]: service.nmap_tunnel = "ssl" for item in ["debian", "ubuntu"]: if service.nmap_version and item in service.nmap_version.lower( ) and host.os_family is None: host.os_family = "linux" hostname = DatabaseImporter.get_xml_attribute( "hostname", service_tag.attrib) hostname_levels = len( hostname.split(".")) if hostname else 0 if hostname: host_name = self._domain_utils.add_domain_name( session=self._session, workspace=host.workspace, item=hostname, source=source, verify=True, report_item=self._report_item) if not host_name: print("[I] ignoring host name: {}".format( hostname.lower()), file=self._stdout) else: self._domain_utils.add_host_host_name_mapping( self._session, host=host, host_name=host_name, source=source, mapping_type=resource_type, report_item=self._report_item) extra_info = DatabaseImporter.get_xml_attribute( "extrainfo", service_tag.attrib) if extra_info: service.nmap_extra_info = extra_info match_domain = re_domain.match(extra_info) if match_domain: domain = match_domain.group("domain") domain_level = len(domain) if hostname_levels == 1 and domain_level > 1: host_name = self._domain_utils.add_domain_name( session=self._session, workspace=self._workspace, item="{}.{}".format(hostname, domain), source=source, verify=True, report_item=self._report_item) else: host_name = self._domain_utils.add_domain_name( session=self._session, workspace=self._workspace, item=domain, source=source, verify=True, report_item=self._report_item) if host_name: self._domain_utils.add_host_host_name_mapping( self._session, host=host, host_name=host_name, source=source, mapping_type=resource_type, report_item=self._report_item) self._analyze_fingerprint(service, port) # Extract additional information from XML self.extractor.execute(session=self._session, workspace=self._workspace, domain_utils=self._domain_utils, ip_utils=self._ip_utils, service=service, source=source, report_item=self._report_item, service_tag=extra_info, host_tag=host_tag, port_tag=port) elif len(services) > 1: raise NotImplementedError( "more than one service identified. this case has not " "been implemented!") if not host_created: print( "[I] host '{}' did not have any services to import and thus, " "is ignored".format(ipv4_address), file=self._stdout) # if not host_created: # host = self._create_host(source, # host_up, # host_up_reason, # host_tag, # ipv4_address, # ipv6_address, # mac_address) os_tag = host_tag.find("os") if host and os_tag is not None: for item in os_tag.findall("*/osclass"): accuracy = DatabaseImporter.get_xml_attribute( "accuracy", item.attrib) if accuracy and int(accuracy) == 100: osfamily = DatabaseImporter.get_xml_attribute( "osfamily", item.attrib) host.os_family = osfamily.lower( ) if osfamily is not None and host.os_family is None else None
def _import_file(self, input_file: str) -> None: """ This method imports the given file into the database. :param input_file: The file to be imported :return: """ tree = ET.parse(input_file) root = tree.getroot() source = Engine.get_or_create(self._session, Source, name=self._source) for host_tag in root.findall('*/ReportHost'): host = None properties = host_tag.find("HostProperties") ip_address = DatabaseImporter.get_xml_attribute( "name", host_tag.attrib) if properties: ipv4_address = properties.find("*/[@name='host-ip']") ipv4_address = ipv4_address.text if ipv4_address is not None else ip_address os_info = properties.find("*/[@name='os']") os_info = os_info.text if os_info is not None else None host = self._ip_utils.add_host(session=self._session, workspace=self._workspace, address=ipv4_address, source=source, report_item=self._report_item) host.os_family = os_info.lower( ) if os_info is not None and host.os_family is None else None if host: for item in host_tag.findall("ReportItem"): port = int( DatabaseImporter.get_xml_attribute( "port", item.attrib)) severity = int( DatabaseImporter.get_xml_attribute( "severity", item.attrib)) protocol = DatabaseImporter.get_xml_attribute( "protocol", item.attrib) service_name = DatabaseImporter.get_xml_attribute( "svc_name", item.attrib) if service_name: if service_name[-1] == '?': confidence = 7 service_name = service_name[:-1] else: confidence = 10 else: confidence = None protocol = Service.get_protocol_type(protocol) if protocol: if port > 0: plugin_id = DatabaseImporter.get_xml_attribute( "pluginID", item.attrib) plugin_name = DatabaseImporter.get_xml_attribute( "pluginName", item.attrib) nmap_tunnel = "ssl" if plugin_id == "56984" and \ plugin_name == "SSL / TLS Versions Supported" else None service = self._domain_utils.add_service( session=self._session, port=port, protocol_type=protocol, state=ServiceState.Open, nessus_service_confidence=confidence, nessus_service_name=service_name, host=host, nmap_tunnel=nmap_tunnel, source=source, report_item=self._report_item) # add vulnerability information if severity > 0: description = XmlUtils.get_element_text( item, "description") cve = XmlUtils.get_element_text(item, "cve") cvss_base_score = XmlUtils.get_element_text( item, "cvss_base_score") cvss3_base_score = XmlUtils.get_element_text( item, "cvss3_base_score") row = [[ cve, cvss3_base_score, cvss_base_score, "{} - {}".format(plugin_id, plugin_name), description ]] vulnerability = self._domain_utils.get_list_as_csv( row) self._domain_utils.add_additional_info( session=self._session, service=service, name="CVEs", values=vulnerability, source=source, report_item=self._report_item)
def import_content(self, xml_content: str) -> None: """ This method imports the given XML content into the database. :param xml_content: The XML content :return: """ try: root = ET.fromstring(xml_content) except xml.etree.ElementTree.ParseError: return source = Engine.get_or_create(self._session, Source, name=self._source) for host_tag in root.findall('host'): ipv4_address = None ipv6_address = None mac_address = None for addr in host_tag.findall('address'): type = DatabaseImporter.get_xml_attribute( "addrtype", addr.attrib) if type == "ipv4": ipv4_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) elif type == "ipv6": ipv6_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) elif type == "mac": mac_address = DatabaseImporter.get_xml_attribute( "addr", addr.attrib) if ipv4_address: host = self._ip_utils.add_host(session=self._session, workspace=self._workspace, address=ipv4_address, source=source, report_item=self._report_item) elif ipv6_address: host = self._ip_utils.add_host(session=self._session, workspace=self._workspace, address=ipv6_address, source=source, report_item=self._report_item) else: raise NotImplementedError( "the case that the host neither has an IPv4 nor an IPv6 address is not " "implemented!") host.mac_address = mac_address for port in host_tag.findall('*/port'): port_state_tag = port.findall("state[1]")[0].attrib port_state = DatabaseImporter.get_xml_attribute( "state", port_state_tag) port_state = Service.get_service_state(port_state) if port_state == ServiceState.Open: service_protocol = DatabaseImporter.get_xml_attribute( "protocol", port.attrib) service_port = DatabaseImporter.get_xml_attribute( "portid", port.attrib) service_protocol = Service.get_protocol_type( service_protocol) service = self._domain_utils.add_service( session=self._session, port=service_port, protocol_type=service_protocol, state=port_state, host=host, source=source, report_item=self._report_item) service.nmap_service_state_reason = DatabaseImporter.get_xml_attribute( "reason", port_state_tag) if port.findall("service[@name='ssl']"): service.nmap_tunnel = "ssl"