def __init__( self, address: str, port: int, cert_file: str, key_file: str, ca_file: str, stream_timeout: int, ): super().__init__(stream_timeout) self.socket = (address, port) if not Path(cert_file).exists(): raise OspdError(f'cert file {cert_file} not found') if not Path(key_file).exists(): raise OspdError(f'key file {key_file} not found') if not Path(ca_file).exists(): raise OspdError(f'CA file {ca_file} not found') validate_cacert_file(ca_file) protocol = ssl.PROTOCOL_SSLv23 self.tls_context = ssl.SSLContext(protocol) self.tls_context.verify_mode = ssl.CERT_REQUIRED self.tls_context.load_cert_chain(cert_file, keyfile=key_file) self.tls_context.load_verify_locations(ca_file)
def process_vts_params( scanner_vts: Element, ) -> Dict[str, Union[Dict[str, str], List]]: """Receive an XML object with the Vulnerability Tests an their parameters to be use in a scan and return a dictionary. @param: XML element with vt subelements. Each vt has an id attribute. Optional parameters can be included as vt child. Example form: <vt_selection> <vt_single id='vt1' /> <vt_single id='vt2'> <vt_value id='param1'>value</vt_value> </vt_single> <vt_group filter='family=debian'/> <vt_group filter='family=general'/> </vt_selection> @return: Dictionary containing the vts attribute and subelements, like the VT's id and VT's parameters. Example form: {'vt1': {}, 'vt2': {'value_id': 'value'}, 'vt_groups': ['family=debian', 'family=general']} """ vt_selection = {} # type: Dict filters = [] for vt in scanner_vts: if vt.tag == 'vt_single': vt_id = vt.attrib.get('id') vt_selection[vt_id] = {} for vt_value in vt: if not vt_value.attrib.get('id'): raise OspdError( 'Invalid VT preference. No attribute id' ) vt_value_id = vt_value.attrib.get('id') vt_value_value = vt_value.text if vt_value.text else '' vt_selection[vt_id][vt_value_id] = vt_value_value if vt.tag == 'vt_group': vts_filter = vt.attrib.get('filter', None) if vts_filter is None: raise OspdError('Invalid VT group. No filter given.') filters.append(vts_filter) vt_selection['vt_groups'] = filters return vt_selection
def start(self, stream_callback: StreamCallbackType): try: self.stream_callback = stream_callback self.server = ThreadedTlsSocketServer(self, self.socket) self._start_threading_server() except OSError as e: logger.error("Couldn't bind socket on %s:%s", self.socket[0], self.socket[1]) raise OspdError("Couldn't bind socket on {}:{}. {}".format( self.socket[0], str(self.socket[1]), e))
def __init__( self, address: str, port: int, cert_file: str, key_file: str, ca_file: str, stream_timeout: int, ): super().__init__(stream_timeout) self.socket = (address, port) if not Path(cert_file).exists(): raise OspdError('cert file {} not found'.format(cert_file)) if not Path(key_file).exists(): raise OspdError('key file {} not found'.format(key_file)) if not Path(ca_file).exists(): raise OspdError('CA file {} not found'.format(ca_file)) validate_cacert_file(ca_file) # Despite the name, ssl.PROTOCOL_SSLv23 selects the highest # protocol version that both the client and server support. In modern # Python versions (>= 3.4) it supports TLS >= 1.0 with SSLv2 and SSLv3 # being disabled. For Python > 3.5, PROTOCOL_SSLv23 is an alias for # PROTOCOL_TLS which should be used once compatibility with Python 3.5 # is no longer desired. if hasattr(ssl, 'PROTOCOL_TLS'): protocol = ssl.PROTOCOL_TLS else: protocol = ssl.PROTOCOL_SSLv23 self.tls_context = ssl.SSLContext(protocol) self.tls_context.verify_mode = ssl.CERT_REQUIRED self.tls_context.load_cert_chain(cert_file, keyfile=key_file) self.tls_context.load_verify_locations(ca_file)
def validate_cacert_file(cacert: str): """Check if provided file is a valid CA Certificate""" try: context = ssl.create_default_context(cafile=cacert) except AttributeError: # Python version < 2.7.9 return except IOError: raise OspdError('CA Certificate not found') from None try: not_after = context.get_ca_certs()[0]['notAfter'] not_after = ssl.cert_time_to_seconds(not_after) not_before = context.get_ca_certs()[0]['notBefore'] not_before = ssl.cert_time_to_seconds(not_before) except (KeyError, IndexError): raise OspdError('CA Certificate is erroneous') from None now = int(time.time()) if not_after < now: raise OspdError('CA Certificate expired') if not_before > now: raise OspdError('CA Certificate not active yet')
def start(self, stream_callback: StreamCallbackType): self._cleanup_socket() self._create_parent_dirs() try: self.stream_callback = stream_callback self.server = ThreadedUnixSocketServer(self, str(self.socket_path)) self._start_threading_server() except OSError as e: logger.error("Couldn't bind socket on %s", str(self.socket_path)) raise OspdError("Couldn't bind socket on {}. {}".format( str(self.socket_path), e)) if self.socket_path.exists(): self.socket_path.chmod(self.socket_mode)
def add( self, vt_id: str, name: str = None, vt_params: str = None, vt_refs: str = None, custom: str = None, vt_creation_time: str = None, vt_modification_time: str = None, vt_dependencies: str = None, summary: str = None, impact: str = None, affected: str = None, insight: str = None, solution: str = None, solution_t: str = None, solution_m: str = None, detection: str = None, qod_t: str = None, qod_v: str = None, severities: str = None, ) -> None: """ Add a vulnerability test information. IMPORTANT: The VT's Data Manager will store the vts collection. If the collection is considerably big and it will be consultated intensible during a routine, consider to do a deepcopy(), since accessing the shared memory in the data manager is very expensive. At the end of the routine, the temporal copy must be set to None and deleted. """ if not vt_id: raise OspdError('Invalid vt_id {}'.format(vt_id)) if self.vt_id_pattern.fullmatch(vt_id) is None: raise OspdError('Invalid vt_id {}'.format(vt_id)) if vt_id in self.vts: raise OspdError('vt_id {} already exists'.format(vt_id)) if name is None: name = '' vt = {'name': name} if custom is not None: vt["custom"] = custom if vt_params is not None: vt["vt_params"] = vt_params if vt_refs is not None: vt["vt_refs"] = vt_refs if vt_dependencies is not None: vt["vt_dependencies"] = vt_dependencies if vt_creation_time is not None: vt["creation_time"] = vt_creation_time if vt_modification_time is not None: vt["modification_time"] = vt_modification_time if summary is not None: vt["summary"] = summary if impact is not None: vt["impact"] = impact if affected is not None: vt["affected"] = affected if insight is not None: vt["insight"] = insight if solution is not None: vt["solution"] = solution if solution_t is not None: vt["solution_type"] = solution_t if solution_m is not None: vt["solution_method"] = solution_m if detection is not None: vt["detection"] = detection if qod_t is not None: vt["qod_type"] = qod_t elif qod_v is not None: vt["qod"] = qod_v if severities is not None: vt["severities"] = severities self.vts[vt_id] = vt
def process_target_element(cls, scanner_target: Element) -> Dict: """Receive an XML object with the target, ports and credentials to run a scan against. Arguments: Single XML target element. The target has <hosts> and <ports> subelements. Hosts can be a single host, a host range, a comma-separated host list or a network address. <ports> and <credentials> are optional. Therefore each ospd-scanner should check for a valid ones if needed. Example form: <target> <hosts>192.168.0.0/24</hosts> <ports>22</ports> <credentials> <credential type="up" service="ssh" port="22"> <username>scanuser</username> <password>mypass</password> </credential> <credential type="up" service="smb"> <username>smbuser</username> <password>mypass</password> </credential> </credentials> <alive_test></alive_test> <alive_test_ports></alive_test_ports> <reverse_lookup_only>1</reverse_lookup_only> <reverse_lookup_unify>0</reverse_lookup_unify> </target> Return: A Dict hosts, port, {credentials}, exclude_hosts, options]. Example form: { 'hosts': '192.168.0.0/24', 'port': '22', 'credentials': {'smb': {'type': type, 'port': port, 'username': username, 'password': pass, } }, 'exclude_hosts': '', 'finished_hosts': '', 'options': {'alive_test': 'ALIVE_TEST_CONSIDER_ALIVE', 'alive_test_ports: '22,80,123', 'reverse_lookup_only': '1', 'reverse_lookup_unify': '0', }, } """ if scanner_target: exclude_hosts = '' finished_hosts = '' ports = '' hosts = None credentials = {} # type: Dict options = {} for child in scanner_target: if child.tag == 'hosts': hosts = child.text if child.tag == 'exclude_hosts': exclude_hosts = child.text if child.tag == 'finished_hosts': finished_hosts = child.text if child.tag == 'ports': ports = child.text if child.tag == 'credentials': credentials = cls.process_credentials_elements(child) if child.tag == 'alive_test_methods': options['alive_test_methods'] = '1' cls.process_alive_test_methods(child, options) if child.tag == 'alive_test': options['alive_test'] = child.text if child.tag == 'alive_test_ports': options['alive_test_ports'] = child.text if child.tag == 'reverse_lookup_unify': options['reverse_lookup_unify'] = child.text if child.tag == 'reverse_lookup_only': options['reverse_lookup_only'] = child.text if hosts: return { 'hosts': hosts, 'ports': ports, 'credentials': credentials, 'exclude_hosts': exclude_hosts, 'finished_hosts': finished_hosts, 'options': options, } else: raise OspdError('No target to scan')