def import_mass_password(): """ Process a mass run of medusa/hydra.. result file will have IP addresses, service and info """ if request.extension == "load": buttons = [] else: buttons = ["submit"] from skaldship.general import check_datadir check_datadir(request.folder) form = SQLFORM.factory( Field( "f_filename", "upload", uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T("Password file"), ), Field( "f_ftype", "string", label=T("File Type"), default="Medusa", requires=IS_IN_SET(("Medusa", "Hydra", "Metasploit Creds CSV")), ), Field("f_proto", "string", label=T("Protocol"), default="tcp", requires=IS_IN_SET(("tcp", "udp", "info"))), Field("f_number", "string", label=T("Port Number"), requires=IS_NOT_EMPTY()), Field("f_message", "string", label=T("Message to add")), Field("f_add_hosts", "boolean", label=T("Add Hosts"), comment=T("Add missing hosts to the database")), buttons=buttons, _action=URL("accounts", "import_mass_password"), _id="import_mass_password", ) if request.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename if form.errors: response.flash = "Error in form" return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) logger.info("Processing password file: %s" % (filename)) resp_text = process_mass_password( pw_file=filename, pw_type=request.vars.f_ftype, message=request.vars.f_message, proto=request.vars.f_proto, portnum=request.vars.f_number, add_hosts=request.vars.f_add_hosts, user_id=auth.user.id, ) response.flash = resp_text response.title = "%s :: Import Mass Password File" % (settings.title) if request.extension == "json": return dict() else: return dict(form=form)
def do_screenshot(services=None): """ Grab a screenshot of a URL and import it to the evidence db. """ try: from pydal.objects import Row except ImportError: from gluon.dal import Row from skaldship.general import check_datadir db = current.globalenv['db'] settings = current.globalenv['settings'] if isinstance(services, int): services = [services] service_rows = [] if isinstance(services, list): for svc in services: service_rows.append(db.t_services[svc]) if isinstance(services, Row): service_rows = [services] phantomjs = settings.get('phantomjs', 'phantomjs') good_count = 0 invalid_count = 0 for svc_rec in service_rows: if not isinstance(svc_rec, Row): invalid_count += 1 continue ipaddr = svc_rec.f_hosts_id.f_ipaddr port = "%s%s" % (svc_rec.f_number, svc_rec.f_proto[0]) check_datadir(current.globalenv['request'].folder) folder = os.path.join(current.globalenv['request'].folder, "data/screenshots") filename = "%s-%s-webshot.png" % (ipaddr.replace(':', '_'), port) if svc_rec.f_name in ['http', 'https', 'HTTP', 'HTTPS']: scheme = svc_rec.f_name.lower() else: scheme = 'http' url = "%s://%s:%s/" % (scheme, ipaddr, svc_rec.f_number) res = grab_screenshot(url, os.path.join(folder, filename), phantomjs) if res[0]: query = (db.t_evidence.f_hosts_id == svc_rec.f_hosts_id) & (db.t_evidence.f_filename == filename) db.t_evidence.update_or_insert( query, f_filename=filename, f_hosts_id=svc_rec.f_hosts_id, f_data=res[1], f_evidence=filename, f_type="Screenshot", f_text="Web Screenshot - %s" % (url)) db.commit() print(" [-] Web screenshot obtained: %s" % (url)) good_count += 1 else: print(" [!] Web screenshot failed: %s" % (url)) invalid_count += 1 return [good_count, invalid_count]
def update_hashes_by_file(): """ Upload and parse a list of cracked hashes Supporting password file formats: JTR PWDUMP JTR Shadow Hash:Password Password:Hash """ import os from skaldship.general import check_datadir check_datadir(request.folder) if request.extension == "load": buttons = [] else: buttons = ['submit'] pw_set = ('JTR PWDUMP', 'JTR Shadow', 'Hash:Password', 'Password:Hash') form = SQLFORM.factory( Field('f_filename', 'upload', uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T('Password file')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(pw_set)), Field('f_message', 'string', label=T('Message to add')), buttons=buttons, _action=URL('accounts', 'update_hashes_by_file'), _id='accounts_update_hashes_by_file', ) resp_text = "" accounts_added = [] accounts_updated = [] if request.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) logger.info("Processing password file: %s" % (filename)) resp_text = process_cracked_file(pw_file=filename, file_type=request.vars.f_type, message=request.vars.f_message) response.title = "%s :: Update Password Hashes by File" % (settings.title) if request.extension == "json": return dict() else: return dict(form=form, resp_text=resp_text)
def database_restore(): """ Retore a database from CSV data """ response.title = "%s :: Database CSV Restore" % (settings.title) import os import glob from skaldship.general import check_datadir check_datadir(request.folder) backup_dir = os.path.join(request.folder, "data/backups") os.chdir(backup_dir) csv_files = [] for ext in ["*.csv", "*.csv.gz"]: csv_files.extend(glob.glob(ext)) form = SQLFORM.factory( Field("file", type="string", requires=IS_EMPTY_OR(IS_IN_SET(csv_files)), label=T("Local File")), Field("upload", type="upload", uploadfolder=backup_dir, label=T("Upload CSV File")), Field("wipe", type="boolean", default=False, label=T("Wipe all existing data")), ) if form.process().accepted: if form.vars.wipe: db.t_hosts.truncate(mode="CASCADE") db.t_services.truncate(mode="CASCADE") db.t_os.truncate(mode="CASCADE") db.t_host_os_refs.truncate(mode="CASCADE") db.t_apps.truncate(mode="CASCADE") db.t_services_apps_refs.truncate(mode="CASCADE") db.t_service_vulns.truncate(mode="CASCADE") db.t_service_info.truncate(mode="CASCADE") db.t_accounts.truncate(mode="CASCADE") db.t_host_notes.truncate(mode="CASCADE") db.t_evidence.truncate(mode="CASCADE") db.t_snmp.truncate(mode="CASCADE") db.commit() if form.vars.file: fname = form.vars.file elif form.vars.upload: fname = form.vars.upload if fname.endswith(".gz"): import gzip fobj = gzip.open(fname, "rb") else: fobj = open(fname, "rb") db.import_from_csv_file(fobj) elif form.errors: response.flash = "Error in form" os.chdir(request.folder) return dict(form=form, backup_dir=backup_dir)
def do_screenshot(services=None): """ Grab a screenshot and import it to the evidence db. """ try: from pydal.objects import Row except ImportError: from gluon.dal import Row from gluon import current import os from skaldship.general import check_datadir from multiprocessing import Process db = current.globalenv['db'] settings = current.globalenv['settings'] if isinstance(services, int): services = [services] service_rows = [] if isinstance(services, list): for svc in services: service_rows.append(db.t_services[svc]) if isinstance(services, Row): service_rows = [services] good_count = 0 invalid_count = 0 for svc_rec in service_rows: if not isinstance(svc_rec, Row): invalid_count += 1 continue ipaddr = svc_rec.f_hosts_id.f_ipaddr port = svc_rec.f_number check_datadir(current.globalenv['request'].folder) folder = os.path.join(current.globalenv['request'].folder, "data/screenshots") filename = "%s-%st-vnc_screenshot.png" % (ipaddr.replace(':', '_'), port) res = grab_screenshot(ipaddr, port, os.path.join(folder, filename)) if res[0]: query = (db.t_evidence.f_hosts_id == svc_rec.f_hosts_id) & (db.t_evidence.f_filename == filename) db.t_evidence.update_or_insert( query, f_filename=filename, f_hosts_id=svc_rec.f_hosts_id, f_data=res[1], f_evidence=filename, f_type="Screenshot", f_text="VNC Screenshot - %s:%s" % (ipaddr, port)) db.commit() print(" [-] VNC screenshot obtained: %s:%s" % (ipaddr, port)) good_count += 1 else: print(" [!] VNC screenshot failed: %s:%s" % (ipaddr, port)) invalid_count += 1 return [good_count, invalid_count]
def database_restore(): """ Retore a database from CSV data """ response.title = "%s :: Database CSV Restore" % (settings.title) import os import glob from skaldship.general import check_datadir check_datadir(request.folder) backup_dir = os.path.join(request.folder, 'data/backups') os.chdir(backup_dir) csv_files = [] for ext in ["*.csv", "*.csv.gz"]: csv_files.extend(glob.glob(ext)) form = SQLFORM.factory( Field('file', type='string', requires=IS_EMPTY_OR(IS_IN_SET(csv_files)), label=T('Local File')), Field('upload', type='upload', uploadfolder=backup_dir, label=T('Upload CSV File')), Field('wipe', type='boolean', default=False, label=T('Wipe all existing data')) ) if form.process().accepted: if form.vars.wipe: db.t_hosts.truncate(mode="CASCADE") db.t_services.truncate(mode="CASCADE") db.t_os.truncate(mode="CASCADE") db.t_host_os_refs.truncate(mode="CASCADE") db.t_apps.truncate(mode="CASCADE") db.t_services_apps_refs.truncate(mode="CASCADE") db.t_service_vulns.truncate(mode="CASCADE") db.t_service_info.truncate(mode="CASCADE") db.t_accounts.truncate(mode="CASCADE") db.t_host_notes.truncate(mode="CASCADE") db.t_evidence.truncate(mode="CASCADE") db.t_snmp.truncate(mode="CASCADE") db.commit() if form.vars.file: fname = form.vars.file elif form.vars.upload: fname = form.vars.upload if fname.endswith('.gz'): import gzip fobj = gzip.open(fname, 'rb') else: fobj = open(fname, 'rb') db.import_from_csv_file(fobj) elif form.errors: response.flash = "Error in form" os.chdir(request.folder) return dict(form=form, backup_dir=backup_dir)
def import_scan(): """ Upload/import hping Scan file via scheduler task """ import time from skaldship.general import check_datadir filedir = os.path.join(request.folder, 'data', 'scanfiles') check_datadir(request.folder) response.title = "%s :: Import hping 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('hping 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())) form = SQLFORM.factory(*fields, table_name='hping') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a hping file filename = form.vars.f_filename filename = os.path.join(filedir, form.vars.f_filename) from skaldship.hping import process_file print("Starting hping Import") process_file( filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, ) response.flash = "hping upload complete" redirect(URL('default', 'index')) return dict(form=form)
def update_hashes_by_file(): """ Upload and parse a list of cracked hashes Supporting password file formats: JTR PWDUMP JTR Shadow Hash:Password Password:Hash """ import os from skaldship.general import check_datadir check_datadir(request.folder) if request.extension == "load": buttons = [] else: buttons = ["submit"] pw_set = ("JTR PWDUMP", "JTR Shadow", "Hash:Password", "Password:Hash") form = SQLFORM.factory( Field( "f_filename", "upload", uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T("Password file"), ), Field("f_type", "string", label=T("File type"), default="PWDUMP", requires=IS_IN_SET(pw_set)), Field("f_message", "string", label=T("Message to add")), buttons=buttons, _action=URL("accounts", "update_hashes_by_file"), _id="accounts_update_hashes_by_file", ) resp_text = "" accounts_added = [] accounts_updated = [] if request.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename if form.errors: response.flash = "Error in form" return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) logger.info("Processing password file: %s" % (filename)) resp_text = process_cracked_file( pw_file=filename, file_type=request.vars.f_type, message=request.vars.f_message ) response.title = "%s :: Update Password Hashes by File" % (settings.title) if request.extension == "json": return dict() else: return dict(form=form, resp_text=resp_text)
def do_screenshot(services=None): """ Grab a screenshot and import it to the evidence db. """ from gluon.dal import Row from gluon import current import os from skaldship.general import check_datadir from multiprocessing import Process db = current.globalenv['db'] settings = current.globalenv['settings'] if isinstance(services, int): services = [services] service_rows = [] if isinstance(services, list): for svc in services: service_rows.append(db.t_services[svc]) if isinstance(services, Row): service_rows = [services] good_count = 0 invalid_count = 0 for svc_rec in service_rows: if not isinstance(svc_rec, Row): invalid_count += 1 continue # go with ipv6 if defined, else pick the ipv4 address ipaddr = svc_rec.f_hosts_id.f_ipv6 or svc_rec.f_hosts_id.f_ipv4 port = svc_rec.f_number check_datadir(current.globalenv['request'].folder) folder = os.path.join(current.globalenv['request'].folder, "data/screenshots") filename = "%s-%st-vnc_screenshot.png" % (ipaddr.replace(':', '_'), port) res = grab_screenshot(ipaddr, port, os.path.join(folder, filename)) if res[0]: query = (db.t_evidence.f_hosts_id == svc_rec.f_hosts_id) & (db.t_evidence.f_filename == filename) db.t_evidence.update_or_insert( query, f_filename=filename, f_hosts_id=svc_rec.f_hosts_id, f_data=res[1], f_evidence=filename, f_type="Screenshot", f_text="VNC Screenshot - %s:%s" % (ipaddr, port)) db.commit() print(" [-] VNC screenshot obtained: %s:%s" % (ipaddr, port)) good_count += 1 else: print(" [!] VNC screenshot failed: %s:%s" % (ipaddr, port)) invalid_count += 1 return [good_count, invalid_count]
def database_backup(): """ Export/backup database in CSV format """ response.title = "%s :: Database CSV Backup" % (settings.title) import os import gzip from datetime import datetime backup_dir = os.path.join(request.folder, "data/backups") form = SQLFORM.factory( Field("download", type="boolean", default=True, label=T("Download")), Field("gzip", type="boolean", default=True, label=T("GZip Compress")), ) if form.process().accepted: fname = "kvasir-%s-%s-%s" % ( settings.customer, settings.assesment_type, datetime.now().strftime("%m%d%y-%H%M%S"), ) fname = "".join([x if x.isalnum() else "_" for x in fname]) if form.vars.download: # generate csv and download s = StringIO.StringIO() db.export_to_csv_file(s) response.headers["Content-Type"] = "text/csv" if form.vars.gzip: gz_s = StringIO.StringIO() response.headers["Content-Disposition"] = 'attachment; filename="%s.gz"' % fname gz = gzip.GzipFile(filename="temp.gz", mode="wb", fileobj=gz_s) gz.write(s.getvalue()) gz.close() return gz_s.getvalue() else: response.headers["Content-Disposition"] = 'attachment; filename="%s"' % fname return s.getvalue() else: # generate csv and store locally from skaldship.general import check_datadir check_datadir(request.folder) tmpfile = os.path.join(request.folder, "data/backups", fname) if form.vars.gzip: fobj = gzip.open(tmpfile + ".gz", "wb") else: fobj = open(tmpfile, "wb") db.export_to_csv_file(fobj) return redirect(URL("default", "data_dir/backups")) elif form.errors: response.flash = "Error in form" return dict(form=form, backup_dir=backup_dir)
def import_mass_password(): """ Process a mass run of medusa/hydra.. result file will have IP addresses, service and info """ if request.extension == "load": buttons=[] else: buttons=['submit'] from skaldship.general import check_datadir check_datadir(request.folder) form=SQLFORM.factory( Field('f_filename', 'upload', uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T('Password file'), requires=IS_NOT_EMPTY(error_message=T('Filename required'))), Field('f_ftype', 'string', label=T('File Type'), default="Medusa", requires=IS_IN_SET(('Medusa', 'Hydra', 'Metasploit Creds CSV'))), Field('f_proto', 'string', label=T('Protocol'), default='tcp', requires=IS_IN_SET(('tcp', 'udp', 'info'))), Field('f_number', 'integer', label=T('Port Number'), requires=IS_INT_IN_RANGE(0, 65536)), Field('f_message', 'string', label=T('Message to add')), Field('f_add_hosts', 'boolean', label=T('Add Hosts'), comment=T('Add missing hosts to the database')), buttons=buttons, _action=URL('accounts', 'import_mass_password'), _id='import_mass_password', ) if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): if request.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) logger.info("Processing password file: %s" % (filename)) resp_text = process_mass_password( pw_file=filename, pw_type=request.vars.f_ftype, message=request.vars.f_message, proto=request.vars.f_proto, portnum=request.vars.f_number, add_hosts=request.vars.f_add_hosts, user_id=auth.user.id, ) response.flash = resp_text response.title = "%s :: Import Mass Password File" % (settings.title) if request.extension == "json": return dict() else: return dict(form=form)
def import_scan(): """ Upload/import hping Scan file via scheduler task """ import time from skaldship.general import check_datadir filedir = os.path.join(request.folder,'data','scanfiles') check_datadir(request.folder) response.title = "%s :: Import hping 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('hping 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())) form = SQLFORM.factory(*fields, table_name='hping') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a hping file filename = form.vars.f_filename filename = os.path.join(filedir, form.vars.f_filename) from skaldship.hping import process_file print("Starting hping Import") process_file( filename=filename, asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, ) response.flash = "hping upload complete" redirect(URL('default', 'index')) return dict(form=form)
def update_hashes_by_file(): """ Upload and parse a list of cracked hashes Supporting password file formats: JTR PWDUMP JTR Shadow Hash:Password Password:Hash """ import os from skaldship.general import check_datadir check_datadir(request.folder) if request.extension == "load": buttons=[] else: buttons=['submit'] pw_set = ('JTR PWDUMP', 'JTR Shadow', 'Hash:Password', 'Password:Hash') form = SQLFORM.factory( Field('f_filename', 'upload', uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T('Password file')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(pw_set)), Field('f_message', 'string', label=T('Message to add')), buttons=buttons, _action=URL('accounts', 'update_hashes_by_file'), _id='accounts_update_hashes_by_file', ) if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) logger.info("Processing password file: %s" % (filename)) response.flash = process_cracked_file( pw_file=filename, file_type=request.vars.f_type, message=request.vars.f_message ) response.title = "%s :: Update Password Hashes by File" % (settings.title) return dict(form=form)
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 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_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)
response.flash = "Error in form" elif form.accepts(request.vars, session): # process a nexpose file if not nxsitelist: nexpose_site = "0" else: nexpose_site = form.vars.f_nexpose_site if nexpose_site != "0": report = Report() report.host = nexpose_config["host"] report.port = nexpose_config["port"] nx_loggedin = report.login(user_id=nexpose_config["user"], password=nexpose_config["password"]) if nx_loggedin: # have nexpose generate the adhoc report check_datadir(request.folder) filename = os.path.join(filedir, "%s-%s.xml" % (form.vars.f_asset_group, int(time.time()))) fout = open(filename, "w") fout.write(report.adhoc_generate(filterid=nexpose_site)) fout.close() else: response.flash = "Unable to login to Nexpose" return dict(form=form) else: filename = form.vars.f_filename 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:
def import_file(): """ Import and parse password file into t_accounts """ import os from skaldship.general import check_datadir check_datadir(request.folder) # Service_id is primary, host_id is secondary, if none then list # all the services svc_set = [] url=URL('accounts', 'import_file') if request.vars.has_key('service_id'): try: record = db.t_services[request.vars.service_id] svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) url = URL('accounts', 'import_file', vars={'service_id':request.vars.service_id}) except: pass elif request.vars.has_key('host_id'): try: host_record = get_host_record(request.vars.host_id) svc_records = db(db.t_services.f_hosts_id == host_record.id).select(cache=(cache.ram, 30)) url = URL('accounts', 'import_file', vars={'host_id':request.vars.host_id}) for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) except: pass if len(svc_set) == 0: # all services svc_records = db(db.t_services).select(cache=(cache.ram,30)) svc_set = [] for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) if request.extension == "load": buttons=[] else: buttons=['submit'] form = SQLFORM.factory( Field('f_service', 'string', label=T('Host / Service'), requires=IS_IN_SET(svc_set), default=svc_set[0][0]), Field('f_filename', 'upload', uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T('Password file')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(settings.password_file_types)), Field('f_source', 'string', label=T('Source (if necessary)')), Field('f_add_to_evidence', 'boolean', label=T('Add Evidence')), Field('f_taskit', type='boolean', default=True, label=T('Run in background task')), buttons=buttons, _action=url, _id='accounts_import_form' ) resp_text = "" accounts_added = [] accounts_updated = [] if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): if form.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) if form.vars.f_taskit: task = scheduler.queue_task( accounts_import_file, pvars=dict( filename=filename, service=form.vars.f_service, f_type=form.vars.f_type, f_source=form.vars.f_source ), group_name=settings.scheduler_group_name, sync_output=5, timeout=settings.scheduler_timeout ) if task.id: resp_text = "Submitted file for processing: %s" % (A("task " + str(task.id), _href=URL(c='tasks', f='status', args=task.id)).xml()) else: resp_text = "Error submitting job: %s" % (task.errors) else: logger.info("Processing password file: %s" % (filename)) account_data = process_password_file( pw_file=filename, file_type=request.vars.f_type, source=request.vars.f_source ) resp_text = insert_or_update_acct(form.vars.f_service, account_data) logger.info(resp_text) if form.vars.f_add_to_evidence is True: # add the password file to evidence try: pwdata = open(filename, "r").readlines() except Exception, e: logger.error("Error opening %s: %s" % (filename, e)) db.t_evidence.insert( f_hosts_id = db.t_services[form.vars.f_service].f_hosts_id, f_type = 'Password File', f_text = form.vars.f_type, f_filename = orig_filename, f_evidence = form.vars.f_filename, f_data = pwdata) db.commit()
def paste(): """ Import and parse password pasted to a textbox into t_accounts """ from skaldship.general import check_datadir check_datadir(request.folder) # Service_id is primary, host_id is secondary, if none then list # all the services svc_set = [] url = URL('accounts', 'paste') if request.vars.has_key('service_id'): try: record = db.t_services[request.vars.service_id] svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) url = URL('accounts', 'paste', vars={'service_id': request.vars.service_id}) except: pass elif request.vars.has_key('host_id'): try: host_record = get_host_record(request.vars.host_id) svc_records = db( db.t_services.f_hosts_id == host_record.id).select( cache=(cache.ram, 30)) url = URL('accounts', 'paste', vars={'host_id': request.vars.host_id}) for record in svc_records: svc_set.append( (record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) except: pass if len(svc_set) == 0: # all services svc_records = db(db.t_services).select(cache=(cache.ram, 30)) svc_set = [] for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) if request.extension == "load": buttons = [] else: buttons = ['submit'] form = SQLFORM.factory( Field('f_service', 'string', label=T('Host / Service'), requires=IS_IN_SET(svc_set), default=svc_set[0][0]), Field('f_pwtext', 'text', label=T('Password text')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(settings.password_file_types)), Field('f_source', 'string', label=T('Source (if necessary)')), Field('f_add_to_evidence', 'boolean', label=T('Add file to Evidence')), buttons=buttons, _action=url, _id='accounts_paste_form' #_action=url, _id='accounts_paste_form', formstyle='bootstrap_modal' ) resp_text = "" accounts_added = [] accounts_updated = [] if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): from gluon.utils import web2py_uuid host_id = db.t_services[form.vars.f_service].f_hosts_id pwd_file_dir = os.path.join(request.folder, 'data', 'passwords', 'other') if not os.path.exists(pwd_file_dir): from gluon.fileutils import mktree mktree(pwd_file_dir) filename = "%s-pwfile-%s" % (host_id, web2py_uuid()) full_file_path = os.path.join(request.folder, 'data/passwords/other', filename) of = open(full_file_path, "w") of.write(form.vars.f_pwtext) of.close() logger.debug("Processing password file: %s" % (full_file_path)) account_data = process_password_file(pw_file=full_file_path, file_type=request.vars.f_type, source=request.vars.f_source) response.headers[ 'web2py-component-command'] = 'accounttable.fnReloadAjax();' resp_text = insert_or_update_acct(form.vars.f_service, account_data) if form.vars.f_add_to_evidence is True: # add the password file to evidence try: pwdata = open(full_file_path, "r").readlines() except Exception, e: logger.error("Error opening %s: %s" % (full_file_path, e)) resp_text += "Error opening %s: %s\n" % (full_file_path, e) db.t_evidence.insert(f_hosts_id=host_id, f_type='Password File', f_text=form.vars.f_type, f_filename=filename, f_evidence=filename, f_data=pwdata) resp_text += "\n%s added to evidence\n" % (filename) db.commit()
def import_file(): """ Import and parse password file into t_accounts """ import os from skaldship.general import check_datadir check_datadir(request.folder) # Service_id is primary, host_id is secondary, if none then list # all the services svc_set = [] url = URL('accounts', 'import_file') if request.vars.has_key('service_id'): try: record = db.t_services[request.vars.service_id] svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) url = URL('accounts', 'import_file', vars={'service_id': request.vars.service_id}) except: pass elif request.vars.has_key('host_id'): try: host_record = get_host_record(request.vars.host_id) svc_records = db( db.t_services.f_hosts_id == host_record.id).select( cache=(cache.ram, 30)) url = URL('accounts', 'import_file', vars={'host_id': request.vars.host_id}) for record in svc_records: svc_set.append( (record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) except: pass if len(svc_set) == 0: # all services svc_records = db(db.t_services).select(cache=(cache.ram, 30)) svc_set = [] for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) if request.extension == "load": buttons = [] else: buttons = ['submit'] form = SQLFORM.factory( Field('f_service', 'string', label=T('Host / Service'), requires=IS_IN_SET(svc_set), default=svc_set[0][0]), Field('f_filename', 'upload', uploadfolder=os.path.join(request.folder, settings.password_upload_dir), label=T('Password file')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(settings.password_file_types)), Field('f_source', 'string', label=T('Source (if necessary)')), Field('f_add_to_evidence', 'boolean', label=T('Add Evidence')), Field('f_taskit', type='boolean', default=True, label=T('Run in background task')), buttons=buttons, _action=url, _id='accounts_import_form') resp_text = "" accounts_added = [] accounts_updated = [] if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): if form.vars.f_filename is not None: orig_filename = request.vars.f_filename.filename filename = os.path.join(request.folder, settings.password_upload_dir, form.vars.f_filename) if form.vars.f_taskit: task = scheduler.queue_task( accounts_import_file, pvars=dict(filename=filename, service=form.vars.f_service, f_type=form.vars.f_type, f_source=form.vars.f_source), group_name=settings.scheduler_group_name, sync_output=5, timeout=settings.scheduler_timeout) if task.id: resp_text = "Submitted file for processing: %s" % (A( "task " + str(task.id), _href=URL(c='tasks', f='status', args=task.id)).xml()) else: resp_text = "Error submitting job: %s" % (task.errors) else: logger.info("Processing password file: %s" % (filename)) account_data = process_password_file(pw_file=filename, file_type=request.vars.f_type, source=request.vars.f_source) resp_text = insert_or_update_acct(form.vars.f_service, account_data) logger.info(resp_text) if form.vars.f_add_to_evidence is True: # add the password file to evidence try: pwdata = open(filename, "r").readlines() except Exception, e: logger.error("Error opening %s: %s" % (filename, e)) db.t_evidence.insert( f_hosts_id=db.t_services[form.vars.f_service].f_hosts_id, f_type='Password File', f_text=form.vars.f_type, f_filename=orig_filename, f_evidence=form.vars.f_filename, f_data=pwdata) db.commit()
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)
def nmap_scan(): """ Run nmap scan and hand file over to parser """ from skaldship.general import check_datadir import time import os response.title = "%s :: Run Nmap Scan" % (settings.title) scan_profiles = { 'Ping Scan': ["-sn"], 'Intense Scan': ["-T4", "-A", "-v"], 'Intense Scan (All TCP Ports)': ["-p", "1-65535", "-T4", "-A", "-v"], 'Intense Scan (No Ping)': ["-T4", "-A", "-v", "-Pn"], 'Quick Scan': ["-T4", "-F"], 'Quick Scan Plus': ["-sV", "-T4", "-O", "-F", "--version-light"], 'Slow Comprehensive Scan': ["-sS", "-sU", "-T4", "-A", "-v", "-PE", "-PP", "-PS80,443", "-PA3389", "-PU40125", "-PY", "-g 53", "--script", "default"] } 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_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())) fields.append(Field('f_scan_profile', label=T('Scan Profile'), requires=IS_EMPTY_OR(IS_IN_SET(sorted(scan_profiles.keys()), zero=None)))) fields.append(Field('f_scan_options', type='string', label=T('Scan Options'))) fields.append(Field('f_target_list', type='text', label=T('Scan Targets'))) fields.append(Field('f_blacklist', type='text', label=T('Blacklist'))) fields.append(Field('f_addnoports', type='boolean', label=T('Add Hosts w/o Ports'), default=False)) fields.append(Field('f_update_hosts', type='boolean', label=T('Update Host Information'), default=False)) form = SQLFORM.factory(*fields, table_name='nmap_scan') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a nmap scan # build the hosts only/exclude list ip_blacklist = [] data = form.vars.get('f_blacklist') if data: ip_blacklist = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals ip_targets = [] data = form.vars.get('f_target_list') if data: ip_targets = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals if form.vars.f_scan_options: scan_options = form.vars.f_scan_options.split(' ') else: scan_options = scan_profiles[form.vars.f_scan_profile] check_datadir(request.folder) filename = "nmap-%s-%s.xml" % (form.vars.f_asset_group, int(time.time())) filedir = os.path.join(request.folder, 'data', 'scanfiles', filename) scan_options.extend(['--stats-every', '5s', '-oX', filedir]) task = scheduler.queue_task( run_scanner, pvars=dict( scanner='nmap', asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, target_list=ip_targets, blacklist=ip_blacklist, scan_options=scan_options, addnoports=form.vars.f_addnoports, 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) return dict(form=form)
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.items(): nxsitelist.append([int(k), sites[k]['name']]) except Exception as e: pass if nxsitelist: fields.append( Field('f_nexpose_site', type='integer', label=T('Nexpose Site'), requires=IS_IN_SET(nxsitelist, zero=None))) fields.append( Field('f_filename', 'upload', uploadfolder=filedir, label=T('Nexpose 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 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='nexpose_xml') # form processing if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a nexpose file if not nxsitelist: nexpose_site = '0' else: nexpose_site = form.vars.f_nexpose_site if nexpose_site != '0': report = Report() report.host = nexpose_config['host'] report.port = nexpose_config['port'] nx_loggedin = report.login(user_id=nexpose_config['user'], password=nexpose_config['password']) if nx_loggedin: # have nexpose generate the adhoc report check_datadir(request.folder) filename = os.path.join( filedir, "%s-%s.xml" % (form.vars.f_asset_group, int(time.time()))) fout = open(filename, "w") fout.write(report.adhoc_generate(filterid=nexpose_site)) fout.close() else: response.flash = "Unable to login to Nexpose" return dict(form=form) else: filename = form.vars.f_filename 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='nexpose', 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.nexpose import process_xml log("Starting Nexpose XML Import") process_xml( 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, ) response.flash = "Nexpose XML upload complete" redirect(URL('default', 'index')) return dict(form=form)
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 nmap_scan(): """ Run nmap scan and hand file over to parser """ from skaldship.general import check_datadir import time import os response.title = "%s :: Run Nmap Scan" % (settings.title) scan_profiles = { 'Ping Scan': ["-sn"], 'Intense Scan': ["-T4", "-A", "-v"], 'Intense Scan (All TCP Ports)': ["-p", "1-65535", "-T4", "-A", "-v"], 'Intense Scan (No Ping)': ["-T4", "-A", "-v", "-Pn"], 'Quick Scan': ["-T4", "-F"], 'Quick Scan Plus': ["-sV", "-T4", "-O", "-F", "--version-light"], 'Slow Comprehensive Scan': [ "-sS", "-sU", "-T4", "-A", "-v", "-PE", "-PP", "-PS80,443", "-PA3389", "-PU40125", "-PY", "-g 53", "--script", "default" ] } 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_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())) fields.append( Field('f_scan_profile', label=T('Scan Profile'), requires=IS_EMPTY_OR( IS_IN_SET(sorted(scan_profiles.keys()), zero=None)))) fields.append( Field('f_scan_options', type='string', label=T('Scan Options'))) fields.append(Field('f_target_list', type='text', label=T('Scan Targets'))) fields.append(Field('f_blacklist', type='text', label=T('Blacklist'))) fields.append( Field('f_addnoports', type='boolean', label=T('Add Hosts w/o Ports'), default=False)) fields.append( Field('f_update_hosts', type='boolean', label=T('Update Host Information'), default=False)) form = SQLFORM.factory(*fields, table_name='nmap_scan') if form.errors: response.flash = 'Error in form' elif form.accepts(request.vars, session): # process a nmap scan # build the hosts only/exclude list ip_blacklist = [] data = form.vars.get('f_blacklist') if data: ip_blacklist = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals ip_targets = [] data = form.vars.get('f_target_list') if data: ip_targets = data.split('\r\n') # TODO: check for ip subnet/range and break it out to individuals if form.vars.f_scan_options: scan_options = form.vars.f_scan_options.split(' ') else: scan_options = scan_profiles[form.vars.f_scan_profile] check_datadir(request.folder) filename = "nmap-%s-%s.xml" % (form.vars.f_asset_group, int( time.time())) filedir = os.path.join(request.folder, 'data', 'scanfiles', filename) scan_options.extend(['--stats-every', '5s', '-oX', filedir]) task = scheduler.queue_task(run_scanner, pvars=dict( scanner='nmap', asset_group=form.vars.f_asset_group, engineer=form.vars.f_engineer, target_list=ip_targets, blacklist=ip_blacklist, scan_options=scan_options, addnoports=form.vars.f_addnoports, 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) return dict(form=form)
def paste(): """ Import and parse password pasted to a textbox into t_accounts """ from skaldship.general import check_datadir check_datadir(request.folder) # Service_id is primary, host_id is secondary, if none then list # all the services svc_set = [] url=URL('accounts', 'paste') if request.vars.has_key('service_id'): try: record = db.t_services[request.vars.service_id] svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) url = URL('accounts', 'paste', vars={'service_id':request.vars.service_id}) except: pass elif request.vars.has_key('host_id'): try: host_record = get_host_record(request.vars.host_id) svc_records = db(db.t_services.f_hosts_id == host_record.id).select(cache=(cache.ram, 30)) url = URL('accounts', 'paste', vars={'host_id':request.vars.host_id}) for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) except: pass if len(svc_set) == 0: # all services svc_records = db(db.t_services).select(cache=(cache.ram,30)) svc_set = [] for record in svc_records: svc_set.append((record.id, "%s :: %s/%s" % (host_title_maker(db.t_hosts[record.f_hosts_id]), record.f_proto, record.f_number))) if request.extension == "load": buttons=[] else: buttons=['submit'] form = SQLFORM.factory( Field('f_service', 'string', label=T('Host / Service'), requires=IS_IN_SET(svc_set), default=svc_set[0][0]), Field('f_pwtext', 'text', label=T('Password text')), Field('f_type', 'string', label=T('File type'), default='PWDUMP', requires=IS_IN_SET(settings.password_file_types)), Field('f_source', 'string', label=T('Source (if necessary)')), Field('f_add_to_evidence', 'boolean', label=T('Add file to Evidence')), buttons=buttons, _action=url, _id='accounts_paste_form' #_action=url, _id='accounts_paste_form', formstyle='bootstrap_modal' ) resp_text = "" accounts_added = [] accounts_updated = [] if form.errors: response.flash = 'Error in form' return TABLE(*[TR(k, v) for k, v in form.errors.items()]) elif form.accepts(request.vars, session): from gluon.utils import web2py_uuid host_id = db.t_services[form.vars.f_service].f_hosts_id pwd_file_dir = os.path.join(request.folder, 'data', 'passwords', 'other') if not os.path.exists(pwd_file_dir): from gluon.fileutils import mktree mktree(pwd_file_dir) filename = "%s-pwfile-%s" % (host_id, web2py_uuid()) full_file_path = os.path.join(request.folder, 'data/passwords/other', filename) of = open(full_file_path, "w") of.write(form.vars.f_pwtext) of.close() logger.debug("Processing password file: %s" % (full_file_path)) account_data = process_password_file(pw_file=full_file_path, file_type=request.vars.f_type, source=request.vars.f_source) response.headers['web2py-component-command'] = 'accounttable.fnReloadAjax();' resp_text = insert_or_update_acct(form.vars.f_service, account_data) if form.vars.f_add_to_evidence is True: # add the password file to evidence try: pwdata = open(full_file_path, "r").readlines() except Exception, e: logger.error("Error opening %s: %s" % (full_file_path, e)) resp_text += "Error opening %s: %s\n" % (full_file_path, e) db.t_evidence.insert( f_hosts_id = host_id, f_type = 'Password File', f_text = form.vars.f_type, f_filename = filename, f_evidence = filename, f_data = pwdata) resp_text += "\n%s added to evidence\n" % (filename) db.commit()
def launch_terminal(record=None, launch_cmd=None): """ Opens a terminal on the Web Server. This only works if the web2py server is running on the user's workstation. The command to execute is stored in the user's settings db under auth_user.f_launch_cmd. Variables translated: _IP_ -- The current IP Address (v4 by default, v6 if exists) _LOGFILE_ -- Session logfile name (we prepend the path) If an IPv6 address is used then ':' is changed to '_' Example: xterm -sb -sl 1500 -vb -T 'manual hacking: _IP_' -n 'manual hacking: _IP_' -e script _LOGFILE_ """ record = get_host_record(record) # only execute launch on requests from localhost! if request.env['remote_addr'] != '127.0.0.1': logger.error("Can only launch from localhost! remote_addr = %s" % (request.env['remote_addr'])) return "Can only launch from localhost" if record is None: return "No record found" import string, os, subprocess import time from gluon.validators import IS_IPADDRESS # if no launch command use the default if not launch_cmd: launch_cmd = "xterm -sb -sl 1500 -vb -T 'manual hacking: _IP_' -n 'manual hacking: _IP_' -e 'script _LOGFILE_'" # check ip address ip = record.f_ipaddr logip = ip if IS_IPADDRESS(is_ipv6=True)(ip)[0] == None: logip = ip.replace(":", "_") logdir = "session-logs" logfilename = "%s-%s.log" % (logip, time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))) logfile = os.path.join(logdir, logfilename) launch_cmd = launch_cmd.replace("_IP_", ip) launch_cmd = launch_cmd.replace("_LOGFILE_", logfile) from skaldship.general import check_datadir # Check to see if data directories exist, create otherwise check_datadir(request.folder) datadir = os.path.join(os.getcwd(), request.folder, "data") # chdir to datadir! launch_cmd = launch_cmd.replace("_DATADIR_", datadir) os.chdir(datadir) # set environment variables os.environ['IP'] = ip os.environ['HOSTNAME'] = record.f_hostname or "" os.environ['DATADIR'] = datadir try: logger.info("Spawning: %s\n" % (launch_cmd)) print("Spawning: %s" % (launch_cmd)) subprocess.Popen(launch_cmd, shell=True)#, stdout=None, stdin=None, stderr=None) except Exception, e: logger.error("Error spawning launch cmd (%s): %s\n" % (launch_cmd, e)) print("Error spawning launch cmd (%s): %s\n" % (launch_cmd, e))