From 620690f74575789e446752984a2dce6f0c74f2c5 Mon Sep 17 00:00:00 2001 From: ebouillon Date: Sat, 20 Feb 2016 16:58:38 +0100 Subject: [PATCH] Added files via upload Init --- MaltegoTransform.py | 174 +++++++++++++++++++++++++++++++++++++++++++ README | 29 ++++++++ misp_domain2event.py | 29 ++++++++ misp_event2domain.py | 38 ++++++++++ misp_getEventInfo.py | 30 ++++++++ misp_util.py | 37 +++++++++ 6 files changed, 337 insertions(+) create mode 100644 MaltegoTransform.py create mode 100644 README create mode 100644 misp_domain2event.py create mode 100644 misp_event2domain.py create mode 100644 misp_getEventInfo.py create mode 100644 misp_util.py diff --git a/MaltegoTransform.py b/MaltegoTransform.py new file mode 100644 index 0000000..9791d67 --- /dev/null +++ b/MaltegoTransform.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +####################################################### +# Maltego Python Local Transform Helper # +# Version 0.2 # +# # +# Local transform specification can be found at: # +# http://ctas.paterva.com/view/Specification # +# # +# For more help and other local transforms # +# try the forum or mail me: # +# # +# http://www.paterva.com/forum # +# # +# Andrew MacPherson [ andrew <> Paterva.com ] # +# # +####################################################### +import sys + +def u2a_ascii(text): + # takes care of "'ascii' codec can't encode character" errors + return text.encode('unicode-escape') + +class MaltegoEntity(object): + value = ""; + weight = 100; + displayInformation = None; + additionalFields = []; + iconURL = ""; + entityType = "Phrase" + + def __init__(self,eT=None,v=None): + if (eT is not None): + self.entityType = eT; + if (v is not None): + self.value = sanitise(v); + self.additionalFields = []; + self.displayInformation = None; + + def setType(self,eT=None): + if (eT is not None): + self.entityType = eT; + + def setValue(self,eV=None): + if (eV is not None): + self.value = sanitise(eV); + + def setWeight(self,w=None): + if (w is not None): + self.weight = w; + + def setDisplayInformation(self,di=None): + if (di is not None): + self.displayInformation = di; + + def addAdditionalFields(self,fieldName=None,displayName=None,matchingRule=False,value=None): + self.additionalFields.append([sanitise(fieldName),sanitise(displayName),matchingRule,sanitise(value)]); + + def setIconURL(self,iU=None): + if (iU is not None): + self.iconURL = iU; + + def returnEntity(self): + print ""; + print "" + str(self.value) + ""; + print "" + str(self.weight) + ""; + if (self.displayInformation is not None): + print ""; + if (len(self.additionalFields) > 0): + print ""; + for i in range(len(self.additionalFields)): + if (str(self.additionalFields[i][2]) <> "strict"): + print "" + str(u2a_ascii(self.additionalFields[i][3])) + ""; + else: + print "" + str(u2a_ascii(self.additionalFields[i][3])) + ""; + print ""; + if (len(self.iconURL) > 0): + print "" + self.iconURL + ""; + print ""; + +class MaltegoTransform(object): + entities = [] + exceptions = [] + UIMessages = [] + values = {}; + + def __init__(self): + values = {}; + value = None; + + def parseArguments(self,argv): + if (argv[1] is not None): + self.value = argv[1]; + + if (len(argv) > 2): + if (argv[2] is not None): + vars = argv[2].split('#'); + for x in range(0,len(vars)): + vars_values = vars[x].split('=') + if (len(vars_values) == 2): + self.values[vars_values[0]] = vars_values[1]; + + def getValue(self): + if (self.value is not None): + return self.value; + + def getVar(self,varName): + if (varName in self.values.keys()): + if (self.values[varName] is not None): + return self.values[varName]; + + def addEntity(self,enType,enValue): + me = MaltegoEntity(enType,enValue); + self.addEntityToMessage(me); + return self.entities[len(self.entities)-1]; + + def addEntityToMessage(self,maltegoEntity): + self.entities.append(maltegoEntity); + + def addUIMessage(self,message,messageType="Inform"): + self.UIMessages.append([messageType,message]); + + def addException(self,exceptionString): + self.exceptions.append(exceptionString); + + def throwExceptions(self): + print ""; + print ""; + print "" + + for i in range(len(self.exceptions)): + print "" + self.exceptions[i] + ""; + print "" + print ""; + print ""; + exit(); + + def returnOutput(self): + print ""; + print ""; + + print "" + for i in range(len(self.entities)): + self.entities[i].returnEntity(); + print "" + + print "" + for i in range(len(self.UIMessages)): + print "" + self.UIMessages[i][1] + ""; + print "" + + print ""; + print ""; + + def writeSTDERR(self,msg): + sys.stderr.write(str(msg)); + + def heartbeat(self): + self.writeSTDERR("+"); + + def progress(self,percent): + self.writeSTDERR("%" + str(percent)); + + def debug(self,msg): + self.writeSTDERR("D:" + str(msg)); + + + +def sanitise(value): + replace_these = ["&",">","<"]; + replace_with = ["&",">","<"]; + tempvalue = value; + for i in range(0,len(replace_these)): + tempvalue = tempvalue.replace(replace_these[i],replace_with[i]); + return tempvalue; diff --git a/README b/README new file mode 100644 index 0000000..3b503ed --- /dev/null +++ b/README @@ -0,0 +1,29 @@ +MISP-Maltego + +Set of Maltego transforms to interface with a MISP instance. + +Prerequisites: +- MISP instance API access +- PyMISP + +INSTALL: + +- Edit misp_util.py and set BASE_URL and API_KEY variables with your MISP base URL and MISP API key. + +- Create symbolic links to misp_domain2event.py and misp_event2domain.py +$ for i in misp_email2event.py misp_email-subject2event.py misp_ip2event.py misp_hash2event.py ; do ln -s misp_domain2event.py $i; done +$ for i in misp_event2email.py misp_event2email-subject.py misp_event2hash.py misp_event2ip.py ; do ln -s misp_event2domain.py $i; done + +- Import transforms in Maltego as follows (for instance): +misp_ip2event.py: [MISP] IP to Event / Returns MISPEvent entities containing the corresponding IP attribute +misp_domain2event.py: [MISP] Domain to Event / Returns MISPEvent entities containing the corresponding Domain attribute +misp_hash2event.py: [MISP] Hash to Event / Returns MISPEvent entities containing the corresponding Hash attribute +misp_ip2event.py: [MISP] Email address to Event / Returns MISPEvent entities containing the corresponding Email address attribute +misp_email-subject2event.py: [MISP] Email subject to Event / Returns MISPEvent entities containing the corresponding Email subject attribute +misp_event2ip.py: [MISP] Event to IP attribute / Returns the IP attributes belonging to an event +misp_event2domain.py: [MISP] Event to Domain attribute / Returns Domain attributes belonging to an event +misp_event2hash.py: [MISP] Event to Hash attribute / Returns Hash attributes belonging to an event +misp_event2email.py: [MISP] Event to Email address attribute / Returns Email address attributes belonging to an event +misp_event2email-subject.py: [MISP] Event to Email subject attribute / Returns Email subject attributes belonging to an event +misp_getEventInfo.py: [MISP] Get Event Info / Adorns the Event with Info as notes + diff --git a/misp_domain2event.py b/misp_domain2event.py new file mode 100644 index 0000000..3bfc995 --- /dev/null +++ b/misp_domain2event.py @@ -0,0 +1,29 @@ +############################################# +# MISP API Domain to Event +# +# Author: Emmanuel Bouillon +# Email: emmanuel.bouillon.sec@gmail.com +# Date: 24/11/2015 +############################################# +import sys +from misp_util import * +from pymisp import PyMISP +import json + +attribute2filter = { + 'ip':'ip-src&&ip-dst', 'domain':'domain&&hostname', + 'hash':'md5&&sha1&&sha256&&malware-sample', + 'email':'email-src&&email-dst', 'email-subject': 'email-subject' +} + +if __name__ == '__main__': + enValue = sys.argv[1] + enType = sys.argv[0].split('_')[-1].split('2')[0] #misp_enType2event.py + mt = MaltegoTransform() + mt.addUIMessage("[INFO] " + enType + " to MISP Event") + try: + retrieveEvents(mt, attribute2filter[enType], enValue) + except Exception as e: + mt.addUIMessage("[Error] " + str(e)) + mt.returnOutput() + diff --git a/misp_event2domain.py b/misp_event2domain.py new file mode 100644 index 0000000..3da178a --- /dev/null +++ b/misp_event2domain.py @@ -0,0 +1,38 @@ +############################################# +# MISP API Domain to Event +# +# Author: Emmanuel Bouillon +# Email: emmanuel.bouillon.sec@gmail.com +# Date: 24/11/2015 +############################################# +import sys +from misp_util import * +from pymisp import PyMISP +import json + +type2attribute = {'domain':('domain','hostname'), 'hostname':('hostname'), 'hash':('md5','sha1','sha256') , 'ip':('ip-src','ip-dst'), 'email':('email-src','email-dst'), 'email-subject': ('email-subject')} +argType2enType = {'domain':'maltego.Domain', 'hostname':'maltego.Domain', 'hash':'maltego.Hash', 'ip':'maltego.IPv4Address', 'email':'maltego.EmailAddress', 'email-subject': 'maltego.Phrase'} +filename_pipe_hash_type = ('filename|md5', 'filename|sha1', 'filename|sha256', 'malware-sample') + +if __name__ == '__main__': + event_id = sys.argv[1] + argType = sys.argv[0].split('.')[0].split('2')[1] # misp_event2argType.py + misp = init() + try: + event = misp.get_event(event_id) + event_json = event.json() + mt = MaltegoTransform() + for attribute in event_json['Event']["Attribute"]: + value = attribute["value"] + aType = attribute["type"] + if aType in type2attribute[argType]: + if aType in filename_pipe_hash_type: + h = value.split('|')[1].strip() + me = MaltegoEntity(argType2enType[argType], h) + mt.addEntityToMessage(me); + else: + me = MaltegoEntity(argType2enType[argType], value) + mt.addEntityToMessage(me); + except Exception as e: + mt.addUIMessage("[ERROR] " + str(e)) + mt.returnOutput() diff --git a/misp_getEventInfo.py b/misp_getEventInfo.py new file mode 100644 index 0000000..66d0dd2 --- /dev/null +++ b/misp_getEventInfo.py @@ -0,0 +1,30 @@ +############################################# +# MISP API Domain to Event +# +# Author: Emmanuel Bouillon +# Email: emmanuel.bouillon.sec@gmail.com +# Date: 24/11/2015 +############################################# +import sys +from misp_util import * +from pymisp import PyMISP +import json + +if __name__ == '__main__': + m = init() + mt = MaltegoTransform() + event_id = sys.argv[1] + try: + event = m.get_event(event_id) + event_json = event.json() + eid = event_json['Event']['id'] + einfo = event_json['Event']['info'] + eorgc = event_json['Event']['orgc'] + me = MaltegoEntity('maltego.MISPEvent',eid); + me.addAdditionalFields('EventLink', 'EventLink', False, BASE_URL + '/events/view/' + eid ) + me.addAdditionalFields('Org', 'Org', False, eorgc) + me.addAdditionalFields('notes#', 'notes', False, eorgc + ": " + einfo) + mt.addEntityToMessage(me); + except Exception as e: + mt.addUIMessage("[ERROR] " + str(e)) + mt.returnOutput() diff --git a/misp_util.py b/misp_util.py new file mode 100644 index 0000000..79f1477 --- /dev/null +++ b/misp_util.py @@ -0,0 +1,37 @@ +############################################# +# MISP API miscellaneous functions. +# +# Author: Emmanuel Bouillon +# Email: emmanuel.bouillon.sec@gmail.com +# Date: 24/11/2015 +############################################# + +# MISP BASE URL +BASE_URL = '' +# API KEY +API_KEY = '' +# MISP_VERIFYCERT +MISP_VERIFYCERT = True +# pyMISP DEBUG +MISP_DEBUG = False + +from pymisp import PyMISP +from MaltegoTransform import * + +def init(): + return PyMISP(BASE_URL, API_KEY, MISP_VERIFYCERT, 'json', MISP_DEBUG) + +def retrieveEvents(mt, enFilter, enValue): + misp = init() + result = misp.search(values = enValue, type_attribute = enFilter) + for e in result['response']: + eid = e['Event']['id'] + einfo = e['Event']['info'] + eorgc = e['Event']['orgc'] + me = MaltegoEntity('maltego.MISPEvent',eid); + me.addAdditionalFields('EventLink', 'EventLink', False, BASE_URL + '/events/view/' + eid ) + me.addAdditionalFields('Org', 'Org', False, eorgc) + me.addAdditionalFields('notes#', 'notes', False, eorgc + ": " + einfo) + mt.addEntityToMessage(me); + return +