def get_misp_connection(config=None, parameters=None): global misp_connection if misp_connection: return misp_connection if not config: raise MaltegoException("ERROR: MISP connection not yet established, and config not provided as parameter.") misp_verify = True misp_debug = False misp_url = None misp_key = None try: if is_local_exec_mode(): misp_url = config['MISP_maltego.local.misp_url'] misp_key = config['MISP_maltego.local.misp_key'] if config['MISP_maltego.local.misp_verify'] in ['False', 'false', 0, 'no', 'No']: misp_verify = False if config['MISP_maltego.local.misp_debug'] in ['True', 'true', 1, 'yes', 'Yes']: misp_debug = True if is_remote_exec_mode(): try: misp_url = parameters['mispurl'].value misp_key = parameters['mispkey'].value except AttributeError: raise MaltegoException("ERROR: mispurl and mispkey need to be set to something valid") misp_connection = PyMISP(misp_url, misp_key, misp_verify, 'json', misp_debug, tool='misp_maltego') except Exception: if is_local_exec_mode(): raise MaltegoException("ERROR: Cannot connect to MISP server. Please verify your MISP_Maltego.conf settings.") if is_remote_exec_mode(): raise MaltegoException("ERROR: Cannot connect to MISP server. Please verify your settings (MISP URL and API key), and ensure the MISP server is reachable from the internet.") return misp_connection
def do_transform(self, request, response, config): # Get Credential JSON dictionary credential = request.entity # Test for properties try: url = config[ 'EffectiveCouscous.local.baseurl'] + 'credentials/{0}'.format( credential['id']) except KeyError: raise MaltegoException( "This Credential is not tied to a Metasploit Credential. Please associate it with a Credential before running this transform" ) return response cred = apitools.get_json_dict(url, config) # Fetch values credential.id = cred['id'] credential.logins_count = cred['logins_count'] credential.pub_username = cred['public']['username'] credential.pub_type = cred['public']['type'] credential.priv_data = cred['private']['data'] credential.priv_type = cred['private']['type'] credential.priv_jtr_format = cred['private']['jtr_format'] credential.origin_service_id = cred['origin']['service_id'] credential.origin_type = cred['origin']['type'] credential.origin_module = cred['origin']['module_full_name'] raise MaltegoException( 'Due to implementation limitations, it is not possible to refresh this Entity "as is". Please suppress it and spawn it again from its parent Entity to see it with its new properties.' ) return response
def dotransform(request, response, config): try: query = '%s -site:blockchain.info -site:blockexplorer.com' % request.value jsondata = json.loads( csequery(config['gcse/gapi'], config['gcse/gcseid'], query)) except Exception as e: raise MaltegoException('An error occured: %s' % e) # parses the GCSE results if 'items' in jsondata: try: for item in jsondata['items']: e = URL(item['link'], url=item['link']) e += Label("Title", item['title'].encode('ascii', 'ignore')) e += Label("Snippet", item['snippet'].encode('ascii', 'ignore')) e += Label("Google Query", jsondata['queries']['request'][0]['searchTerms']) response += e # TODO: Check to see if there are more than one page of results up to 100 results can be returned by the GCSE API # if 'nextPage' in jsondata['queries'] return response except Exception as e: raise MaltegoException('An error occured: %s' % e) else: pass
def scriptable_transform_runner(transform, value, fields, params, config): global scriptable_api_initialized if not scriptable_api_initialized: scriptable_api_initialized = True def run_transform(self, transform, params=None, config=None): if isinstance(transform, basestring): transform = load_object(transform)() return scriptable_transform_runner(transform, self.value, self.fields, params or [], config or load_config()) Entity.run_transform = run_transform request = MaltegoTransformRequestMessage( parameters={ 'canari.local.arguments': Field(name='canari.local.arguments', value=params) }) request._entities = [to_entity(transform.input_type, value, fields)] msg = transform.do_transform(request, MaltegoTransformResponseMessage(), config) if isinstance(msg, MaltegoTransformResponseMessage): return Response(msg) elif isinstance(msg, basestring): raise MaltegoException(msg) else: raise MaltegoException( 'Could not resolve message type returned by transform.')
def get_misp_connection(config=None): global misp_connection if misp_connection: return misp_connection if not config: raise MaltegoException( "ERROR: MISP connection not yet established, and config not provided as parameter." ) if config['MISP_maltego.local.misp_verify'] in [ 'True', 'true', 1, 'yes', 'Yes' ]: misp_verify = True else: misp_verify = False if config['MISP_maltego.local.misp_debug'] in [ 'True', 'true', 1, 'yes', 'Yes' ]: misp_debug = True else: misp_debug = False try: misp_connection = PyMISP(config['MISP_maltego.local.misp_url'], config['MISP_maltego.local.misp_key'], misp_verify, 'json', misp_debug) except Exception: raise MaltegoException( "ERROR: Cannot connect to MISP server. Please verify your MISP_Maltego.conf settings" ) return misp_connection
def do_transform(self, request, response, config): msf_service = request.entity # Test for properties ----------------------------------------------// try: test = msf_service['id'] except KeyError: raise MaltegoException( "This Service is not tied to a Metasploit Service. \ Please associate it with a Service before running this transform" ) return response url = config['EffectiveCouscous.local.baseurl'] + 'services/{0}'.format( msf_service['id']) service = apitools.get_json_dict(url, config) msf_service.info = service['info'] msf_service.name = service['name'] msf_service.proto = service['proto'] msf_service.port = service['port'] msf_service.host_id = service['host']['id'] msf_service.service_id = service['id'] msf_service.workspace_id = service['host']['workspace_id'] msf_service.created_at = service['created_at'] msf_service.updated_at = service['updated_at'] msf_service.state = service['state'] raise MaltegoException( 'Due to implementation limitations, it is not possible to refresh this Entity "as is". \ Please suppress it and spawn it again from its parent Entity to see it with its new properties.' ) return response
def scrape(url): if not url: return response = session.get(url, headers={"User-Agent": ua.random}) if "InternalCaptcha" in response.url: raise MaltegoException("Internal Captcha: " + response.url) if response.status_code == requests.codes.ok: return BeautifulSoup(response.content, "html.parser") raise MaltegoException(response.status_code)
def run(args): [transform, params, value, fields] = parseargs(['canari %s' % cmd_name(__name__)] + args) transform_module = None fix_binpath(config['default/path']) try: transform_module = import_transform(transform) if os.name == 'posix' and hasattr(transform_module.dotransform, 'privileged') and os.geteuid(): rc = sudo(sys.argv) if rc == 1: message(MaltegoTransformResponseMessage() + UIMessage('User cancelled transform.')) elif rc == 2: message(MaltegoTransformResponseMessage() + UIMessage('Too many incorrect password attempts.')) elif rc: message(MaltegoTransformResponseMessage() + UIMessage('Unknown error occurred.')) exit(0) if hasattr(transform_module, 'onterminate'): onterminate(transform_module.onterminate) else: transform_module.__setattr__('onterminate', lambda *args: exit(-1)) input_entity = to_entity(guess_entity_type(transform_module, fields), value, fields) msg = transform_module.dotransform( MaltegoTransformRequestMessage(value, fields, params, input_entity), MaltegoTransformResponseMessage()) if get_transform_version( transform_module.dotransform ) == 2 else transform_module.dotransform( MaltegoTransformRequestMessage(value, fields, params, input_entity), MaltegoTransformResponseMessage(), config) if isinstance(msg, MaltegoTransformResponseMessage): message(msg) elif isinstance(msg, basestring): raise MaltegoException(msg) else: raise MaltegoException( 'Could not resolve message type returned by transform.') except MaltegoException, me: croak(str(me))
def croak(cause): """Throw an exception in the Maltego GUI containing cause. :param cause: a string containing the issue description. """ return MaltegoMessage(message=MaltegoTransformExceptionMessage( exceptions=[MaltegoException(cause)])).render()
def do_transform(transform): try: # Let's get an XML object tree req = MaltegoMessage.parse(request.data).message # If our transform define an input entity type then we should check # whether the request contains the right type if transform.input_type and transform.input_type is not Unknown and \ not isinstance(req.entity, transform.input_type): return Response(application.four_o_four, status=404) # Execute it! msg = transform().do_transform(req, MaltegoTransformResponseMessage(), load_config()) # Let's serialize the return response and clean up whatever mess was left behind if isinstance(msg, MaltegoTransformResponseMessage): return message(msg) else: raise MaltegoException(str(msg)) # Unless we croaked somewhere, then we need to fix things up here... except MaltegoException as me: return croak(str(me)) except Exception: if application.debug: return croak(traceback.format_exc()) else: return croak('Transform execution failed.')
def dotransform(request, response, config): try: btc_add = bitcoin_address(request.fields['address']) for trans in btc_add['transactions']: if request.value == trans['transaction_hash']: for address in trans['addresses']: e = BitcoinAddress(address) e += Field("date", trans['date'], displayname='Date') e += Field("trans_uri", trans['transaction_uri'], displayname='Transaction URI') e += Field("recieved_address", request.fields['address'], displayname='Recieved Address') e += Label("Bitcoin Address", address) e += Label("Bitcoin Recieved Address", request.fields['address']) e += Label("Transaction Type", trans['transaction_type']) e += Label("Transaction Hash", trans['transaction_hash']) e += Label("Transaction Date", trans['date']) response += e else: pass return response except Exception as e: raise MaltegoException('An error occured: %s' % e)
def do_transform(self, request, response, config): ws = request.entity # Test for properties try: test = ws['workspace_id'] except KeyError: raise MaltegoException( "This Netblock/Host is not tied to a Metasploit Workspace. \ Please associate it with a workspace before running this transform" ) return response url = config[ 'EffectiveCouscous.local.baseurl'] + 'workspaces/{0}'.format( ws['workspace_id']) workspace = apitools.get_json_dict(url, config) ws['workspace_id'] = workspace['id'] ws['name'] = workspace['name'] ws['created_at'] = workspace['created_at'] ws['updated_at'] = workspace['updated_at'] ws['boundary'] = workspace['boundary'] ws['description'] = workspace['description'] ws['owner_id'] = workspace['owner_id'] ws['limit_to_network'] = workspace['limit_to_network'] ws['import_fingerprint'] = workspace['import_fingerprint'] return response
def dotransform(request, response): r = route(request.value) if r is None: raise MaltegoException('Network is unavailable') elif not r['nexthop']: return findlocalneighbors(r['network'], response) return findremoteneighbors(IPAddress(request.value), response)
def loginSearch(hash): url = 'https://fileadvisor.bit9.com/Services/login.aspx' ua = [('User-agent', 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)')] browse = mechanize.Browser() browse.addheaders = ua browse.open(url) browse.select_form("aspnetForm") browse.set_all_readonly(False) un = config['bit9/username'] pw = config['bit9/password'] if un == "<YOUR USERNAME HERE>" or pw == "<YOUR PASSWORD HERE>": raise MaltegoException( "Please specify Username and Password in config") browse["__EVENTTARGET"] = "" browse["__EVENTARGUMENT"] = "" browse["ctl00$ColumnBody$TextBox_UserName"] = un browse["ctl00$ColumnBody$TextBox_Password"] = pw browse.submit(name="ctl00$ColumnBody$Button_Submit") browse.select_form("aspnetForm") browse.set_all_readonly(False) browse["__EVENTTARGET"] = "" browse["__EVENTARGUMENT"] = "" browse["ctl00$ColumnBody$RadComboBox1_input"] = hash browse["submitbt"] = "Search »" results = browse.submit() return results.read()
def do_transform(self, request, response, config): ip_address = request.entity # Test for properties try: url = config[ 'EffectiveCouscous.local.baseurl'] + 'hosts/{0}'.format( ip_address['id']) host = apitools.get_json_dict(url, config) except KeyError: raise MaltegoException( "This IPv4Address is not tied to a Metasploit Host. \ Please associate it with a Host before running this transform" ) return response # Spawn Host (NEW) h = getOsEntity(host['os_name'], host['name']) h.ipv4address = ip_address['ipv4-address'] h.id = '-' if host['id'] is None else host['id'] h.mac = '-' if host['mac'] is None else host['mac'] h.comm = '-' if host['comm'] == '' else host['comm'] h.name = '-' if host['name'] is None else host['name'] h.state = '-' if host['state'] is None else host['state'] h.os_family = '-' if host['os_family'] is None else host['os_family'] h.os_name = '-' if host['os_name'] is None else host['os_name'] h.os_flavor = '-' if host['os_flavor'] is None else host['os_flavor'] h.os_sp = '-' if host['os_sp'] is None else host['os_sp'] h.os_lang = '-' if host['os_lang'] is None else host['os_lang'] h.arch = '-' if host['arch'] is None else host['arch'] h.workspace_id = '-' if host['workspace_id'] is None else host[ 'workspace_id'] h.purpose = '-' if host['purpose'] is None else host['purpose'] h.info = '-' if host['info'] is None else host['info'] h.comments = '-' if host['comments'] is None else host['comments'] h.scope = '-' if host['scope'] is None else host['scope'] h.virtual_host = '-' if host['virtual_host'] is None else host[ 'virtual_host'] h.note_count = '-' if host['note_count'] is None else host['note_count'] h.vuln_count = '-' if host['vuln_count'] is None else host['vuln_count'] h.service_count = '-' if host['service_count'] is None else host[ 'service_count'] h.host_detail_count = '-' if host[ 'host_detail_count'] is None else host['host_detail_count'] h.exploit_attempt_count = '-' if host[ 'exploit_attempt_count'] is None else host['exploit_attempt_count'] h.cred_count = '-' if host['cred_count'] is None else host['cred_count'] h.detected_arch = '-' if host['detected_arch'] is None else host[ 'detected_arch'] h.created_at = host['created_at'] h.updated_at = host['updated_at'] # Origin Tool h.origin_tool = 'Metasploit' # Link Style h.link_color = LinkColor.Black h.link_thickness = 3 response += h return response
def do_transform(self, request, response, config): msf_service = request.entity # Test for properties ------------------------------------------------// try: test = msf_service['id'] except KeyError: raise MaltegoException( "This Service is not tied to a Metasploit Service. \ Please associate it with a Service before running this transform" ) return response dict = {} dict['id'] = msf_service.workspace_id dict['name'] = msf_service.name dict['created_at'] = msf_service.created_at dict['updated_at'] = msf_service.updated_at dict['info'] = msf_service.info dict['proto'] = msf_service.proto dict['port'] = msf_service.port dict['host_id'] = msf_service.host_id dict['state'] = msf_service.state data = json.dumps(dict) url = config['EffectiveCouscous.local.baseurl'] + 'services/{0}'.format( msf_service['id']) update = apitools.put_json(url, data, config) return response
def dotransform(request, response): checkdir(config['nexpose/reportdir']) # Nexpose API session login session = nexlogin() # Nexpose Adhoc report generation and save to file siteid = request.fields['siteid'] report = '%s.xml' % siteid reportstatus = reportChecker(session, siteid, report) if reportstatus == True: f = open(os.path.join(config['nexpose/reportdir'], report)) reporto = f.read() f.close else: raise MaltegoException('Something went wrong with the report checks') for dic in nexposeVulns(reporto): for key, val in dic.iteritems(): e = NexposeVulnerability(val[0], siteid=siteid, scanid=request.fields['scanid'], vulnid=key) e += Label('cvss Score', val[2]) e += Label('Severity', val[1]) response += e return response nexlogout(session)
def dotransform(request, response, config): try: btc_add = bitcoin_address(request.value) for trans in btc_add['transactions']: if 'Received' in trans['transaction_type']: e = BitcoinTransaction(trans['transaction_hash'], trans_type=trans['transaction_type'], amount=trans['transaction_amount'], trans_uri=trans['transaction_uri'], address=request.value) e += Field("date", trans['date'], displayname='Date') e += Label("Bitcoin Address", request.value) e += Label("Total Amount of Transaction", trans['transaction_amount']) e += Label("Transaction Type", trans['transaction_type']) e += Label("Transaction Date", trans['date']) e.linklabel = 'Received' response += e else: pass return response except Exception as e: raise MaltegoException('An error occured: %s' % e)
def dotransform(request, response): checkdir(config['nexpose/reportdir']) # Nexpose API session login session = nexlogin() # Nexpose Adhoc report generation and save to file siteid = request.fields['siteid'] report = '%s.xml' % siteid reportstatus = reportChecker(session, siteid, report) if reportstatus == True: f = open(os.path.join(config['nexpose/reportdir'], report)) reporto = f.read() f.close else: raise MaltegoException('Something went wrong with the report checks') for dic in nexposeExploits(reporto): for key, val in dic.iteritems(): if key == request.fields['vulnid'] and val[1] == 'exploitdb': e = NexposeEDBExploit(val[0], exploittype=val[1], siteid=siteid, scanid=request.fields['scanid'], vulnid=key) e += Label('Exploit DB URL', val[2]) e += Label('Skill Level', val[3]) response += e return response nexlogout(session)
def do_transform(self, request, response, config): # Get Credential JSON dictionary credential = request.entity # Test for properties try: url = config[ 'EffectiveCouscous.local.baseurl'] + 'credentials/{0}'.format( credential['id']) except KeyError: raise MaltegoException( "This Credential is not tied to a Metasploit Credential. Please associate it with a Credential before running this transform" ) return response cred = apitools.get_json_dict(url, config)[0] # THIS IS NOT WORKING: THE DICTIONARY ASKED FOR THE PUT METHOD IS # WEIRD, THEREFORE IT NEEDS TO BE COPIED ANOTHER WAY THAN THIS ONE # Push values # cred['id'] = int(credential.id) # cred['logins_count'] = int(credential.logins_count) # cred['public']['username'] = credential.pub_username # cred['public']['type'] = credential.pub_type # cred['private']['data'] = credential.priv_data # cred['private']['type'] = credential.priv_type # cred['private']['jtr_format'] = credential.priv_jtr_format # cred['origin']['service_id'] = credential.origin_service_id # cred['origin']['type'] = credential.origin_type # cred['origin']['module_full_name'] = credential.origin_module # data = json.dumps(cred) # update = apitools.post_json(url, data) return response
def dotransform(request, response): #Build the request type = 'hash' page = build(request.value, type) global count global count2 count = 1 try: list = page.find( text='Dropped File').previous.previous.parent.findAll('p') except: raise MaltegoException('No Dropped Files') for item in list: count2 = 1 if count % 2 == 1: split = item.findAll('a') for s in split: if count2 % 2 == 1: pass else: e = Hash(s.text) name = s.previous.previous.previous.text e += Field('Filename', name) response += e count2 += 1 elif count % 2 == 0: pass count += 1 return response
def croak(error_msg): """Throw an exception in the Maltego GUI containing error_msg.""" s = StringIO() Message( MaltegoMessage( MaltegoTransformExceptionMessage( exceptions=MaltegoException(error_msg)))).write(file=s) return s.getvalue()
def snmpargs(request): if request.fields['protocol'].upper() != 'UDP': raise MaltegoException( 'SNMP over UDP for versions 1 and 2c are only supported.') return (str(IPAddress(request.fields['snmp.agent'])), int(request.fields['ip.port']), request.value, request.fields['snmp.version'], config['scapy/sr_timeout'], config['scapy/sr_retries'])
def croak(error, message_writer=message): """Throw an exception in the Maltego GUI containing error_msg.""" if isinstance(error, MaltegoException): message_writer(MaltegoTransformExceptionMessage(exceptions=[error])) else: message_writer( MaltegoTransformExceptionMessage( exceptions=[MaltegoException(error)]))
def report(task_id): url = 'http://%s:%s/tasks/report/%s' % (config['cuckoo/host'], config['cuckoo/port'], task_id) try: r = requests.get(url) return r.json() except Exception as e: raise MaltegoException("The Transform has returned: %s" % e)
def file_search_md5(md5): url = 'http://%s:%s/files/view/md5/%s' % (config['cuckoo/host'], config['cuckoo/port'], md5) try: r = requests.get(url) return r.json() except Exception as e: raise MaltegoException("The Transform has returned: %s" % e)
def get_yeti_connection(config=None): global yeti_connection if yeti_connection: return yeti_connection if not config: raise MaltegoException("Configuration is empty !") assert 'Yeti.local.api_url' in config and 'Yeti.local.api_key' in config try: api = pyeti.YetiApi(url=config['Yeti.local.api_url'], api_key=config['Yeti.local.api_key']) return api except Exception: raise MaltegoException("Yeti Error")
def snmpargs(request): protocol = (request.entity.protocol or 'UDP').upper() if protocol != 'UDP': raise MaltegoException( 'SNMP over UDP for versions 1 and 2c are only supported.') return (str(IPAddress(request.entity.agent)), int(request.entity.port), request.value, request.entity.version, config['scapy/sr_timeout'], config['scapy/sr_retries'])
def __init__(self, config=None, parameters=None): self.misp = None if not config: raise MaltegoException( "ERROR: MISP connection not yet established, and config not provided as parameter." ) misp_verify = True misp_debug = False misp_url = None misp_key = None try: if is_local_exec_mode(): misp_url = config['MISP_maltego.local.misp_url'] misp_key = config['MISP_maltego.local.misp_key'] if config['MISP_maltego.local.misp_verify'] in [ 'False', 'false', 0, 'no', 'No' ]: misp_verify = False if config['MISP_maltego.local.misp_debug'] in [ 'True', 'true', 1, 'yes', 'Yes' ]: misp_debug = True else: try: misp_url = parameters['mispurl'].value misp_key = parameters['mispkey'].value except AttributeError: raise MaltegoException( "ERROR: mispurl and mispkey need to be set to something valid" ) self.misp = PyMISP(url=misp_url, key=misp_key, ssl=misp_verify, debug=misp_debug, tool='misp_maltego', timeout=(2, 60)) except Exception: if is_local_exec_mode(): raise MaltegoException( "ERROR: Cannot connect to MISP server. Please verify your MISP_Maltego.conf settings." ) else: raise MaltegoException( "ERROR: Cannot connect to MISP server. Please verify your settings (MISP URL and API key), and ensure the MISP server is reachable from the internet." )
def submit_file(sample): url = 'http://%s:%s/tasks/create/file' % (config['cuckoo/host'], config['cuckoo/port']) samples = {'file': open(sample, 'rb')} try: r = requests.post(url, files=samples) return r.json() except Exception as e: raise MaltegoException("The Transform has returned: %s" % e)