def tasks(self) -> Iterator[Union[str, str, str]]: """ extract ip, mac, task-IDs """ raw_data = self._omp(['--xml', '<get_tasks/>'], 300) for result_line in re.findall(r"<task id=\"[0-9a-f-]*?\">.*?</task>", raw_data): try: name = re.findall('<target id=.*?>.*</name>', result_line)[0] name = re.findall('<name>.*?</name>', name)[0] ip = re.findall('\(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\)', name)[0][1:-1] mac = re.findall( '>[\dA-F]{2}:[\dA-F]{2}:[\dA-F]{2}:[\dA-F]{2}:[\dA-F]{2}:[\dA-F]{2}\s', name)[0][1:-1] if len(ip) < 8 or len(mac) < 17: log.err('task strange mac/ip') continue status = re.findall('<status>.*?</status>', result_line)[0] running = True if rm_tags(status) == "Running" else False except IndexError: log.err('task index error') continue task = re.findall('<task id=\"[0-9a-f-]*?\">', result_line)[0] task = get_quote(task) yield ip, mac, task, running
def _omp(self, arg: list, timeout: int = 30) -> str: """ communication with OpenVAS """ cmd = self.base_cmd.split() + arg label = cmd[0] + " " + " ".join(cmd[len(cmd) - 2:]) tried = 0 while tried < 3: stdout, _ = exe(cmd, timeout=timeout, label=label) if not stdout: raise SystemExit(66) stdout = stdout.replace('\n', ' ') if "Failed to authenticate." in stdout: tried += 1 log.err("wrong password or openvas busy [{0}/3]".format(tried)) sleep(43) elif "Failed to acquire socket." in stdout: log.crit("Failed to acquire socket.".format(self.port)) raise SystemExit(6) else: return stdout log.crit("giving up, wrong password or openvas busy." \ "try `systemctl restart greenbone-security-assistant` @ {0}.".format(self.ip)) raise SystemExit(4)
def reports(self) -> Iterator[Union[str, str, datetime]]: """ extract ip, reportID and time stamp from openvas report """ raw_data = self._omp(['--xml', '<get_reports/>'], 300) for report_chunk in re.findall( r"<report id=\"[0-9a-f-]*?\">.*?</report>", raw_data): report = re.findall(r"<report id=\"[0-9a-f-]*?\">", report_chunk)[0] report = get_quote(report) for result_chunk in re.findall( r"<result id=\"[0-9a-f-]*?\">.*?</result>", report_chunk): ip = re.findall('<host>[0-9.]*?<.*?>', result_chunk) if not len(ip) == 1: log.err('report: multiple hosts found') continue ip = rm_tags(ip[0]) stamp = re.findall( '<modification_time>.*?</modification_time>', result_chunk) if not len(stamp) == 1: log.err('report: multiple timestamps found') continue stamp = rm_tags(stamp[0]) stamp = datetime.strptime(stamp[:19], '%Y-%m-%dT%H:%M:%S') yield ip, report, stamp
def import_targets(path: str) -> None: """ call method for file or folder """ if os.path.isfile(path): import_target_file(path) elif os.path.isdir(path): import_target_folder(path) else: log.err('nothing to import from `{0}`?'.format(path))
def exe(command: Union[list, str], **kwargs) -> Tuple[Union[str, bool], Union[str, Exception]]: """ execute external process, returns (stdout: str|false, stderr: str) kwargs: timeout: default = 300sec label: log-label """ timeout = kwargs.pop('timeout', 300) if not isinstance(timeout, int): raise ValueError("timeout can be int only") if isinstance(command, str): command = command.split() elif not isinstance(command, list): raise ValueError("command can be list or string only") label = kwargs.pop('label', command[0]) try: subp = Popen(command, stdout=PIPE, stderr=STDOUT) except OSError: log.crit("`{0}` not found".format(command[0])) return False, 'not found' except Exception as e: log.crit("`{0}` failed: {1}".format(command[0], e)) return False, e try: stdout, stderr = subp.communicate(timeout=timeout) except TimeoutExpired: log.err('`{0}` exceeded timeout ({1} sesc}.'.format( command[0], timeout)) subp.kill() return False, 'timeout' except Exception as e: log.crit("`{0}` communication failed: {1}".format(command[0], e)) return False, e stdout = '' if not stdout else stdout.decode('utf8') stderr = '' if not stderr else stderr.decode('utf8') log.debug('`{0}` executed.'.format(label)) return stdout, stderr
def openvas_run_task() -> None: """ try to start OV task until success, ordered by last_report """ if tasks_running() > config['run_limit']: log.info('limit of {0} running tasks reached, no new task.'.format( config['run_limit'])) return for ip, _ in test_order('last_attempt'): if machine[ip].running: log.info('[{0}]: task already running'.format( machine[ip].data['mac'])) continue machine[ip].data['last_attempt'] = now() if args.verify: real_mac = get_mac(ip) if real_mac and not machine[ip].data['mac'] == real_mac: log.warn('[{0}]: ERROR: address conflict {1} ({2})'.format( machine[ip].data['mac'], real_mac, ip)) continue if ov.run_task(machine[ip].task): log.notice('[{0}]: started OpenVAS task'.format( machine[ip].data['mac'])) sleep(60 * 2) if task_running(ip): log.debug('[{0}]: running task verified'.format( machine[ip].data['mac'])) machine[ip].keep = True break else: log.warn('[{0}]: task was aborted'.format( machine[ip].data['mac'])) continue else: log.warn('[{0}]: FAILED starting OpenVAS task'.format( machine[ip].data['mac'])) continue else: log.err('FAILED to start any OpenVAS task.')
def clean_up(): """ remove machines with last successfull test older than threshold days """ now = datetime.now() for ip in machine: if machine[ip].running or machine[ip].keep: continue last_success = now - machine[ip].data['last_report'] last_success = last_success.days last_attempt = now - machine[ip].data['last_attempt'] last_attempt = last_attempt.days if not last_success > config['clean_up_threshold_days'] \ or not last_attempt < config['clean_up_threshold_days']: continue if machine[ip].task and not (ov.rm('task', machine[ip].task)): log.err("[{0}]: failed removing task ({1})".format( machine[ip].data['mac'], ip)) if machine[ip].target and not ov.rm('target', machine[ip].target): log.err("[{0}]: failed removing target ({1})".format( machine[ip].data['mac'], ip))
def mk_machine(json_data: dict, source: str) -> None: """ create new machine object """ try: json_data['ip'], json_data['mac'] except KeyError: log.err('failed importing `{0}`'.format(source)) return ip = json_data['ip'] new = registered(ip, True) if not machine[ip].data['mac']: machine[ip].data['mac'] = json_data['mac'].upper() if json_data.get('skip', False): machine[ip].skip = machine[ip].data['skip'] = True machine[ip].data['comment'] = json_data['comment'] if new: log.debug('config for {0} [{1}] imported'.format( machine[ip].data['ip'], machine[ip].data['mac']))