import dsz, dsz.lp import sys, random, time import ops, util.ip, ops.timehelper import os.path import helper, scanbase from math import floor from datetime import datetime import scanengine2 import monitorengine import exceptions def main(arguments): scanbase.setup_db() failout = False scansweepHelper = helper.scansweepHelper([x.lower() for x in arguments]) scansweepHelper.check_env() create_mode = False if (scansweepHelper.options.database is not None): database_op = scansweepHelper.options.database if (not (database_op == 'create')): if (scansweepHelper.options.session is not None): scansweepHelper.database_display(database_op) else: scansweepHelper.database_display(database_op) return else: create_mode = True if (scansweepHelper.options.update is not None): scansweepHelper.handleupdate() return scanbase.write_metadata(scansweepHelper.scansweep_env, scansweepHelper.session, scansweepHelper.scansweep_logfile, scansweepHelper.scansweep_results, scansweepHelper.verbose) if (scansweepHelper.options.exclude is not None): scansweepHelper.parseexcludes(scansweepHelper.options.exclude) if (scansweepHelper.session == scansweepHelper.scansweep_env): if ((scansweepHelper.options.monitor is None) and (scansweepHelper.options.type is None)): dsz.ui.Echo('You must specify a type.', dsz.ERROR) return 0 if ((scansweepHelper.options.monitor is None) and os.path.exists(scansweepHelper.options.type[0])): if (scansweepHelper.options.target is not None): dsz.ui.Echo('You cannot use -target when specifying a queue file.', dsz.ERROR) return 0 queuefile = scansweepHelper.options.type[0] if (not scansweepHelper.verifyqueue(queuefile)): failout = True else: queuelist = scansweepHelper.getqueuefromfile(queuefile) for item in queuelist: scansweepHelper.addtoqueue(item[0], item[1], scansweepHelper.scansweep_env) elif (scansweepHelper.options.type is not None): job_type = scansweepHelper.options.type[0].lower() job = '|'.join(scansweepHelper.options.type) if (not scansweepHelper.verifyjob(job_type, scansweepHelper.options.type)): dsz.ui.Echo('Invalid -type options, please verify your parameters.', dsz.ERROR) return 0 candidate_list = [] if (scansweepHelper.options.target is not None): if (type(scansweepHelper.options.target) == type([])): for target_flag in scansweepHelper.options.target: candidate_list.extend(scansweepHelper.parsetarget(target_flag)) else: candidate_list = scansweepHelper.parsetarget(scansweepHelper.options.target) else: dsz.ui.Echo('You must provide some targets with your scan.', dsz.ERROR) return 0 if ((len(candidate_list) > 255) and (not scansweepHelper.options.cidroverride)): dsz.ui.Echo('You cannot specify more then 255 targets without the -cidroverride option', dsz.ERROR) failout = True else: scansweepHelper.addlisttoqueue({job: candidate_list}) if (scansweepHelper.monitor is not None): for monitortype in scansweepHelper.monitor: if (scansweepHelper.verifymonitor(monitortype) is False): dsz.ui.Echo(('%s is an invalid monitor type' % monitortype)) failout = True if ((scanbase.num_jobs(scansweepHelper.session) > 255) and (not scansweepHelper.options.cidroverride)): dsz.ui.Echo('You cannot specify more then 255 targets without the -cidroverride option', dsz.ERROR) failout = True if (scansweepHelper.options.escalate is not None): rulelist = scansweepHelper.parseescalate(scansweepHelper.options.escalate) if (len(rulelist) == 0): dsz.ui.Echo('You specified -escalate, but had only invalid rules. Exiting.', dsz.ERROR) failout = True for rule in rulelist: scantype = rule[1].split('|')[0] current_rulelist = scanbase.get_escalate_rules(scansweepHelper.session) if (rule not in current_rulelist): scanbase.write_escalate_rule(scansweepHelper.session, rule) if (not (scantype == 'alert')): scanbase.set_jobtype(scansweepHelper.session, scantype) elif ((scansweepHelper.options.type is not None) or (scansweepHelper.options.target is not None)): dsz.ui.Echo('You cannot specify -target or -type when using -session.', dsz.WARNING) failout = True else: dsz.ui.Echo('You are joining another session, and so will use the already available job queue and escalate rules.', dsz.WARNING) if (not scansweepHelper.verifytime(scanbase.get_jobtypes(scansweepHelper.session))): failout = True if failout: return 0 scansweepHelper.printconfig() if create_mode: dsz.ui.Echo('Ran in create mode. Exiting.', dsz.WARNING) return dsz.lp.RecordToolUse('scansweep', scansweepHelper.toolversion, usage='EXERCISED', comment=' '.join([x.lower() for x in arguments])) try: scan(scansweepHelper) finally: dsz.ui.Echo(('=' * 100)) scansweepHelper.showstats() print '\n\n' scansweepHelper.generateresults(quiet=False) def scan(scansweepHelper): lastresults = 0 alreadyoutput = [] num_remaining = scanbase.num_jobs(scansweepHelper.session) sanity_string = ('[%s] Sanity output: %s jobs remaining, %s-%s remaining' % (dsz.Timestamp(), num_remaining, ops.timehelper.get_age_from_seconds((num_remaining * scansweepHelper.min_seconds)), ops.timehelper.get_age_from_seconds((num_remaining * scansweepHelper.max_seconds)))) dsz.ui.Echo(sanity_string, dsz.GOOD) scansweepHelper.showstats() if (not os.path.exists(os.path.dirname(scansweepHelper.scansweep_logfile))): os.mkdir(os.path.dirname(scansweepHelper.scansweep_logfile)) with open(scansweepHelper.scansweep_logfile, 'a') as f: f.write(('%s\n' % sanity_string)) delta = time.time() scantime = time.time() originaltime = time.time() if (scansweepHelper.monitor is not None): scansweepHelper.activatemonitors() while True: if ((time.time() - originaltime) > scansweepHelper.maxtime): dsz.ui.Echo(('Maxtime of %s has been exceeded. Exiting.' % ops.timehelper.get_age_from_seconds(scansweepHelper.maxtime)), dsz.ERROR) break scan_job = scanbase.get_job(scansweepHelper.session) if (scan_job == False): if (scansweepHelper.monitor is None): break else: try: target = scan_job[1] job_info = scan_job[0].split('|') job_type = job_info[0] if (not util.ip.validate(target)): target = scansweepHelper.resolvehostname(target) if (target == None): continue target_scanner = scanengine2.get_scanengine(scan_job, scansweepHelper.timeout) target_scanner.execute_scan(False) if target_scanner.multiple_responses: multi_response = target_scanner.return_data() for response in multi_response: scanbase.write_result(scansweepHelper.session, response.scan_type, response.target, response.return_data(), response.success, scan_job[0]) else: scanbase.write_result(scansweepHelper.session, target_scanner.scan_type, target_scanner.target, target_scanner.return_data(), target_scanner.success, scan_job[0]) if target_scanner.success: succ_out_string = ('[%s] %s (%s jobs remaining)' % (target_scanner.timestamp, target_scanner.return_success_message(), scanbase.num_jobs(scansweepHelper.session))) dsz.ui.Echo(succ_out_string) with open(scansweepHelper.scansweep_logfile, 'a') as f: f.write(('%s\n' % succ_out_string)) rulelist = scanbase.get_escalate_rules(scansweepHelper.session) for rule in rulelist: if target_scanner.check_escalation(rule[0]): if (rule[1] == 'alert'): if (target_scanner.success == True): esc_output_string = ('[%s]\t\tAlerting on %s by rule: (%s->%s)' % (dsz.Timestamp(), target, rule[0], rule[1])) else: esc_output_string = ('[%s] Alerting on %s by rule: (%s->%s)' % (dsz.Timestamp(), target, rule[0], rule[1])) scansweepHelper.alert(esc_output_string) dsz.ui.Echo(esc_output_string, dsz.WARNING) else: add_succ = scansweepHelper.addtoqueue(rule[1], target, scansweepHelper.scansweep_env) if ((target_scanner.success == True) and add_succ): esc_output_string = ('[%s]\t\tEscalating %s by rule: (%s->%s) (%s jobs remaining)' % (dsz.Timestamp(), target, rule[0], rule[1], scanbase.num_jobs(scansweepHelper.session))) elif add_succ: esc_output_string = ('[%s] Escalating %s by rule: (%s->%s) (%s jobs remaining)' % (dsz.Timestamp(), target, rule[0], rule[1], scanbase.num_jobs(scansweepHelper.session))) dsz.ui.Echo(esc_output_string) with open(scansweepHelper.scansweep_logfile, 'a') as f: f.write(('%s\n' % esc_output_string)) except Exception as e: if dsz.ui.Prompt(('The current job failed for some reason. Would you like to quit? %s' % e), False): break else: continue if scansweepHelper.monitor: for monitor_handler in scansweepHelper.monitorengines: found_connections = monitor_handler.execute_monitor() for connection in found_connections: rulelist = scanbase.get_escalate_rules(scansweepHelper.session) for rule in rulelist: if monitor_handler.check_escalation(rule[0], connection): found = False add_succ = True if (not scansweepHelper.internaloverride): for network in scansweepHelper.local_networks: if util.ip.validate_ipv6(connection.target): if (util.ip.expand_ipv6(connection.target)[:19] == network[1]): found = True break elif ((not (network[0] == '')) and (scansweepHelper.getnetwork(connection.target, util.ip.get_cidr_from_subnet(network[0])) == network[1])): found = True break if ((not scansweepHelper.internaloverride) and (not found)): esc_output_string = ('[%s] Escalation failed (outside subnet) %s by rule: (%s->%s) (%s jobs remaining)' % (dsz.Timestamp(), connection.target, rule[0], rule[1], scanbase.num_jobs(scansweepHelper.session))) dsz.ui.Echo(esc_output_string, dsz.WARNING) elif (rule[1] == 'alert'): esc_output_string = ('[%s] Alerting on %s by rule: (%s->%s)' % (dsz.Timestamp(), connection.target, rule[0], rule[1])) scansweepHelper.alert(esc_output_string) dsz.ui.Echo(esc_output_string, dsz.WARNING) else: add_succ = scansweepHelper.addtoqueue(rule[1], connection.target, scansweepHelper.scansweep_env) if add_succ: esc_output_string = ('[%s] Escalating %s by rule: (%s->%s) (%s jobs remaining)' % (dsz.Timestamp(), connection.target, rule[0], rule[1], scanbase.num_jobs(scansweepHelper.session))) dsz.ui.Echo(esc_output_string) if add_succ: with open(scansweepHelper.scansweep_logfile, 'a') as f: f.write(('%s\n' % esc_output_string)) newdelta = time.time() num_remaining = scanbase.num_jobs(scansweepHelper.session) if ((((num_remaining % 10) == 0) and (not (num_remaining in alreadyoutput))) or ((newdelta - delta) > (5 * 60))): maxremaining = int((scansweepHelper.maxtime - (time.time() - originaltime))) sanity_string = ('[%s] Sanity output: %s jobs remaining, %s-%s remaining (max %s), %0.1fs since last sanity' % (dsz.Timestamp(), num_remaining, ops.timehelper.get_age_from_seconds((num_remaining * scansweepHelper.min_seconds)), ops.timehelper.get_age_from_seconds((num_remaining * scansweepHelper.max_seconds)), ops.timehelper.get_age_from_seconds(maxremaining), (newdelta - delta))) dsz.ui.Echo(sanity_string, dsz.GOOD) with open(scansweepHelper.scansweep_logfile, 'a') as f: f.write(('%s\n' % sanity_string)) scansweepHelper.showstats() alreadyoutput.append(scanbase.num_jobs(scansweepHelper.scansweep_env)) delta = newdelta resultstotal = 0 type_list = scanbase.get_jobtypes(scansweepHelper.session) for type in type_list: resultstotal = (resultstotal + scansweepHelper.findlistsize(type)) if (not (lastresults == resultstotal)): scansweepHelper.generateresults(quiet=True) lastresults = resultstotal if scanbase.check_kill(scansweepHelper.session): dsz.ui.Echo(('This session (%s) is marked for death. Exiting.' % scansweepHelper.session), dsz.ERROR) break if ((not (scanbase.num_jobs(scansweepHelper.session) == 0)) or scansweepHelper.monitor): sleep_in_secs = random.randint(scansweepHelper.min_seconds, scansweepHelper.max_seconds) if (not scansweepHelper.nowait): if scansweepHelper.verbose: dsz.ui.Echo(('[%s] Sleeping for %s seconds...' % (dsz.Timestamp(), sleep_in_secs))) try: dsz.Sleep((sleep_in_secs * 1000)) except exceptions.RuntimeError as e: dsz.ui.Echo(('%s' % e), dsz.ERROR) break elif ((time.time() - scantime) < sleep_in_secs): nowaitsleep = int((sleep_in_secs - floor((time.time() - scantime)))) if scansweepHelper.verbose: dsz.ui.Echo(('[%s] Sleeping for %s seconds (%s seconds remain)...' % (dsz.Timestamp(), sleep_in_secs, nowaitsleep))) try: dsz.Sleep((sleep_in_secs * 1000)) except exceptions.RuntimeError as e: dsz.ui.Echo(('%s' % e), dsz.ERROR) break elif scansweepHelper.verbose: dsz.ui.Echo(('[%s] Would sleep for %s seconds but we are overdue...' % (dsz.Timestamp(), sleep_in_secs))) scantime = time.time() if scanbase.check_kill(scansweepHelper.session): dsz.ui.Echo(('This session (%s) is marked for death. Exiting.' % scansweepHelper.session), dsz.ERROR) break if (__name__ == '__main__'): main(sys.argv[1:])