class OpenVASScanner(Scanner): name = 'OpenVAS' def __init__(self): connection = TLSConnection(hostname=config['HOST_NAME'], port=config['PORT'], certfile=None, cafile=None, keyfile=None, password=None, timeout=25) transform = EtreeTransform() self.gmp = Gmp(connection, transform=transform) self.storage_service = StorageService() # Login try: self.gmp.authenticate(config['OPENVAS_USERNAME'], config['OPENVAS_PASSWORD']) except: print(f'[{self.name}] Not able to connect to the {self.name}: ', sys.exc_info()) return def start(self, scan_name, target): print(f'[{self.name}] Starting Scan for Target: {target}') try: return self.scan(scan_name, target) except: print(f'[{self.name}] Not able to connect to the {self.name}: ', sys.exc_info()) return False def scan(self, scan_name, target): print(f'[{self.name}] Scan Name: {scan_name}') address = self._get_address(target) # Creating Target target_response = self.gmp.create_target( name=scan_name, hosts=[address], port_list_id='33d0cd82-57c6-11e1-8ed1-406186ea4fc5') # print('target_response') #pretty_print(target_response) target_id = target_response.get('id') if not target_id: print(f'[{self.name}] could not able to create target: ', target_response.get('status_text')) return False # target_id = '69ca3c65-af09-48b8-bb3a-59e2e6cccb96' print(f'[{self.name}] Target Created: {target_id}') scan_data = self.storage_service.get_by_name(scan_name) if not scan_data: scan_data = { 'scan_name': scan_name, 'scan_id': '', 'target': target, 'status': '' } self.storage_service.add(scan_data) scan_data['OPENVAS'] = { 'openvas_id': target_id, 'target_id': target_id, 'scan_status': { 'status': 'INPROGRESS' } } self.storage_service.update_by_name(scan_name, scan_data) time.sleep(4) self._create_task(scan_name) return scan_data def _create_task(self, scan_name): scan_data = self.storage_service.get_by_name(scan_name) openvas_id = scan_data['OPENVAS']['openvas_id'] scan_config_id = config['SCAN_CONFIG_ID'] scanner_id = config['SCANNER_ID'] report_format_id = config['REPORT_FORMAT_ID'] # Creating Task task_response = self.gmp.create_task(name=scan_name, config_id=scan_config_id, target_id=openvas_id, scanner_id=scanner_id) # print('task_response') # pretty_print(task_response) task_id = task_response.get('id') print(f'[{self.name}] Created Task: with : {task_id}') # Starting Task start_task_response = self.gmp.start_task(task_id) # print('start_task_response') # pretty_print(start_task_response) report_id = start_task_response[0].text scan_data['OPENVAS']['report_id'] = report_id scan_data['OPENVAS']['report_format_id'] = report_format_id scan_data['OPENVAS']['scan_config_id'] = scan_config_id scan_data['OPENVAS']['scanner_id'] = scanner_id scan_data['OPENVAS']['task_id'] = task_id self.storage_service.update_by_name(scan_name, scan_data) return scan_data def get_scan_status(self, scan_name, scan_status_list=[]): if not self.is_valid_scan(scan_name): return False scan_data = self.storage_service.get_by_name(scan_name) scan_status = scan_data.get('OPENVAS', {}).get('scan_status', {}) openvas_id = scan_data.get('OPENVAS', {})['openvas_id'] target = scan_data['target'] task_id = scan_data.get('OPENVAS', {})['task_id'] print(f'[{self.name}] Getting Scan Status for Target: {target}') print(f'[{self.name}] Scan Name: {scan_name}') print(f'[{self.name}] Scan Id: {openvas_id}') try: scan_info = self.gmp.get_task(task_id) status = scan_info.xpath('task/status/text()') progress = scan_info.xpath('task/progress/text()') except: print(f'[{self.name}] Could not get the scan {openvas_id}: ', sys.exc_info()) return False scan_status['status'] = 'COMPLETE' if status[ 0] == 'Done' else 'INPROGRESS' if status[ 0] == 'Running' else status[0] scan_status['progress'] = progress[0] scan_data['OPENVAS']['scan_status'] = scan_status self.storage_service.update_by_name(scan_name, scan_data) if scan_status['status'] is 'COMPLETE': print(f'[{self.name}] Scan {scan_name} Completed') scan_status_list.append({ 'scanner': self.name, 'status': f'{scan_status["status"]} {progress[0]}%' }) return scan_status_list def get_scan_results(self, scan_name, oscan_results={}): if not self.is_valid_scan(scan_name): return False scan_data = self.storage_service.get_by_name(scan_name) # if scan_data.get('OPENVAS', {}).get('scan_status').get('status', None) != 'COMPLETE': # print(f'[{self.name}] Scan is in progress') # return False openvas_id = scan_data.get('OPENVAS', {})['openvas_id'] report_id = scan_data.get('OPENVAS', {})['report_id'] report_format_id = scan_data.get('OPENVAS', {})['report_format_id'] try: report_response = self.gmp.get_report( report_id=report_id, report_format_id=report_format_id) # print('report_response') #pretty_print(report_response) except: print(f'[{self.name}] Could not get the scan {openvas_id}: ', sys.exc_info()) return False self._process_results(report_response, oscan_results) return oscan_results def _process_results(self, report_response, oscan_results={}): report_response_str = ElementTree.tostring(report_response, encoding='unicode') report_response_dict = xmltodict.parse(report_response_str) report_results = report_response_dict.get( 'get_reports_response', {}).get('report', {}).get('report', {}).get('results', {}).get('result', []) # print(json.dumps(report_results, indent=2)) # print('report_results', report_results) for vuln in report_results: name = vuln.get('name') #print('name: ', name) if oscan_results.get(name): # print('--- Duplicate name: ', name) continue nvt = vuln.get('nvt', {}) scan_result = {} scan_result['name'] = name scan_result['severity'] = float(nvt.get('cvss_base', 0)) scan_result['risk'] = vuln.get('threat') scan_result['cve_id'] = nvt.get( 'cve', 'N/A') if nvt.get('cve') != 'NOCVE' else 'N/A' scan_result['description'] = vuln.get('description') scan_result['solution'] = 'N/A' scan_result['reported_by'] = 'OpenVAS' oscan_results[name] = scan_result return oscan_results def is_valid_scan(self, scan_name): scan_data = self.storage_service.get_by_name(scan_name) if not scan_data: print(f'[{self.name}] Invalid Scan Name: {scan_name}') return False if not scan_data.get('OPENVAS'): print(f'[{self.name}] No Scan Details found for {scan_name}') return False return True def pause(self, scan_name): if not self.is_valid_scan(scan_name): return False scan = self.storage_service.get_by_name(scan_name) task_id = scan['OPENVAS']['task_id'] response = self.gmp.stop_task(task_id) #GMP does not support pause print(f'[{self.name}] scan paused ') return response def resume(self, scan_name): if not self.is_valid_scan(scan_name): return False scan = self.storage_service.get_by_name(scan_name) task_id = scan['OPENVAS']['task_id'] response = self.gmp.resume_task(task_id) print(f'[{self.name}] scan resumed ') return response def stop(self, scan_name): if not self.is_valid_scan(scan_name): return False scan = self.storage_service.get_by_name(scan_name) task_id = scan['OPENVAS']['task_id'] response = self.gmp.stop_task(task_id) print(f'[{self.name}] scan stopped ') return response def remove(self, scan_name): if not self.is_valid_scan(scan_name): return False scan = self.storage_service.get_by_name(scan_name) task_id = scan['OPENVAS']['task_id'] response = self.gmp.delete_task(task_id, ultimate=False) print(f'[{self.name}] scan removed ') return response def list_scans(self): self.tasks = self.gmp.get_tasks() task_names = self.tasks.xpath('task/name/text()') print("Available scan names from openvas") pretty_print(task_names) return task_names def start_sp(self, scan_name): if not self.is_valid_scan(scan_name): return False scan_data = self.storage_service.get_by_name(scan_name) print(f'[{self.name}] Starting Scan: {scan_name}') task_id = scan_data['OPENVAS']['task_id'] start_task_response = self.gmp.start_task(task_id) print(f'[{self.name}] Task started') report_id = start_task_response[0].text scan_data['OPENVAS'] = { 'report_id': report_id, 'scan_status': { 'status': 'INPROGRESS' } } self.storage_service.update_by_name(scan_name, scan_data)
class OpenvasRemote: def __init__(self, path, connection, transform): self.path = path self.connection = connection self.gmp = Gmp(connection=connection, transform=transform) def create_task(self, task_name, config_id, target_id, scanner_id, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.create_task( task_name, config_id, target_id, scanner_id) pretty_print(response) id = response.xpath('@id') return id[0] except GvmError as e: print(e) return 'bad' def create_target(self, target_name, targets_list, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.create_target( target_name, hosts=targets_list,alive_test=AliveTest.CONSIDER_ALIVE) pretty_print(response) if(response.xpath("@status_text")[0] == 'Target exists already'): with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_targets( filter="name={0}".format(target_name)) target_id = response.xpath('target/@id')[0] return target_id else: id = response.xpath('@id')[0] return id except GvmError as e: print(e) return 'bad' #this also delete all the reports def delete_all_tasks(self, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_tasks() for task in response.xpath('task'): task_id = task.xpath('@id')[0] response = self.gmp.delete_task(task_id) pretty_print(response) result = {'status': 'good'} return result except GvmError as e: print(e) result = {'status': 'bad'} return result def delete_all_targets(self, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_targets() for target in response.xpath('target'): target_id = target.xpath('@id')[0] response = self.gmp.delete_target(target_id) pretty_print(response) result = {'status': 'good'} return result except GvmError as e: print(e) result = {'status': 'bad'} return result @staticmethod def get_full_and_fast_config_id(): return 'daba56c8-73ec-11df-a475-002264764cea' @staticmethod def get_default_openvas_scanner_id(): return '08b69003-5fc2-4037-a479-93b440211c73' def get_report(self, id, target_list, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_report(id) running_status = response.xpath( 'report/report/scan_run_status/text()')[0] if(running_status == 'Done'): print(response.xpath('report/@id')[0]) report = {} hosts = [] for IP_address in target_list: host = {} host['ip_address'] = IP_address host['results'] = [] host['results_count'] = 0 hosts.append(host) for report_result in response.xpath('report/report/results/result'): print( '=======================================================================') result = {} result['report_id'] = report_result.xpath('@id')[0] result['description'] = report_result.xpath( 'description/text()')[0] result['name'] = report_result.xpath('name/text()')[0] result['port'] = report_result.xpath('port/text()')[0] result['nvt_bid'] = report_result.xpath( 'nvt/bid/text()')[0] result['nvt_cve'] = report_result.xpath( 'nvt/cve/text()')[0] result['nvt_cvss_base'] = report_result.xpath( 'nvt/cvss_base/text()')[0] result['nvt_family'] = report_result.xpath( 'nvt/family/text()')[0] result['nvt_oid'] = report_result.xpath('nvt/@oid')[0] result['nvt_tags'] = report_result.xpath( 'nvt/tags/text()')[0] result['nvt_type'] = report_result.xpath( 'nvt/type/text()')[0] result['nvt_xref'] = report_result.xpath( 'nvt/xref/text()')[0] result['quality_of_detection_value'] = report_result.xpath( 'qod/value/text()')[0] result['quality_of_detection_type'] = report_result.xpath( 'qod/type/text()')[0] result['threat'] = report_result.xpath( 'threat/text()')[0] result['severity'] = report_result.xpath( 'severity/text()')[0] for host in hosts: if(host['ip_address'] == report_result.xpath('host/text()')[0]): host['results'].append(result) report['hosts'] = hosts report['ip_address_count'] = len(target_list) report['status'] = 'received' print(json.dumps(report)) return report else: report = {'status': 'running'} return report except GvmError as e: no_report = {'status': 'bad'} print(e) return no_report def get_reports(self, id, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_reports() pretty_print(response) except GvmError as e: print(e) def get_full_report(self, id, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_report(id) pretty_print(response) except GvmError as e: print(e) def get_targets(self, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_targets() pretty_print(response) for target in response.xpath('target'): pretty_print(target.xpath('@id')) except GvmError as e: print(e) def get_task(self, id, username, password): try: with self.gmp: self.gmp.authenticate(username, password) reponse = self.gmp.get_task(id) pretty_print(reponse) except GvmError as e: print(e) def get_tasks(self, username, password): try: with self.gmp: self.gmp.authenticate(username, password) response = self.gmp.get_tasks() for task in response.xpath('task'): pretty_print(task.xpath('@id')) except GvmError as e: print(e) def scan_target(self, task_name, target_name, targets_list, username, password): try: target_id = self.create_target( target_name, targets_list, username, password) if(target_id == 'bad'): return ('bad','bad','bad','bad') task_id = self.create_task(task_name, self.get_full_and_fast_config_id(), target_id, self.get_default_openvas_scanner_id(), username, password) if(task_id == 'bad'): return ('bad','bad','bad','bad') task_tuple = self.start_task(task_id, username, password) if(task_tuple[0] =='bad'): return ('bad','bad','bad','bad') report_id = task_tuple[0] status = task_tuple[1] return (target_id,task_id,report_id, status) except GvmError as e: print(e) return ('bad','bad','bad','bad') def start_task(self, id, username, password): try: with self.gmp: print(id) self.gmp.authenticate(username, password) reponse = self.gmp.start_task(id) report_id = reponse.xpath('report_id/text()') status = 'start' if(len(report_id) == 0): return ('bad','bad') return (report_id[0], status) except GvmError as e: print(e) return ('bad', 'bad') def test1(self, task_name, target_name,ip_address_list,ip_address_count_per_report,username,password): run_task_name = task_name + '_' + str(uuid4()) total_ip_addresses = len(ip_address_list) remainder = total_ip_addresses % ip_address_count_per_report chopped_ip_addresses = total_ip_addresses - remainder count = 0 left_index = 0 right_index = ip_address_count_per_report for batch in range(chopped_ip_addresses//ip_address_count_per_report): slice_object = slice(left_index,right_index) sub_ip_address_list = ip_address_list[slice_object] left_index = left_index + ip_address_count_per_report right_index = right_index + ip_address_count_per_report run_task_name_id = run_task_name + '_batch_number_' + str(batch) run_target_name_id = run_task_name_id + '_target_' + target_name count = count + 1 report_tuple = self.scan_target(run_task_name_id,run_target_name_id, sub_ip_address_list, username, password) if( remainder > 0): slice_object = slice(-remainder,total_ip_addresses) sub_ip_address_list = ip_address_list[slice_object] run_task_name_id = run_task_name + '_batch_number_' + str(count) run_target_name_id = run_task_name_id + '_target_' + target_name report_tuple = self.scan_target(run_task_name_id,run_target_name_id, sub_ip_address_list, username, password)
class GVM_client: def __init__(self, password, socket_path='/var/run/gvmd.sock', user='******', timeout=10, loglevel=logging.ERROR): logging.basicConfig(level=loglevel) self.connection_errors = 0 self.container_tasks = {} self.password = password self.user = user self.socketconnection = UnixSocketConnection(path=socket_path, timeout=timeout) self.connection = DebugConnection(self.socketconnection) self.transform = EtreeCheckCommandTransform() self.gmp = Gmp(connection=self.connection, transform=self.transform) self.connect() def authenticate(self): try: self.gmp.authenticate(self.user, self.password) except Exception as ex: logging.error('Unable to authenticate: {}'.format(ex)) def connect(self): try: self.authenticate() return self.gmp._connected except Exception as ex: self.connection_errors += 1 logging.error('Can\'t connect to service: {}'.format(ex)) return False def get_xmls(self, directory): results = [] for file_name in os.listdir(directory): if file_name.lower().endswith(".xml"): file_path = os.path.join(directory, file_name) logging.info('Reading file {}'.format(file_path)) with io.open(file_path, 'r', encoding='utf-8') as file: results.append(''.join(file.readlines())) return results def wait_connection(self, connection_tries=10, secs_before_attempt=5): while not self.connect(): if self.connection_errors <= connection_tries: sleep(secs_before_attempt) else: raise Exception('Can\'t connect to gvmd in {} sec'.format(connection_tries*secs_before_attempt)) def wait_sync(self, interval=15): logging.info('Waiting for NVTs/Feeds sync to complete') while True: if self.connect(): families = self.gmp.get_nvt_families().xpath('families/family') feeds = self.gmp.get_feeds().xpath('feed/currently_syncing') if len(families) != 0 and len(feeds) == 0: break else: sleep(interval) def import_configs(self, directory): for config in self.get_xmls(directory): if self.connect(): try: response = self.gmp.import_config(config) if response.attrib['status'] == '201': config_root = ET.fromstring(config) config_name = config_root.findtext('config/name') logging.info('Importing config OK: {}'.format(config_name)) except Exception as ex: logging.error('Importing config error: {}'.format(ex)) def create_target(self, target:Target): if self.connect(): try: response = self.gmp.create_target( name=target.name, make_unique=target.make_unique, hosts=target.hosts, exclude_hosts=target.exclude_hosts, comment=target.comment, alive_tests=target.alive_tests, reverse_lookup_only=target.reverse_lookup_only, reverse_lookup_unify=target.reverse_lookup_unify, port_range=target.port_range, port_list_id=target.port_list_id, asset_hosts_filter=target.asset_hosts_filter, ssh_credential_id=target.ssh_credential_id, ssh_credential_port=target.ssh_credential_port, smb_credential_id=target.smb_credential_id, snmp_credential_id=target.snmp_credential_id, esxi_credential_id=target.esxi_credential_id) if response.attrib['status'] == '201': logging.info('Importing target OK: {}'.format(target.name)) except Exception as ex: logging.error('Importing target error: {}'.format(ex)) def import_targets(self, directory:str): ''' directory: path to exported targets in XML ''' for target_config in self.get_xmls(directory): if self.connect(): try: target = Target(target_config) self.create_target(target) except Exception as ex: logging.error('Importing target error: {}'.format(ex)) def create_task(self, task:Task): if self.connect(): try: response = self.gmp.create_task( name=task.name, target_id=task.target_id, scanner_id=task.scanner_id, config_id=task.config_id, comment=task.comment, alterable=task.alterable, alert_ids=task.alert_ids, hosts_ordering=task.hosts_ordering, schedule_id=task.schedule_id, schedule_periods=task.schedule_periods, observers=task.observers) if response.attrib['status'] == '201': logging.info('Importing task OK: {}'.format(task.name)) except Exception as ex: logging.error('Importing task error: {}'.format(ex)) def create_override(self, override:Override): if self.connect(): try: response = self.gmp.create_override( text=override.text, nvt_oid=override.nvt_oid, seconds_active=override.seconds_active, comment=override.comment, hosts=override.hosts, port=override.port, result_id=override.result_id, severity=override.severity, new_severity=override.new_severity, task_id=override.task_id, threat=override.threat, new_threat=override.new_threat) if response.attrib['status'] == '201': logging.info('Creating override OK: {}'.format(override.text)) except Exception as ex: logging.error('Creating override error: {}'.format(ex)) def import_overrides(self, directory:str): for override_xml in self.get_xmls(directory): if self.connect(): try: override = Override(override_xml) self.create_override(override) except Exception as ex: logging.error('Importing override error: {}'.format(ex)) def import_tasks(self, directory:str): for task_config in self.get_xmls(directory): if self.connect(): try: task = Task(task_config) task.target_id = None for target in self.gmp.get_targets().xpath('target'): target_name = target.find('name').text if target_name == task.name: task.target_id = target.attrib['id'] logging.log(logging.DEBUG, 'Importing task - target_id: {}'.format(task.target_id)) if task.target_id == None: logging.log(logging.DEBUG, 'Importing task - {}. No target_id found'.format(task.name)) continue task.config_id = None for config in self.gmp.get_configs().xpath('config'): if config.find('name').text == task.config['name']: task.config_id = config.attrib['id'] logging.log(logging.DEBUG, 'Importing task - config_id: {}'.format(task.config_id)) break self.create_task(task) except Exception as ex: logging.error('Importing task error: {}'.format(ex)) def import_reports(self, directory): for report_xml in self.get_xmls(directory): if self.connect(): try: report = Report(report_xml) if report.task_name not in self.container_tasks.keys(): response = self.gmp.import_report(report_xml, task_name=report.task_name, task_comment=report.task_comment) if response.attrib['status'] == '201': logging.info('Importing report OK: {}'.format(report.task_name)) tasks = self.gmp.get_tasks().xpath('task') for task in tasks: if task.find('name').text == report.task_name and self._is_container_task(task): logging.log(logging.DEBUG, 'Found container task: {}[{}]'.format(report.task_name, task.attrib['id'])) self.container_tasks[report.task_name] = task.attrib['id'] break else: response = self.gmp.import_report(report_xml, task_id=self.container_tasks[report.task_name]) if response.attrib['status'] == '201': logging.info('Importing report OK: {}'.format(report.task_name)) except Exception as ex: logging.error('Importing report error: {}'.format(ex)) def get_task(self, task_id): if self.connect(): try: response = self.gmp.get_task(task_id=task_id) if response.attrib['status'] == '200': task = Task(response.find('task')) logging.debug('Getting task OK: {} [{}]'.format(task.name, task_id)) return task else: return None except Exception as ex: logging.error('Getting task error: {}'.format(ex)) def get_task_status(self, task_id): if self.connect(): try: response = self.gmp.get_task(task_id=task_id) if response.attrib['status'] == '200': task_status = response.find('task/status').text logging.info('Getting task status OK: {} [{}]'.format(task_id, task_status)) return task_status else: return None except Exception as ex: logging.error('Getting task status error: {}'.format(ex)) def run_task(self, task_id:str): if self.connect(): try: response = self.gmp.start_task(task_id=task_id) if response.attrib['status'] == '202': logging.info('Running task OK: {}'.format(task_id)) return True else: return False except Exception as ex: logging.error('Running task error: {}'.format(ex)) return False def _is_container_task(self, task): return task.find('target').attrib['id'] == '' def get_targets(self): if self.connect(): try: targets = [Target(target) for target in self.gmp.get_targets().xpath('target')] logging.info('Targets found in DB: {}'.format(', '.join([target.name for target in targets]))) return targets except Exception as ex: logging.error('Getting targets error: {}'.format(ex)) return False def get_tasks(self, exclude_containers=True): if self.connect(): try: tasks = self.gmp.get_tasks().xpath('task') logging.info('Tasks found in DB: {}'.format(', '.join([task.find('name').text for task in tasks]))) if exclude_containers: return [Task(task) for task in tasks if not self._is_container_task(task)] else: return [Task(task) for task in tasks] except Exception as ex: logging.error('Getting tasks error: {}'.format(ex)) return False def save_report(self, report_id:str, directory:str): if self.connect(): try: raw_report = self.gmp.get_report(report_id).find('report') report = Report(raw_report) logging.info('Got report: {}'.format(report.name)) file_name = '{}-{}.xml'.format(report.task_name, report.name) file_path = os.path.join(directory, file_name) logging.info('Saving report to file {}'.format(file_path)) if os.path.isfile(file_path): raise Exception('File exists: {}'.format(file_path)) with io.open(file_path, 'wb') as file: file.write(ET.tostring(raw_report, encoding='utf-8', method='xml', pretty_print=True)) return True except Exception as ex: logging.error('Getting targets error: {}'.format(ex)) return False