Пример #1
0
def vcheck(recent_version_url: str) -> Union[str, bool, None]:
    """ compare given remote and local VERSION file
    
    return False if failed, None if no newer version found
    or recent version
    """

    try:
        with open('VERSION') as file:
            current_version = file.read().strip()

    except:
        log.warn('failed to read file `VERSION`.')
        return False

    recent_version = get(recent_version_url)
    if not recent_version.status_code == 200:
        log.warn('failed to get recent version.')
        return False
    recent_version = recent_version.text.strip()

    for current, recent in zip(current_version.split('.'),
                               recent_version.split('.')):
        if recent > current:
            log.notice('v{0} is available (current: v{1}).'.format(
                recent_version, current_version))
            return recent_version

    else:
        log.debug('up to date: v{0}.'.format(current_version))
        return None
Пример #2
0
    def write(self, data: Union[list, dict], **kwargs) -> bool:
        """ save dict or list of dicts to json file (optionally sorted)
        data:
            data: dict or list of dicts
        kwargs:
            list_sort_key: str [default: None]
            reverse: bool [default: False]
         """

        try:
            with open(self.filename, 'w+', encoding='utf-8') as f:
                f.write(
                    json.dumps(self._sort(data, kwargs), indent=4,
                               default=str))
            log.debug('data exported to `{0}`.'.format(self.filename))

        except FileNotFoundError:
            log.warn('`{0}` not found.'.format(self.filename))
            self.error = True
            return False

        except PermissionError:
            log.warn('Could not write `{0}`, permission denied.'.format(
                self.filename))
            self.error = True
            return False

        self.error = False
        return True
Пример #3
0
def crawl_net(subnet: str = None) -> Iterator[Union[str, str]]:
    """ scan given subnet for IPs and MACs using nmap """
    
    log.notice("scanning {0} for machines".format(subnet))
    
    cmd = "nmap -sn"
    cmd = cmd.split()
    cmd.append(subnet)
    
    stdout, _ = exe(cmd, timeout=300)
    if not stdout:
        log.warn("failed to scan network.")
        return None, None, None
    
    s = stdout.replace('\n', '|')
    
    for chunk in re.findall(r"Nmap scan report for.*?MAC Address.*?\(.*?\)", s):
        
        try:
            ip = re.findall(ip_pattern, chunk)[0]
            mac = re.findall(mac_pattern, chunk)[0]
        
        except IndexError:
            continue
        
        comment = re.findall(r"{0}\s\(.*?\)".format(mac), chunk)
        comment = '' if len(comment) == 0 else comment[0][19:-1]
        
        log.debug("found {0}, {1} ({2})".format(ip, mac, comment))
        yield ip, mac, comment
Пример #4
0
def scan_net(subnet: str) -> None:
    """ crawl net and add found IPs """

    for ip, mac, comment in crawl_net(subnet):
        new = registered(ip, True)
        if new:
            log.debug('found {1} ({0}, {2})'.format(ip, mac, comment))

        if machine[ip].data['comment'] == '':
            machine[ip].data['comment'] = comment

        if not machine[ip].data['mac']:
            machine[ip].data['mac'] = mac
Пример #5
0
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
Пример #6
0
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.')
Пример #7
0
def test_order(sort_key: str) -> Iterator[Tuple[str, str]]:
    """ return list (ip, sort_key) ordered by sort_key value """

    r = []
    for ip in machine:
        if not machine[ip].keep or machine[ip].skip:
            log.debug('excluded {0} from run-test-candidates.'.format(ip))
            continue

        # TODO optional min duration between tests of single machines

        r.append((ip, machine[ip].data[sort_key]))

    r.sort(key=lambda k: k[1])

    return r
Пример #8
0
def get_mac(ip: str) -> Union[str, None]:
    """ get current mac address from ip using arping """
    
    cmd = "/usr/sbin/arping -c1 {0}".format(ip)
    cmd = cmd.split()
    
    stdout, _ = exe(cmd, timeout=300)
    if not stdout:
        log.crit("failed to get mac address")
        return None
    
    try:
        mac = re.findall(mac_pattern, stdout.upper())[0]
        
        log.debug("current mac for {0}: {1}".format(ip, mac))
        return mac
    
    except IndexError:
        return None
Пример #9
0
 def __init__(self, ip: str) -> None:
     
     self.keep = self.skip = self.running = False
     self.mac_new = None
     self.target = self.task = self.report = None
     
     self.data = {
       'ip':           ip,
       'mac':          None,
       'comment':      '',
       'severity':     -1,
       'link':         None,
       'created':      default_stamp,
       'last_attempt': default_stamp,
       'last_report':  default_stamp,
       'want_check':   False,
       'ip_changed':   False
       }
     
     log.debug('created container for {0}'.format(ip))
Пример #10
0
    def _sort(self, data: Union[list, dict],
              kwargs: dict) -> Union[list, dict]:
        """ sort data if list  """

        for key in ('list_sort_key', 'reverse'):
            if key in kwargs:
                setattr(self, key, kwargs.get(key))

        if not self.list_sort_key or not isinstance(data, list):
            return data

        try:
            data = sorted(data,
                          key=lambda k: k[self.list_sort_key],
                          reverse=self.reverse)
            sorted_by = " reversed" if self.reverse else ""
            log.debug('sorted by `{0}`{1}.'.format(self.list_sort_key,
                                                   sorted_by))

        except:
            pass

        return data
Пример #11
0
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']))
Пример #12
0
    def read(self, **kwargs) -> Union[list, dict, None]:
        """ load file content as dict or list of dicts (optionally sorted)
        kwargs:
            list_sort_key: str [default: None]
            reverse: bool [default: False]
         """
        try:
            with open(self.filename) as json_file:
                data = json.load(json_file)
            log.debug('`{0}` imported.'.format(self.filename))

        except FileNotFoundError:
            log.warn('`{0}` not found.'.format(self.filename))
            self.error = True
            return None

        except PermissionError:
            log.warn('Could not read `{0}`, permission denied.'.format(
                self.filename))
            self.error = True
            return None

        self.error = False
        return self._sort(data, kwargs)
Пример #13
0
              severity, '\t\t', last_report, '\t\t', comment)

    print('{0} running tasks'.format(tasks_running()))


if __name__ == '__main__':
    args = get_args()
    if args.vv:
        log.log_level = 7
    elif args.v:
        log.log_level = 6

    if args.print:
        log.use_tty = False

    log.debug('initiated...')
    vcheck(
        'https://raw.githubusercontent.com/TMagerl/AutoOpenVAS/master/VERSION')

    config = load_config()
    ov = OpenVAS('admin', config['passwd'], config['openvas_ip'],
                 config['openvas_omp_port'], config['openvas_web_port'])

    machine = {}
    load_previous_data()
    import_targets(config['job_source'])

    if args.scan:
        scan_net(args.scan)

    openvas_analysis()