def import_report(): """ Import a MSF Pro XML Report. TODO: FINISH HIM! """ msf_settings = msf_get_config(session) if msf_settings['workspace'] is None: redirect(URL('api_settings')) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) if not msf.login(): response.flash = "Error logging into Metasploit, check your settings" redirect(URL('api_settings')) form = SQLFORM.factory( Field('whitelist', 'text', label=T('Whitelist hosts/nets')), Field('blacklist', 'text', label=T('Blacklist hosts/nets')), ) if form.accepts(request, sesssion): # build the configuration hash rpt_data = {} rpt_data['DS_REPORT_TYPE'] = 'XML' rpt_data['DS_WHITELIST_HOSTS'] = form.vars.whitelist rpt_data['DS_BLACKLIST_HOSTS'] = form.vars.blacklist rpt_data['Workdspace'] = msf_settings['workspace'] # send the report request and get the task id rpt_taskid = msf.pro_start_report(rpt_data)
def list_lootfiles(): """ Lists local loot files for import processing into Kvasir. This does not use the Metasploit API and depends upon a directory being local to the web2py server instance. The API is used to check if pro is installed and sets the loot_dir to Linux or Windows path """ import os import re response.title = "%s :: Metasploit Loots" % (settings.title) msf_settings = msf_get_config(session) dbsvcs = db.t_services loot_dir = request.args(0) if not loot_dir: try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) if msf.pro_about(): if platform in ["linux", "linux2"]: loot_dir = "/opt/metasploit_pro/apps/pro/loot" else: loot_dir = "C:\\Metasploit\\apps\\pro\\loot" except ImportError, error: pass
def task_list(): """Obtains a list of tasks""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit Task List" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, tasks=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(error=str(error), alert=True, tasks=None) tasks = msf.task_list() tasklist = [] if 'status' in request.vars: # only return specific tasks as defined in status for taskid, task in tasks.items(): if task['status'] == request.vars.status.lower(): tasklist.append({taskid: task}) else: tasklist = tasks return dict(tasks=tasklist)
def import_pwdump(): """Downloads a pwdump loot and processes it""" msf_settings = msf_get_config(session) alert = False error = None response.title = "%s :: Import Metasploit PWDUMP Loot" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(alert=True, error=str(error), form=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() data = msf.loot_list(msf_settings['workspace']) except MSFProAPIError as error: return dict(alert=True, error=str(error), form=None) if not alert: loot_list = [] # list of loot IDs and IPs loot_hosts = {} # mapping of IP to loot IDs for k, v in data.items(): if v['ltype'] == 'host.windows.pwdump' or v[ 'ltype'] == 'windows.hashes': loot_list.append([k, v['host']]) loot_hosts.setdefault(v['host'], k) form = SQLFORM.factory( Field('hosts', 'list', requires=IS_IN_SET(loot_list, multiple=True), label=T('Host')), Field('host_text', 'text', label=T('Host list (1 per line)')), Field('addevidence', 'boolean', label=T('Add to Evidence')), ) if form.accepts(request, session): from skaldship.metasploit import process_pwdump_loot data = [] # based on which form data is entered, make a new loot_list if len(form.vars.hosts) > 0: loot_list = form.vars.hosts elif len(form.vars.host_text) > 0: for ip in form.vars.host_text.split('\n'): try: loot_list.append(loot_hosts[ip]) except: logging.debug("%s not found in MSF loot list" % (ip)) continue retval = process_pwdump_loot(loot_list, msf) response.flash = "PWDUMP files imported\n%s" % (retval) elif form.errors: response.flash = "Errors in your form" else: form = None return dict(form=form, alert=alert, error=str(error))
def import_report_xml(): """ Upload/import Metasploit XML export file """ import time import os from skaldship.general import check_datadir msf_settings = msf_get_config(session) response.title = "%s :: Import Metasploit Pro Report XML" % (settings.title) filedir = os.path.join(request.folder,'data','scanfiles') fields = [] alert = False error = None # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append( [ user.id, user.username ] ) fields.append(Field('f_filename', 'upload', uploadfolder=filedir, label=T('Metasploit XML File'))) # check to see if we have a Metasploit Pro instance configured and talking # if so pull a list of the workspaces and present them try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) except ImportError, error: msf = None
def task_stop(): """Stop a running task""" msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, form=None)
def import_screenshots(): """ Import Screenshot files from Metasploit Pro into Kvasir """ response.title = "%s :: Import Metasploit Screenshots" % (settings.title) msf_settings = msf_get_config(session) loot_apidata = {} try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(form=None, error=str(error), alert=True) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() loot_apidata = msf.loot_list(msf_settings['workspace']) except MSFProAPIError as error: return dict(form=None, error=str(error), alert=True) loot_list = [] loot_dict = {} loot_hosts = {} for k, v in loot_apidata.items(): if v['ltype'] == 'host.windows.screenshot': loot_list.append([k, v['host']]) loot_dict.setdefault(k, v['host']) loot_hosts.setdefault(v['host'], k) form = SQLFORM.factory( Field('host', 'list', requires=IS_IN_SET(loot_list, multiple=True), label=T('Host')), Field('host_text', 'text', label=T('Host list (1 per line)')), ) if form.accepts(request, session): loots = [] # based on which form data is entered, make a new loot_list if form.vars.hosts: loot_list = form.vars.hosts elif form.vars.host_text: for ip in form.vars.host_text.split('\n'): try: loot_list.append(loot_hosts[ip]) except: logging.debug("%s not found in MSF loot list" % (ip)) continue loot_count = process_screenshot_loot(loot_list, msf) repsonse.flash = 'Screenshots added for %s host(s)' % (loot_count) elif form.errors: response.flash = "Errors in your form" return dict(form=form, alert=False, error=None)
def task_log(): """Show the details and log file of a specifc task""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit Task Log" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, data=None)
def send_accounts(): """Builds a list of username:passwords and sends it to Metasploit""" msf_settings = msf_get_config(session) response.title = "%s :: Send Kvasir Passwords to Metasploit Pro" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, form=None)
def task_list(): """Obtains a list of tasks""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit Task List" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, tasks=None)
def api_settings(): """Settings Metasploit API""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit API Settings" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, form=None) error = None alert = False msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: workspaces = [w for w in list(msf.pro_workspaces().keys())] users = [u for u in list(msf.pro_users().get('users').keys())] except MSFProAPIError as e: error = str(e) alert = True workspaces = [] users = [] form = SQLFORM.factory( Field('workspace', 'string', default=msf_settings['workspace'], label=T('Workspace Name'), requires=IS_IN_SET(workspaces)), Field('workspace_num', 'string', default=msf_settings['ws_num'], label=T('Workspace Number')), Field('user', 'string', default=msf_settings['user'], label=T('MSF User'), requires=IS_IN_SET(users)), Field('url', 'string', default=msf_settings['url'], label=T('MSF URL')), Field('key', 'string', default=msf_settings['key'], label=T('API Key')), ) # NOTE: workspace_num must be manually entered since there's no way for us # to learn it from the API. We're just guessing otherwise - 1 is the default # workspace so it's more likely to exist if form.accepts(request, session): settings.msf_workspace = form.vars.workspace settings.msf_workspace_num = form.vars.workspace_num session.msf_key = form.vars.key session.msf_url = form.vars.url session.msf_user = form.vars.user response.flash = "MSF Settings updated" elif form.errors: response.flash = "Errors in your form!" return dict(form=form, error=str(error), alert=False)
def task_status(): """Show details of a specifc task (but not the log file)""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit Task Status" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, data=None)
def api_settings(): """Settings Metasploit API""" msf_settings = msf_get_config(session) response.title = "%s :: Metasploit API Settings" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, form=None)
def exploit_host(): """ Build an exploit for a specific target """ msf_settings = msf_get_config(session) try: from MetasploitAPI import MetasploitAPI, MSFAPIError except ImportError, error: return dict(error=str(error), alert=True, form=None)
def send_scanxml(): """Sends scan XML output file to MSF Pro for importing""" import os response.title = "%s :: Send Scan XML Data to Metasploit" % (settings.title) msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(error=str(error), alert=True, form=None)
def import_pwdump(): """Downloads a pwdump loot and processes it""" msf_settings = msf_get_config(session) alert = False error = None response.title = "%s :: Import Metasploit PWDUMP Loot" % (settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(alert=True, error=str(error), form=None)
def bruteforce(): """ Launches a Metasploit Pro Bruteforce based upon a list of host records """ response.title = "%s :: Metasploit Pro Bruteforce" % (settings.title) msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(alert=True, error=str(error), form=None)
def import_scan(): """ Upload and import Nexpose Scan file """ msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False from skaldship.general import check_datadir import time import os filedir = os.path.join(request.folder, 'data', 'scanfiles') response.title = "%s :: Import Nessus Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) nessus_config = nessus_get_config() # {'ignored_vulnids': [19506, 11219, 34277], # 'servers': {'server_1': {'password': '******', # 'url': 'https://localhost:8834/', # 'user': '******'}}} nessusreports = [[0, None]] import NessusAPI #if auth.user.f_nessus_host is not None: servers = nessus_config.get('servers', {}) for k, v in servers.iteritems(): try: # check to see if NessusAPI is working nessus = NessusAPI.NessusConnection(v.get('user'), v.get('password'), url=v.get('url')) reports = nessus.list_reports() for report in reports: ts = time.ctime(float(report.timestamp)) nessusreports.append([ "%s:%s" % (k, report.name), "%s: %s - %s (%s)" % (k, report.readablename, ts, report.status) ]) except Exception, e: logger.error("Error communicating with %s: %s" % (k, str(e)))
def import_screenshots(): """ Import Screenshot files from Metasploit Pro into Kvasir """ response.title = "%s :: Import Metasploit Screenshots" % (settings.title) msf_settings = msf_get_config(session) loot_apidata={} try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError, error: return dict(form=None, error=str(error), alert=True)
def import_scan(): """ Upload and import Nexpose Scan file """ msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitAPI import MetasploitAPI msf_api = MetasploitAPI(host=msf_settings["url"], apikey=msf_settings["key"]) working_msf_api = msf_api.login() except: working_msf_api = False from skaldship.general import check_datadir import time import os filedir = os.path.join(request.folder, "data", "scanfiles") response.title = "%s :: Import Nessus Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) nessus_config = nessus_get_config(session) # {'ignored_vulnids': [19506, 11219, 34277], # 'servers': {'server_1': {'password': '******', # 'url': 'https://localhost:8834/', # 'user': '******'}}} nessusreports = [[0, None]] import NessusAPI # if auth.user.f_nessus_host is not None: servers = nessus_config.get("servers", {}) for k, v in servers.iteritems(): try: # check to see if NessusAPI is working nessus = NessusAPI.NessusConnection(v.get("user"), v.get("password"), url=v.get("url")) reports = nessus.list_reports() for report in reports: ts = time.ctime(float(report.timestamp)) nessusreports.append( ["%s:%s" % (k, report.name), "%s: %s - %s (%s)" % (k, report.readablename, ts, report.status)] ) except Exception, e: logger.error("Error communicating with %s: %s" % (k, str(e)))
def import_xml_scan(): """ Upload/import Nexpose XML Scan file via scheduler task """ from NexposeAPI import NexposeAPI, Sites, Report from skaldship.general import check_datadir from skaldship.metasploit import msf_get_config import time import os msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False filedir = os.path.join(request.folder, 'data', 'scanfiles') response.title = "%s :: Import Nexpose XML Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) # check to see if nexpose is configured/active and get site listing nexpose_config = nexpose_get_config() nxsitelist = [] if nexpose_config['host'] is not None and nexpose_config[ 'user'] is not None: # see if the host is open/active first if nexpose_config['host'] is not None: sites = Sites() sites.host = nexpose_config['host'] sites.port = nexpose_config['port'] try: if sites.login(user_id=nexpose_config['user'], password=nexpose_config['password']): sites = sites.listings() nxsitelist.append([0, None]) for k, v in sites.iteritems(): nxsitelist.append([int(k), sites[k]['name']]) except Exception, e: pass
def import_xml_scan(): """ Upload/import Nexpose XML Scan file via scheduler task """ from NexposeAPI import NexposeAPI, Sites, Report from skaldship.general import check_datadir from skaldship.metasploit import msf_get_config import time import os msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings["url"], apikey=msf_settings["key"]) working_msf_api = msf_api.login() except: working_msf_api = False filedir = os.path.join(request.folder, "data", "scanfiles") response.title = "%s :: Import Nexpose XML Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) # check to see if nexpose is configured/active and get site listing nexpose_config = nexpose_get_config() nxsitelist = [] if nexpose_config["host"] is not None and nexpose_config["user"] is not None: # see if the host is open/active first if nexpose_config["host"] is not None: sites = Sites() sites.host = nexpose_config["host"] sites.port = nexpose_config["port"] try: if sites.login(user_id=nexpose_config["user"], password=nexpose_config["password"]): sites = sites.listings() nxsitelist.append([0, None]) for k, v in sites.iteritems(): nxsitelist.append([int(k), sites[k]["name"]]) except Exception, e: pass
def task_stop(): """Stop a running task""" msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, form=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(error=str(error), alert=True, form=None) if 'taskid' not in request.vars: tasks = msf.task_list() task_list = [] for taskid, task in tasks.items(): if tasks[taskid]['status'] == 'running': task_list.append([ taskid, "%s (%s) :: %s :: %s" % ( taskid, tasks[taskid]['status'], tasks[taskid]['description'], tasks[taskid]['info'], ) ]) form = SQLFORM.factory( Field('taskid', 'string', requires=IS_IN_SET(task_list), label=T('Task ID'))) return dict(form=form) response.title = "%s :: Stop Metasploit Task" % (settings.title) data = msf.task_stop(request.vars.taskid) return dict(data=data)
def exploit_host(): """ Build an exploit for a specific target TODO: Finish metasploit.exploit_host """ msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, form=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(error=str(error), alert=True, form=None) target = request.vars.f_target or None exploit = request.vars.f_exploit or None form = SQLFORM.factory()
def exploit(): """ Launches Metasploit Pro Exploit based upon a list of host records """ response.title = "%s :: Metasploit Pro Exploit" % (settings.title) msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(alert=True, error=str(error), form=None) host_records = request.vars.host_records if host_records: def host_to_ip(host_rec): if isinstance(host_rec, (int, str)): host_rec = get_host_record(host_rec) if not host_rec: return None return host_rec.get('f_ipaddr') target_ips = '\n'.join( [host_to_ip(x) for x in host_records.split('|')]) else: target_ips = '' module_list = [] alert = False msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: module_list = msf.module_list(modtype='exploits').get('modules') except MSFProAPIError as error: return dict(alert=True, error=str(error), form=None) form = SQLFORM.factory( Field( 'targets', 'text', default=target_ips, label=T('Targets'), requires=IS_NOT_EMPTY(), comment= T('Targets to scan can be IP Addresses, ranged lists or subnets. One per line.' )), Field( 'blacklist_hosts', 'text', label=T('Blacklisted Targets'), comment= T('Targets to blacklist can be IP Addresses, ranged lists or subnets. One per line.' )), Field( 'ports', 'string', default='1-65535', label=T('Ports'), requires=IS_NOT_EMPTY(), comment= T('List of ports to match exploits to. Example: 21-23,80,443,8000-8999' )), Field( 'blacklist_ports', 'string', label=T('Blacklisted Ports'), comment=T( 'List of ports to not exploit. Example: 21-23,80,443,8000-8999' )), Field('min_rank', 'string', default='great', label=T('Minmum Exploit Rank'), requires=IS_IN_SET( ['low', 'average', 'normal', 'good', 'great', 'excellent']), comment=T('Minimum reliability level of exploits to include')), Field('exploit_speed', 'integer', default=5, label=T('Parallel Exploits'), requires=IS_INT_IN_RANGE(1, 11), comment=T('How many exploits to run in parallel (1-10)')), Field('exploit_timeout', 'integer', default=5, label=T('Timeout (in minutes)'), requires=IS_INT_IN_RANGE(0, 1440), comment=T( 'Maximum time (in minutes) an exploit is allowed to run')), Field('limit_sessions', 'boolean', default=True, label=T('Limit sessions'), comment=T('Limit sessions to only one per exploited host')), Field( 'ignore_fragile', 'boolean', default=True, label=T('Skip "fragile" devices'), comment= T('Avoid exploit attempts on fragile systems such as network devices and printers.' )), Field( 'filter_by_os', 'boolean', default=True, label=T('OS'), comment= T('Match exploits to Operating System, known vulnerabilities or ports' )), Field('filter_by_vuln', 'boolean', default=True, label=T('Vulnerabilities')), Field('filter_by_ports', 'boolean', default=True, label=T('Ports')), Field('dry_run', 'boolean', default=False, label=T('Dry run'), comment=T('Prepare for execution but do nothing')), Field('payload', 'string', default='auto', label=T('Payload method'), requires=IS_IN_SET(['auto', 'reverse', 'bind'])), Field('payload_type', 'string', default='meterpreter', label=T('Paylod type'), requires=IS_IN_SET(['meterpreter', 'shell'])), Field('payload_ports', 'string', default='4000-5000', label=T('Payload ports'), requires=IS_NOT_EMPTY(), comment=T('Port range for reverse/connect payloads')), Field('evasion_tcp', 'integer', default=0, label=T('TCP Evasion Level'), requires=IS_INT_IN_RANGE(0, 4)), Field('evasion_app', 'integer', default=0, label=T('Application Evasion'), requires=IS_INT_IN_RANGE(0, 4)), Field( 'modules', 'list:string', label=T('Specifc Module(s)'), requires=IS_EMPTY_OR(IS_IN_SET(module_list, multiple=True)), comment= T('A whitelist of modules to execute, by default all that match are tried' )), table_name='msfpro_exploit', _class="form-horizontal") if form.process().accepted: args = { 'workspace': msf_settings['workspace'], 'username': msf_settings['user'], 'DS_WHITELIST_HOSTS': form.vars.targets, 'DS_BLACKLIST_HOSTS': form.vars.blacklist_hosts, 'DS_WHITELIST_PORTS': form.vars.ports, 'DS_BLACKLIST_PORTS': form.vars.blacklist_ports, 'DS_MinimumRank': form.vars.min_rank, 'DS_EXPLOIT_SPEED': form.vars.exploit_speed, 'DS_EXPLOIT_TIMEOUT': form.vars.exploit_timeout, 'DS_LimitSessions': form.vars.limit_sessions, 'DS_IgnoreFragileDevices': form.vars.ignore_fragile, 'DS_FilterByOS': form.vars.filter_by_os, 'DS_MATCH_VULNS': form.vars.filter_by_vuln, 'DS_MATCH_PORTS': form.vars.filter_by_ports, 'DS_OnlyMatch': form.vars.dry_run, 'DS_PAYLOAD_METHOD': form.vars.payload, 'DS_PAYLOAD_TYPE': form.vars.payload_type, 'DS_PAYLOAD_PORTS': form.vars.payload_ports, 'DS_EVASION_LEVEL_TCP': form.vars.evasion_tcp, 'DS_EVASION_LEVEL_APP': form.vars.evasion_app, #'DS_ModuleFilter': form.vars.filter_by_os, } task = msf.start_exploit(args) msfurl = os.path.join(msf_settings['url'], 'workspaces', msf_settings['workspace_num'], 'tasks', task['task_id']) redirect(msfurl) elif form.errors: response.flash = "Error in form" return dict(form=form, alert=alert)
def vulndata_by_host(): """ Returns a list of vulnerabilties based upon an host identifier (id, ipv4, ipv6) """ from skaldship.metasploit import msf_get_config msf_settings = msf_get_config(session) record = get_host_record(request.args(0)) if record is None: redirect(URL('default', 'error', vars={'msg': T('Host record not found')})) response.title = "%s :: Vulnerabilities for %s" % (settings.title, host_title_maker(record)) services = db(db.t_services.f_hosts_id==record.id).select(db.t_services.id, db.t_services.f_proto, db.t_services.f_number) if request.extension == "json": aaData = [] for svc in services: # service info q = db(db.t_service_vulns.f_services_id == svc.id).select() for vulninfo in q: atxt = {} exploit_list = [] vulndetails = db(db.t_vulndata.id == vulninfo.f_vulndata_id).select(cache=(cache.ram, 300)).first() exploits = db(db.t_exploit_references.f_vulndata_id == vulninfo.f_vulndata_id).select(orderby=~db.t_exploit_references.id) if len(exploits) > 0: expl_count = "Yes (%d)" % (len(exploits)) for expl in exploits: for expl_data in db(db.t_exploits.id == expl.f_exploit_id).select(cache=(cache.ram, 300)): exp_link = expl_data.f_name if expl_data.f_source == 'exploitdb': if db.t_exploitdb[expl_data.f_title]: exploitdb_href = URL('exploitdb', 'detail.html', args=expl_data.f_title) else: exploitdb_href = URL('default', 'redirect', extension='html', vars={'url': 'http://www.exploit-db.com/exploits/%s' % expl_data.f_title}) exp_link = A(IMG(_align="absmiddle", _width=16, _height=16, _src=URL('static','images/exploitdb.ico')), ' exploitdb - ' + expl_data.f_name,_href=exploitdb_href, _target="exploitdb_%s" % (expl_data.f_name)) elif expl_data.f_source == 'metasploit': if session.msf_workspace: msf_uri = os.path.join(msf_settings['url'], 'workspaces', session.msf_workspace_num, 'modules', expl_data.f_title) else: msf_uri = URL('default', 'redirect', extension='html', vars={'url': 'http://www.rapid7.com/db/modules/%s' % expl_data.f_title}) exp_link = A(IMG(_align="absmiddle", _width=16, _height=16, _src=URL('static','images/msf.gif')), ' metasploit - ' + expl_data.f_name, _href=msf_uri, _target="msf_%s" % (expl_data.f_name)) elif expl_data.f_source == 'canvas': exp_link = SPAN(IMG(_align="absmiddle", _width=16, _height=16, _src=URL('static','images/canvas.png')), ' canvas - ' + expl_data.f_name) exploit_list.append("%s : %s (%s/%s)" % (expl_data.f_title, exp_link, expl_data.f_rank, expl_data.f_level)) else: expl_count = "" atxt['0'] = IMG(_src=URL(request.application,'static','images/details_open.png')).xml() atxt['1'] = A('edit', _target="service_vuln_update_%s" % (vulninfo.id), _href=URL('vulns', 'service_vulns_edit', args=vulninfo.id, extension='html')).xml() if vulninfo.f_exploited: atxt['2'] = '<input id="exploited" value="' + str(vulninfo.id) + '" type="checkbox", checked>' else: atxt['2'] = '<input id="exploited" value="' + str(vulninfo.id) + '" type="checkbox">' atxt['3'] = "%s/%s" % (svc.f_proto, svc.f_number) atxt['4'] = A(vulndetails.f_vulnid, _target="vulndata_%s" % (vulndetails.id), _href=URL('vulns', 'vulninfo_by_vulnid', args=vulndetails.f_vulnid, extension='html')).xml() atxt['5'] = vulndetails.f_severity atxt['6'] = vulndetails.f_cvss_score atxt['7'] = SPAN(vulninfo.f_status,_id="vulninfo_status",_vulnstatus=vulninfo.f_status).xml() atxt['8'] = expl_count atxt['9'] = MARKMIN(vulninfo.f_proof).xml() atxt['10'] = MARKMIN(vulndetails.f_description).xml() atxt['11'] = vulndetails.f_title atxt['12'] = "<br />\n".join(exploit_list) atxt['DT_RowId'] = vulninfo.id aaData.append(atxt) result = { 'sEcho': request.vars.sEcho, 'iTotalRecords': len(aaData), 'aaData': aaData, } return result add = AddModal( db.t_service_vulns, 'Add', 'Add', 'Add Vulnerability', #fields=[ #], cmd='vulntable.fnReloadAjax();' ) #db.t_service_vulns.f_services_id.default = svc.id svc_set = [] for svc in services: svc_set.append([svc.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.id]), svc.f_proto, svc.f_number)]) db.t_service_vulns.f_services_id.requires = IS_IN_SET(svc_set) db.t_service_vulns.id.comment = add.create() form = TABLE(THEAD(TR(TH('', _width="5%"), TH(T(''), _width="5%"), TH(T('Pwned'), width="5%"), TH(T('Port')), TH(T('Vuln ID')), TH(T('Sev')), TH(T('CVSS')), TH(T('Status')), TH(T('Exploits')), TH(T('Proof')), TH(T('Description')), TH(T('Title')), TH(T('Exploit List')), ) ), _class="datatable", _id="vulntable", _style="width:100%") return dict(form=form, host=record, add=add)
def import_scan(): """ Upload and import Nessus Scan file """ msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False from skaldship.general import check_datadir import time import os filedir = os.path.join(request.folder, 'data', 'scanfiles') response.title = "%s :: Import Nessus Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) nessus_config = nessus_get_config() # {'ignored_vulnids': [19506, 11219, 34277], # 'servers': {'server_1': {'password': '******', # 'url': 'https://localhost:8834/', # 'user': '******'}}} nessusreports = [[0, None]] import NessusAPI from skaldship.nessus.ness6api import Nessus6API servers = nessus_config.get('servers', {}) for k, v in servers.items(): if v.get('version') == 6: # nessus >= 6 try: nessus = Nessus6API(url=v.get('url'), username=v.get('username'), password=v.get('password'), access_key=v.get('access_key'), secret_key=v.get('secret_key'), verify=v.get('verify_ssl'), proxies=v.get('proxies')) except Exception as e: logger.error("Error communicating with %s: %s" % (k, str(e))) try: for report in nessus.get_scans(): ts = time.ctime( float(report.get('last_modification_date', 0))) nessusreports.append([ "%s:%s" % (k, report.get('id')), "%s: %s - %s (%s)" % (k, report.get('name'), ts, report.get('status')) ]) except Exception as e: logger.error("Error making scan list: %s" % (str(e))) else: # nessus <= 5 try: # check to see if NessusAPI is working nessus = NessusAPI.NessusConnection(v.get('user'), v.get('password'), url=v.get('url')) reports = nessus.list_reports() for report in reports: ts = time.ctime(float(report.timestamp)) nessusreports.append([ "%s:%s" % (k, report.name), "%s: %s - %s (%s)" % (k, report.readablename, ts, report.status) ]) except Exception as e: logger.error("Error communicating with %s: %s" % (k, str(e))) if len(nessusreports) > 1: fields.append( Field('f_nessus_report', type='integer', label=T('Nessus Report'), requires=IS_IN_SET(nessusreports, zero=None))) fields.append( Field('f_filename', 'upload', uploadfolder=filedir, label=T('Nessus Scan File'))) fields.append( Field('f_engineer', type='integer', label=T('Engineer'), default=auth.user.id, requires=IS_IN_SET(userlist))) fields.append( Field('f_asset_group', type='string', label=T('Asset Group'), requires=IS_NOT_EMPTY())) # check to see if we have a Metasploit Pro instance configured and talking # if so pull a list of the workspaces and present them if working_msf_api: msf_workspaces = ["None"] for w in list(msf_api.pro_workspaces().keys()): msf_workspaces.append(w) fields.append( Field('f_msf_workspace', type='string', label=T('MSF Pro Workspace'), requires=IS_EMPTY_OR(IS_IN_SET(msf_workspaces, zero=None)))) fields.append( Field('f_include_list', type='text', label=T('Hosts to Only Include'))) fields.append( Field('f_ignore_list', type='text', label=T('Hosts to Ignore'))) fields.append( Field('f_update_hosts', type='boolean', label=T('Update Host Information'), default=False)) fields.append( Field('f_taskit', type='boolean', default=auth.user.f_scheduler_tasks, label=T('Run in background task'))) form = SQLFORM.factory(*fields, table_name='nessus_scan') # form processing if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # if no Nessus servers configured or valid, set report_name to 0 if nessusreports == [[0, None]]: report_name = '0' else: if form.vars.f_nessus_report != "0": # If a nessus report is selected, try to parse it to set report_name try: (server, report_name) = form.vars.f_nessus_report.split(':') except ValueError as e: msg = "Invalid report name sent: %s" % ( form.vars.f_nessus_report) response.flash = msg logging.error(msg) return dict(form=form) else: # set report_name to 0 if no f_nessus_report sent report_name = '0' if report_name != '0': # download a report from a Nessus server n_server = nessus_config.get('servers').get(server) filename = os.path.join( filedir, "nessus-%s-%s.xml" % (form.vars.f_asset_group, int(time.time()))) check_datadir(request.folder) if n_server.get('version') == 6: # nessus version => 6 try: nessus = Nessus6API(url=n_server.get('url'), username=n_server.get('username'), password=n_server.get('password'), access_key=n_server.get('access_key'), secret_key=n_server.get('secret_key'), verify=n_server.get('verify_ssl'), proxies=n_server.get('proxies')) nessus_report = nessus.report_download(report_name) fout = open(filename, "w") fout.write(nessus_report) fout.close() except Exception as e: msg = ("Error download Nessus report: %s" % (e)) logger.error(msg) response.flash = msg return dict(form=form) else: # nessus version <= 5 try: # build a new nessus connection with the configured server details and download the report n_server = nessus_config.get('servers').get(server) nessus = NessusAPI.NessusConnection( n_server.get('user'), n_server.get('password'), url=n_server.get('url')) fout = open(filename, "w") nessus.download_report(report_name, fout) fout.close() except Exception as e: msg = ("Error download Nessus report: %s" % (e)) logger.error(msg) response.flash = msg return dict(form=form) else: filename = os.path.join(filedir, form.vars.f_filename) # build the hosts only/exclude list ip_exclude = [] data = form.vars.get('f_ignore_list') if data: ip_exclude = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals ip_include = [] data = form.vars.get('f_include_list') if data: ip_include = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals if form.vars.f_msf_workspace: msf_workspace = form.vars.f_msf_workspace if msf_workspace == "None": msf_workspace = None else: msf_workspace = None msf_settings = { 'workspace': msf_workspace, 'url': msf_settings['url'], 'key': msf_settings['key'] } if form.vars.f_taskit: task = scheduler.queue_task( scanner_import, pvars=dict( scanner='nessus', filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, msf_settings=msf_settings, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ), group_name=settings.scheduler_group_name, sync_output=5, timeout=settings.scheduler_timeout) if task.id: redirect(URL('tasks', 'status', args=task.id)) else: response.flash = "Error submitting job: %s" % (task.errors) else: from skaldship.nessus.processor import process_scanfile logger.info("Starting Nessus Report Import") response.flash = process_scanfile( filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, msf_settings=msf_settings, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ) redirect(URL('default', 'index')) return dict(form=form)
"--msfidx", dest="msfidx", action="store", default=0, help="Metasploit workspace index") (options, params) = optparser.parse_args() rows = db(db.auth_user.username == options.engineer) if rows.count() != 1: exit( "An error was encountered when selecting a user. Please try with a valid user name." ) msf_settings = msf_get_config(session) msf_workspaces = [None] try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False if working_msf_api: for w in msf_api.pro_workspaces().keys():
def send_scanxml(): """Sends scan XML output file to MSF Pro for importing""" import os response.title = "%s :: Send Scan XML Data to Metasploit" % ( settings.title) msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, form=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(error=str(error), alert=True, form=None) filedir = os.path.join(request.folder, 'data', 'scanfiles') try: scanfiles = os.listdir(filedir) except OSError: scanfiles = [] file_select = [] count = 0 for fn in scanfiles: file_select.append([count, fn]) count += 1 form = SQLFORM.factory( Field('fname', 'string', requires=IS_IN_SET(file_select), label=T('Scan File')), Field( 'blacklist', 'text', label=T('Blacklisted hosts'), comment= T('Targets to blacklist can be IP Addresses, ranged lists or subnets. One per line.' )), Field('preserve_hosts', 'boolean', default=False, label=T('Preserve existing hosts')), ) if form.accepts(request, session): fname = file_select[int(form.vars.fname)][1] fname = os.path.join(filedir, fname) try: scan_data = open(fname, "r+").readlines() except Exception as error: return dict(form=form, error=str(error), alert=True) task = msf.pro_import_data( msf_workspace, "".join(scan_data), { 'preserve_hosts': form.vars.preserve_hosts, 'blacklist_hosts': "\n".join(form.vars.blacklist) }, ) """ # documented in API but not valid yet @9/6/13 #validate = msf.pro_validate_import_file(fname) task = msf.pro_start_import({ 'workspace': msf_workspace, 'username': msf_settings['user'], 'DS_PATH': fname, 'DS_PRESERVE_HOSTS': form.vars.preserve_hosts, 'DS_BLACKLIST_HOSTS': "\n".join(form.vars.blacklist), 'DS_REMOVE_FILE': False, 'DS_ImportTags': True, }) """ msfurl = os.path.join(msf_settings['url'], 'workspaces', msf_settings['workspace_num'], 'tasks', task['task_id']) redirect(msfurl) elif form.errors: response.flash = "Errors in your form" return dict(form=form, alert=False, error=None)
def bruteforce(): """ Launches a Metasploit Pro Bruteforce based upon a list of host records """ response.title = "%s :: Metasploit Pro Bruteforce" % (settings.title) msf_settings = msf_get_config(session) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(alert=True, error=str(error), form=None) host_records = request.vars.host_records if host_records: def host_to_ip(host_rec): if isinstance(host_rec, (int, str)): host_rec = get_host_record(host_rec) if not host_rec: return None return host_rec.get('f_ipaddr') target_ips = '\n'.join( [host_to_ip(x) for x in host_records.split('|')]) else: target_ips = '' loot_list = [] # list of loot IDs and IPs alert = False msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(alert=True, error=str(error), form=None) form = SQLFORM.factory( Field( 'targets', 'text', default=target_ips, label=T('Targets'), requires=IS_NOT_EMPTY(), comment= T('Targets to scan can be IP Addresses, ranged lists or subnets. One per line.' ), ), Field( 'blacklist', 'text', label=T('Blacklisted hosts'), comment= T('Targets to blacklist can be IP Addresses, ranged lists or subnets. One per line.' )), Field( 'stop_on_success', 'boolean', default=True, label=T('Stop on success'), comment=T('Stop scanning a host after first user login success')), Field('verbose', 'boolean', default=False, label=T('Verbose')), Field('include_known', 'boolean', default=True, label=T('Include known'), comment=T('Include known credentials from the Workspace')), Field('dry_run', 'boolean', default=False, label=T('Dry run'), comment=T('Prepare for execution but do nothing')), Field( 'scope', 'string', default='normal', label=T('Scope'), requires=IS_IN_SET([ 'quick', 'defaults', 'normal', 'deep', 'known', 'imported', '50k' ]), ), Field('speed', 'string', default=3, label=T('Speed'), requires=IS_IN_SET([[0, 'Glacial'], [1, 'Slow'], [2, 'Stealthy'], [3, 'Normal'], [4, 'Fast'], [5, 'Turbo']])), Field( 'services', 'list:string', label=T('Services'), requires=IS_EMPTY_OR( IS_IN_SET([ 'Telnet', 'SSH', 'SMB', 'VNC', 'SNMP', 'Postgres', 'MySQL', 'MSSQL', 'Oracle', 'DB2', 'FTP', 'HTTP', 'HTTPS', 'EXEC', 'LOGIN', 'SHELL', ], multiple=(1, 17))), comment=T('List of services to bruteforce, multiples permitted')), Field( 'addl_creds', 'text', label=T('Additional credentals'), comment= T('List additional credentials to test. One per line with space between username and password.' )), Field('getsession', 'boolean', default=True, label=T('Execute session'), comment=T( 'On successful access pop a shell or meterpreter session')), Field('payload', 'string', default='auto', label=T('Payload method'), requires=IS_IN_SET(['auto', 'reverse', 'bind'])), Field('payload_type', 'string', default='meterpreter', label=T('Paylod type'), requires=IS_IN_SET(['meterpreter', 'shell'])), Field( 'payload_ports', 'string', default='4000-5000', label=T('Payload ports'), requires=IS_NOT_EMPTY(), comment=T('Port range for reverse/connect payloads'), ), Field('smb_domains', 'string', label=T('SMB Domains'), comment=T('List of SMB domains, separated by spaces, to use')), Field( 'preverse_domains', 'boolean', default=True, label=T('Preserve Domains'), comment=T('Use previously identified SMB Domains with usernames')), Field('mssql_windows_auth', 'boolean', default=False, label=T('MSSQL Windows Auth'), comment=T( 'MSSQL attempts should use NTLM instead of Standard mode')), Field('skip_blank_pw', 'boolean', default=False, label=T('Blanks')), Field('skip_machine_names', 'boolean', default=False, label=T('Machine names')), Field('skip_builtin_windows', 'boolean', default=False, label=T('Built-in Windows')), Field('skip_builtin_unix', 'boolean', default=False, label=T('Built-in UNIX')), Field('recombine_creds', 'boolean', default=False, label=T('Recombine credentials')), Field('max_guess_per_svc', 'integer', default=0, label=T('Per service'), requires=IS_INT_IN_RANGE(0, 65535)), Field('max_guess_per_user', 'integer', default=0, label=T('Per user'), requires=IS_INT_IN_RANGE(0, 65535)), Field('max_guess_overall', 'integer', default=0, label=T('Overall'), requires=IS_INT_IN_RANGE(0, 65535)), Field('max_time_per_svc', 'integer', default=0, label=T('Per service'), requires=IS_INT_IN_RANGE(0, 1440), comment=T('Maximum time to bruteforce per service (in minutes')), Field('max_time', 'integer', default=0, label=T('Overall'), requires=IS_INT_IN_RANGE(0, 65535), comment=T('Maximum time to run brute force (in minutes)')), table_name='msfpro_bruteforce', _class="form-horizontal") if form.process().accepted: args = { 'workspace': msf_settings['msf_workspace'], 'username': msf_settings['user'], 'DS_WHITELIST_HOSTS': form.vars.targets, 'DS_BLACKLIST_HOSTS': form.vars.blacklist, 'DS_STOP_ON_SUCCESS': form.vars.stop_on_success, 'DS_VERBOSE': form.vars.verbose, 'DS_INCLUDE_KNOWN': form.vars.include_known, 'DS_DRY_RUN': form.vars.dry_run, 'DS_BRUTEFORCE_SCOPE': form.vars.scope, 'DS_BRUTEFORCE_SPEED': form.vars.speed, 'DS_BRUTEFORCE_SERVICES': " ".join(form.vars.services), 'DS_BRUTEFORCE_GETSESSION': form.vars.getsession, 'DS_QUICKMODE_CREDS': form.vars.addl_creds, 'DS_PAYLOAD_METHOD': form.vars.payload, 'DS_PAYLOAD_TYPE': form.vars.payload_type, 'DS_PAYLOAD_PORTS': form.vars.payload_ports, 'DS_SMB_DOMAINS': form.vars.smb_domains, 'DS_PRESERVE_DOMAINS': form.vars.preverse_domains, 'DS_MAXGUESSESPERSERVICE': form.vars.max_guess_per_svc, 'DS_MAXGUESSESPERUSER': form.vars.max_guess_per_user, 'DS_MAXGUESSESOVERALL': form.vars.max_guess_overall, 'DS_MAXMINUTESPERSERVICE': form.vars.max_time_per_svc, 'DS_MAXMINUTESOVERALL': form.vars.max_time, 'DS_BRUTEFORCE_SKIP_BLANK_PASSWORDS': form.vars.skip_blank_pw, 'DS_BRUTEFORCE_SKIP_MACHINE_NAMES': form.vars.skip_machine_names, 'DS_BRUTEFORCE_SKIP_BUILTIN_WINDOWS_ACCOUNTS': form.vars.skip_builtin_windows, 'DS_BRUTEFORCE_SKIP_BLANK_BUILTIN_UNIX_ACCOUNTS': form.vars.skip_builtin_unix, 'DS_BRUTEFORCE_RECOMBINE_CREDS': form.vars.recombine_creds, 'DS_MSSQL_WINDOWS_AUTH': form.vars.mssql_windows_auth } task = msf.start_bruteforce(args) msfurl = os.path.join(msf_settings['url'], 'workspaces', msf_settings['workspace_num'], 'tasks', task['task_id']) redirect(msfurl) elif form.errors: response.flash = "Error in form" return dict(form=form, alert=alert, error=False)
def import_report_xml(): """ Upload/import Metasploit XML export file """ import time import os from skaldship.general import check_datadir msf_settings = msf_get_config(session) response.title = "%s :: Import Metasploit Pro Report XML" % ( settings.title) filedir = os.path.join(request.folder, 'data', 'scanfiles') fields = [] alert = False error = None # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) fields.append( Field('f_filename', 'upload', uploadfolder=filedir, label=T('Metasploit XML File'))) # check to see if we have a Metasploit Pro instance configured and talking # if so pull a list of the workspaces and present them try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) except ImportError as error: msf = None if msf: try: msf_reports_res = msf.report_list( workspace=msf_settings['workspace']) except MSFProAPIError as error: msf_reports_res = None if msf_reports_res: from datetime import datetime msf_reports = [] for rpt in list(msf_reports_res.keys()): report_name = "Generated: %s" % (datetime.strftime( datetime.fromtimestamp(msf_reports_res[rpt]['created_at']), "%m-%d-%y %H:%M:%S")) msf_reports.append([rpt, report_name]) fields.append( Field('f_msf_report', type='string', label=T('MSF Pro Report'), requires=IS_EMPTY_OR(IS_IN_SET(msf_reports, zero=None)))) fields.append( Field('f_engineer', type='integer', label=T('Engineer'), default=auth.user.id, requires=IS_IN_SET(userlist))) fields.append( Field('f_asset_group', type='string', label=T('Asset Group for new Hosts'), default="Metasploit Import", requires=IS_NOT_EMPTY())) fields.append( Field('f_include_list', type='text', label=T('Hosts to Only Include'))) fields.append( Field('f_ignore_list', type='text', label=T('Hosts to Ignore'))) fields.append( Field('f_update_hosts', type='boolean', default=True, label=T('Update Existing Hosts'))) fields.append( Field('f_taskit', type='boolean', default=auth.user.f_scheduler_tasks, label=T('Run in background task'))) form = SQLFORM.factory(*fields, table_name='metasploit_xml') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # build the hosts only/exclude list ip_exclude = [] data = form.vars.get('f_ignore_list') if data: ip_exclude = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals ip_include = [] data = form.vars.get('f_include_list') if data: ip_include = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals if form.vars.f_msf_report: try: msf_report = msf.report_download(rptid=form.vars.f_msf_report) except MSFProAPIError as error: error = "Unable to download report from Metasploit Pro: %s" % ( str(error)) return dict(form=form, alert=True, error=error) check_datadir(request.folder) filename = os.path.join( filedir, "msfpro-%s-%s.xml" % (msf_settings['workspace'], int(time.time()))) fout = open(filename, "w") fout.write(msf_report['data']) fout.close() del (msf_report) else: filename = os.path.join(filedir, form.vars.f_filename) if form.vars.f_taskit: task = scheduler.queue_task( scanner_import, pvars=dict( scanner='metasploit', filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ), group_name=settings.scheduler_group_name, sync_output=5, timeout=settings.scheduler_timeout) if task.id: redirect(URL('tasks', 'status', args=task.id)) else: response.flash = "Error submitting job: %s" % (task.errors) else: from skaldship.metasploit.pro import process_report_xml logger.info("Starting Metasploit XML Import") result = process_report_xml( filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ) response.flash = result redirect(URL('default', 'index')) return dict(form=form, alert=alert, error=error)
action="store", default=getpass.getuser(), help="User to import data.") optparser.add_option("-n", "--noports", dest="noports", action="store_true", default=False, help="Add hosts without ports.") optparser.add_option("-u", "--update", dest="update_hosts", action="store_true", default=False, help="Update hosts.") optparser.add_option("-m", "--msfidx", dest="msfidx", action="store", default=0, help="Metasploit workspace index") (options, params) = optparser.parse_args() rows = db(db.auth_user.username == options.engineer) if rows.count() != 1: exit("An error was encountered when selecting a user. Please try with a valid user name.") msf_settings = msf_get_config(session) msf_workspaces = [None] try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False if working_msf_api: for w in msf_api.pro_workspaces().keys(): msf_workspaces.append(w)
def list_lootfiles(): """ Lists local loot files for import processing into Kvasir. This does not use the Metasploit API and depends upon a directory being local to the web2py server instance. The API is used to check if pro is installed and sets the loot_dir to Linux or Windows path """ import os import re response.title = "%s :: Metasploit Loots" % (settings.title) msf_settings = msf_get_config(session) dbsvcs = db.t_services loot_dir = request.args(0) if not loot_dir: try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) if msf.pro_about(): if platform in ["linux", "linux2"]: loot_dir = "/opt/metasploit_pro/apps/pro/loot" else: loot_dir = "C:\\Metasploit\\apps\\pro\\loot" except ImportError as error: pass if not loot_dir: from sys import platform if platform in ["linux", "linux2", "darwin", "freebsd"]: loot_dir = os.path.join(os.environ.get('HOME'), '.msf4/loot') elif platform in ["win32", "cygwin"]: loot_dir = '$FINDYOUR/msf4/loot/path' try: os.chdir(loot_dir) loot_files = os.listdir(loot_dir) except OSError: loot_files = [] loot_file_details = [] for loot in loot_files: try: (timestamp, workspace, ipaddr, filetype, extension) = re.split('_', loot) except ValueError: logging.warn("Invalid loot file: %s" % (loot)) continue # TODO: service_list = get_services(ipaddr) host_rec = get_host_record(ipaddr) services = [] for service in db(dbsvcs.f_hosts_id == host_rec).select( dbsvcs.id, dbsvcs.f_proto, dbsvcs.f_number, cache=(cache.ram, 120)): services.append( [service.id, "%s/%s" % (service.f_proto, service.f_number)]) loot_file_details.append([workspace, ipaddr, services, filetype]) form_lootdir = SQLFORM.factory( Field('lootdir', 'string', default=loot_dir, requires=IS_NOT_EMPTY(), label=T('Metasploit Loot Directory')), ) return dict(form_lootdir=form_lootdir, loot_file_details=loot_file_details)
def import_scan(): """ Upload and import Nessus Scan file """ msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False from skaldship.general import check_datadir import time import os filedir = os.path.join(request.folder, 'data', 'scanfiles') response.title = "%s :: Import Nessus Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append([user.id, user.username]) nessus_config = nessus_get_config() # {'ignored_vulnids': [19506, 11219, 34277], # 'servers': {'server_1': {'password': '******', # 'url': 'https://localhost:8834/', # 'user': '******'}}} nessusreports = [[0, None]] import NessusAPI from skaldship.nessus.ness6api import Nessus6API servers = nessus_config.get('servers', {}) for k, v in servers.iteritems(): if v.get('version') == 6: # nessus >= 6 try: nessus = Nessus6API( url=v.get('url'), username=v.get('username'), password=v.get('password'), access_key=v.get('access_key'), secret_key=v.get('secret_key'), verify=v.get('verify_ssl'), proxies=v.get('proxies') ) except Exception, e: logger.error("Error communicating with %s: %s" % (k, str(e))) try: for report in nessus.get_scans(): ts = time.ctime(float(report.get('last_modification_date', 0))) nessusreports.append([ "%s:%s" % (k, report.get('id')), "%s: %s - %s (%s)" % (k, report.get('name'), ts, report.get('status')) ]) except Exception, e: logger.error("Error making scan list: %s" % (str(e)))
def import_xml_scan(): """ Upload/import Nmap XML Scan file via scheduler task """ import time from skaldship.general import check_datadir from skaldship.metasploit import msf_get_config msf_settings = msf_get_config(session) try: # check to see if we have a Metasploit RPC instance configured and talking from MetasploitProAPI import MetasploitProAPI msf_api = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) working_msf_api = msf_api.login() except: working_msf_api = False filedir = os.path.join(request.folder,'data','scanfiles') check_datadir(request.folder) response.title = "%s :: Import Nmap XML Scan Results" % (settings.title) fields = [] # buld the dropdown user list users = db(db.auth_user).select() userlist = [] for user in users: userlist.append( [ user.id, user.username ] ) fields.append(Field('f_filename', 'upload', uploadfolder=filedir, label=T('Nmap XML File'))) fields.append(Field('f_engineer', type='integer', label=T('Engineer'), default=auth.user.id, requires=IS_IN_SET(userlist))) fields.append(Field('f_asset_group', type='string', label=T('Asset Group'), requires=IS_NOT_EMPTY())) # If Metasploit available, pull a list of the workspaces and present them if working_msf_api: msf_workspaces = [] msf_workspaces.append( "None" ) for w in msf_api.pro_workspaces().keys(): msf_workspaces.append(w) fields.append(Field('f_msf_workspace', type='string', label=T('MSF Pro Workspace'), requires=IS_EMPTY_OR(IS_IN_SET(msf_workspaces, zero=None)))) fields.append(Field('f_addnoports', type='boolean', label=T('Add Hosts w/o Ports'), default=False)) fields.append(Field('f_include_list', type='text', label=T('Hosts to Only Include'))) fields.append(Field('f_ignore_list', type='text', label=T('Hosts to Ignore'))) fields.append(Field('f_update_hosts', type='boolean', label=T('Update Host Information'), default=False)) fields.append(Field('f_taskit', type='boolean', default=auth.user.f_scheduler_tasks, label=T('Run in background task'))) form = SQLFORM.factory(*fields, table_name='nmap_xml') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a nmap file filename = os.path.join(filedir, form.vars.f_filename) # build the hosts only/exclude list ip_exclude = [] data = form.vars.get('f_ignore_list') if data: ip_exclude = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals ip_include = [] data = form.vars.get('f_include_list') if data: ip_include = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals if form.vars.f_msf_workspace: msf_workspace = form.vars.f_msf_workspace if msf_workspace == "None": msf_workspace = None else: msf_workspace = None msf_settings = {'workspace': msf_workspace, 'url': msf_settings['url'], 'key': msf_settings['key']} if form.vars.f_taskit: task = scheduler.queue_task( scanner_import, pvars=dict( scanner='nmap', filename=filename, addnoports=form.vars.f_addnoports, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, msf_settings=msf_settings, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ), group_name=settings.scheduler_group_name, sync_output=5, timeout=settings.scheduler_timeout ) if task.id: redirect(URL('tasks', 'status', args=task.id)) else: response.flash = "Error submitting job: %s" % (task.errors) else: from skaldship.nmap import process_xml print("Starting Nmap XML Import") process_xml( filename=filename, addnoports=form.vars.f_addnoports, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, msf_settings=msf_settings, ip_ignore_list=ip_exclude, ip_include_list=ip_include, update_hosts=form.vars.f_update_hosts, ) response.flash = "Nmap XML upload complete" redirect(URL('default', 'index')) return dict(form=form)
def send_accounts(): """Builds a list of username:passwords and sends it to Metasploit""" msf_settings = msf_get_config(session) response.title = "%s :: Send Kvasir Passwords to Metasploit Pro" % ( settings.title) try: from MetasploitProAPI import MetasploitProAPI, MSFProAPIError except ImportError as error: return dict(error=str(error), alert=True, form=None) msf = MetasploitProAPI(host=msf_settings['url'], apikey=msf_settings['key']) try: msf.login() except MSFProAPIError as error: return dict(error=str(error), alert=True, form=None) form = SQLFORM.factory( Field('userpass', 'boolean', default=True, label=T('User/Pass Combos')), Field('pwdump', 'boolean', default=True, label=T('PWDUMP Hashes')), ) if form.accepts(request, session): pass elif form.errors: reseponse.flash = "Error in your form" return dict(form=form, alert=False, error=None) else: return dict(form=form, alert=False, error=None) """ First build a list of username:passwords from the t_accounts database and make a temporary file, then start_import_creds the file Second build a pwdump list for LM/NT hashes, make a temporary file, then start_import_creds that file! Requires MSFPRO and Kvasir be on the same workstation. """ tasks = {} import tempfile if form.vars.userpass: # build username:password file rows = db(db.t_accounts.f_compromised == True).select( db.t_accounts.f_username, db.t_accounts.f_password, cache=(cache.ram, 60)) if rows is not None: tmpfile = tempfile.NamedTemporaryFile(delete=False) fname = tmpfile.name for row in rows: tmpfile.write("%s %s\n" % (row.f_username, row.f_password)) tmpfile.close() opts = { 'workspace': msf_workspace, 'DS_FTYPE': 'userpass', 'DS_IMPORT_PATH': fname, 'DS_NAME': 'Kvasir import %s' % (fname), 'DS_DESC': 'Kvasir import', 'DS_REMOVE_FILE': True, } task = msf.pro_start_import_creds(opts) redirect(URL('task_log', args=task.get('id'))) else: response.flash = "No user:pass combos to import" if form.vars.pwdump: # build pwdump file rows = db(db.t_accounts.f_hash1_type == "LM").select( db.t_accounts.f_username, db.t_accounts.f_uid, db.t_accounts.f_hash1, db.t_accounts.f_hash2, cache=(cache.ram, 60)) if rows is not None: tmpfile = tempfile.NamedTemporaryFile(delete=False) fname = tmpfile.name for row in rows: tmpfile.write( "%s:%s:%s:%s:::\n" % (row.f_username, row.f_uid, row.f_hash1, row.f_hash2)) tmpfile.close() opts = { 'workspace': msf_workspace, 'DS_FTYPE': 'pwdump', 'DS_IMPORT_PATH': fname, 'DS_NAME': 'Kvasir pwdump import %s' % (fname), 'DS_DESC': 'Kvasir pwdump import', 'DS_REMOVE_FILE': True, } task = msf.pro_start_import_creds(opts) redirect(URL('task_log', args=task.get('id'))) else: response.flash = "No pwdump hashes to import" return dict(form=form, alert=False, error=None)