From abd836babb81a325562afbffcb3f9de23fa7075d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 25 Oct 2016 17:28:55 -0400 Subject: [PATCH 01/11] Add simple script to push MISP events into Neo4j --- examples/make_neo4j.py | 32 ++++++++++++++++++++++ pymisp/__init__.py | 1 + pymisp/tools/__init__.py | 0 pymisp/tools/neo4j.py | 59 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100755 examples/make_neo4j.py create mode 100644 pymisp/tools/__init__.py create mode 100644 pymisp/tools/neo4j.py diff --git a/examples/make_neo4j.py b/examples/make_neo4j.py new file mode 100755 index 0000000..247a866 --- /dev/null +++ b/examples/make_neo4j.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import PyMISP +from pymisp import Neo4j +from pymisp import MISPEvent +from keys import misp_url, misp_key +import argparse + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Get all the events matching a value.') + parser.add_argument("-s", "--search", required=True, help="String to search.") + parser.add_argument("--host", default='localhost:7474', help="Host where neo4j is running.") + parser.add_argument("-u", "--user", default='neo4j', help="User on neo4j.") + parser.add_argument("-p", "--password", default='neo4j', help="Password on neo4j.") + args = parser.parse_args() + + neo4j = Neo4j(args.host, args.user, args.password) + neo4j.del_all() + misp = PyMISP(misp_url, misp_key) + result = misp.search_all(args.search) + for json_event in result['response']: + if not json_event['Event']: + print(json_event) + continue + print('Importing', json_event['Event']['info'], json_event['Event']['id']) + try: + misp_event = MISPEvent() + misp_event.load(json_event) + neo4j.import_event(misp_event) + except: + print('broken') diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 7cbe0ee..e8553e2 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -3,3 +3,4 @@ __version__ = '2.4.53' from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey from .api import PyMISP from .mispevent import MISPEvent, MISPAttribute, EncodeUpdate, EncodeFull +from .tools.neo4j import Neo4j diff --git a/pymisp/tools/__init__.py b/pymisp/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pymisp/tools/neo4j.py b/pymisp/tools/neo4j.py new file mode 100644 index 0000000..cb49df1 --- /dev/null +++ b/pymisp/tools/neo4j.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import glob +import os +from pymisp import MISPEvent + +try: + from py2neo import authenticate, Graph, Node, Relationship + has_py2neo = True +except ImportError: + has_py2neo = False + + +class Neo4j(): + + def __init__(self, host='localhost:7474', username='neo4j', password='neo4j'): + if not has_py2neo: + raise Exception('py2neo is required, please install: pip install py2neo') + authenticate(host, username, password) + self.graph = Graph() + + def load_events_directory(self, directory): + self.events = [] + for path in glob.glob(os.path.join(directory, '*.json')): + e = MISPEvent() + e.load(path) + self.import_event(e) + + def del_all(self): + self.graph.delete_all() + + def import_event(self, event): + tx = self.graph.begin() + event_node = Node('Event', uuid=event.uuid) + event_node['name'] = event.info + # event_node['distribution'] = event.distribution + # event_node['threat_level_id'] = event.threat_level_id + # event_node['analysis'] = event.analysis + # event_node['published'] = event.published + # event_node['date'] = event.date.isoformat() + tx.create(event_node) + for a in event.attributes: + attr_node = Node('Attribute', a.type, uuid=a.uuid) + attr_node['category'] = a.category + attr_node['name'] = a.value + # attr_node['to_ids'] = a.to_ids + # attr_node['comment'] = a.comment + # attr_node['distribution'] = a.distribution + tx.create(attr_node) + member_rel = Relationship(event_node, "is member", attr_node) + tx.create(member_rel) + val = Node('Value', name=a.value) + ev = Relationship(event_node, "has", val) + av = Relationship(attr_node, "is", val) + s = val | ev | av + tx.merge(s) + tx.graph.push(s) + tx.commit() From 2907fd18d775bfd23070eb1db1bb99fd700652ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 27 Oct 2016 15:58:08 -0400 Subject: [PATCH 02/11] Cleanup neo4j support --- examples/make_neo4j.py | 4 +++- pymisp/tools/neo4j.py | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/make_neo4j.py b/examples/make_neo4j.py index 247a866..26b568e 100755 --- a/examples/make_neo4j.py +++ b/examples/make_neo4j.py @@ -13,10 +13,12 @@ if __name__ == '__main__': parser.add_argument("--host", default='localhost:7474', help="Host where neo4j is running.") parser.add_argument("-u", "--user", default='neo4j', help="User on neo4j.") parser.add_argument("-p", "--password", default='neo4j', help="Password on neo4j.") + parser.add_argument("-d", "--deleteall", action="store_true", default=False, help="Delete all nodes from the database") args = parser.parse_args() neo4j = Neo4j(args.host, args.user, args.password) - neo4j.del_all() + if args.deleteall: + neo4j.del_all() misp = PyMISP(misp_url, misp_key) result = misp.search_all(args.search) for json_event in result['response']: diff --git a/pymisp/tools/neo4j.py b/pymisp/tools/neo4j.py index cb49df1..af5ba2c 100644 --- a/pymisp/tools/neo4j.py +++ b/pymisp/tools/neo4j.py @@ -32,8 +32,7 @@ class Neo4j(): def import_event(self, event): tx = self.graph.begin() - event_node = Node('Event', uuid=event.uuid) - event_node['name'] = event.info + event_node = Node('Event', uuid=event.uuid, name=event.info) # event_node['distribution'] = event.distribution # event_node['threat_level_id'] = event.threat_level_id # event_node['analysis'] = event.analysis From d48f2481763a4bf8eb7c075fdeedf0e438708c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 27 Oct 2016 15:58:58 -0400 Subject: [PATCH 03/11] Fix Python2 - Python3 support --- pymisp/mispevent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index b436aab..bb3a024 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -20,10 +20,11 @@ from .exceptions import PyMISPError, NewEventError, NewAttributeError # Least dirty way to support python 2 and 3 try: - warnings.warn("You're using python 2, it is strongly recommended to use python >=3.3") basestring + warnings.warn("You're using python 2, it is strongly recommended to use python >=3.3") except NameError: basestring = str + unicode = str class MISPAttribute(object): From ac2e801d978e07111c1e4a3f922e1fe337b37c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 27 Oct 2016 16:25:17 -0400 Subject: [PATCH 04/11] Add helper tool to load STIX objects. --- pymisp/tools/stix.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 pymisp/tools/stix.py diff --git a/pymisp/tools/stix.py b/pymisp/tools/stix.py new file mode 100644 index 0000000..b964295 --- /dev/null +++ b/pymisp/tools/stix.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +try: + from misp_stix_converter.converters.buildMISPAttribute import buildEvent, open_stix + from misp_stix_converter.converters.convert import MISPtoSTIX + has_misp_stix_converter = True +except ImportError: + has_misp_stix_converter = False + + +def load_stix(stix, distribution=3, threat_level_id=2, analysis=0): + '''Returns a MISPEvent object from a STIX package''' + if not has_misp_stix_converter: + raise Exception('You need to install misp_stix_converter from https://github.com/MISP/MISP-STIX-Converter') + stix = open_stix(stix) + return buildEvent(stix, distribution=distribution, + threat_level_id=threat_level_id, analysis=analysis) + + +def make_stix_package(misp_event, to_json=False, to_xml=False): + '''Returns a STIXPackage from a MISPEvent. + + Optionally can return the package in json or xml. + + ''' + if not has_misp_stix_converter: + raise Exception('You need to install misp_stix_converter from https://github.com/MISP/MISP-STIX-Converter') + package = MISPtoSTIX(misp_event) + if to_json: + return package.to_json() + elif to_xml: + return package.to_xml() + else: + return package From 857cd40ea20d9c79282170ad6185dc53f5c9a9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 27 Oct 2016 16:29:56 -0400 Subject: [PATCH 05/11] Update import --- pymisp/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index e8553e2..dac6257 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -4,3 +4,4 @@ from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDe from .api import PyMISP from .mispevent import MISPEvent, MISPAttribute, EncodeUpdate, EncodeFull from .tools.neo4j import Neo4j +from .tools import stix From 81e3ce37afd617f18cdd5acc13d8dcebd53989f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 27 Oct 2016 17:04:23 -0400 Subject: [PATCH 06/11] Fix forgotten import --- pymisp/mispevent.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index bb3a024..5fa82c8 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -6,6 +6,7 @@ import time import json from json import JSONEncoder import os +import warnings try: from dateutil.parser import parse except ImportError: @@ -21,6 +22,7 @@ from .exceptions import PyMISPError, NewEventError, NewAttributeError # Least dirty way to support python 2 and 3 try: basestring + unicode warnings.warn("You're using python 2, it is strongly recommended to use python >=3.3") except NameError: basestring = str From bee1630e98320f8e00a2eeec9dbfc5e457d1b901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 28 Oct 2016 14:13:57 -0400 Subject: [PATCH 07/11] Add query example --- examples/make_neo4j.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/make_neo4j.py b/examples/make_neo4j.py index 26b568e..6393813 100755 --- a/examples/make_neo4j.py +++ b/examples/make_neo4j.py @@ -7,6 +7,17 @@ from pymisp import MISPEvent from keys import misp_url, misp_key import argparse +""" +Sample Neo4J query: + + +MATCH ()-[r:has]->(n) +WITH n, count(r) as rel_cnt +WHERE rel_cnt > 5 +MATCH (m)-[r:has]->(n) +RETURN m, n LIMIT 200; +""" + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Get all the events matching a value.') parser.add_argument("-s", "--search", required=True, help="String to search.") From 6c5289d495d44809ed0943dfd29247f680a82a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sat, 29 Oct 2016 15:27:48 -0400 Subject: [PATCH 08/11] Initial version of the OpenIOC loader --- pymisp/mispevent.py | 22 +++++--- pymisp/tools/openioc.py | 118 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 pymisp/tools/openioc.py diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 5fa82c8..e0ecb73 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -234,6 +234,19 @@ class MISPEvent(object): self._reinitialize_event() self.set_all_values(**e) + def set_date(self, date, ignore_invalid=False): + if isinstance(date, basestring) or isinstance(date, unicode): + self.date = parse(date).date() + elif isinstance(date, datetime.datetime): + self.date = date.date() + elif isinstance(date, datetime.date): + self.date = date + else: + if ignore_invalid: + self.date = datetime.date.today() + else: + raise NewEventError('Invalid format for the date: {} - {}'.format(date, type(date))) + def set_all_values(self, **kwargs): # Required value if kwargs.get('info'): @@ -257,14 +270,7 @@ class MISPEvent(object): if kwargs.get('published') is not None: self.publish() if kwargs.get('date'): - if isinstance(kwargs['date'], basestring) or isinstance(kwargs['date'], unicode): - self.date = parse(kwargs['date']).date() - elif isinstance(kwargs['date'], datetime.datetime): - self.date = kwargs['date'].date() - elif isinstance(kwargs['date'], datetime.date): - self.date = kwargs['date'] - else: - raise NewEventError('Invalid format for the date: {} - {}'.format(kwargs['date'], type(kwargs['date']))) + self.set_date(kwargs['date']) if kwargs.get('Attribute'): for a in kwargs['Attribute']: attribute = MISPAttribute(self.describe_types) diff --git a/pymisp/tools/openioc.py b/pymisp/tools/openioc.py new file mode 100644 index 0000000..7c89b95 --- /dev/null +++ b/pymisp/tools/openioc.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import MISPEvent +try: + from bs4 import BeautifulSoup + has_bs4 = True +except ImportError: + has_bs4 = False + + +iocMispMapping = { + 'DriverItem/DriverName': {'category': 'Artifacts dropped', 'type': 'other', 'comment': 'DriverName.'}, + + 'DnsEntryItem/Host': {'type': 'domain'}, + + 'Email/To': {'type': 'target-email'}, + 'Email/Date': {'type': 'comment', 'comment': 'EmailDate.'}, + 'Email/Body': {'type': 'email-subject'}, + 'Email/From': {'type': 'email-dst'}, + 'Email/Subject': {'type': 'email-subject'}, + 'Email/Attachment/Name': {'type': 'email-attachment'}, + + 'FileItem/Md5sum': {'type': 'md5'}, + 'FileItem/Sha1sum': {'type': 'sha1'}, + 'FileItem/Sha256sum': {'type': 'sha256'}, + 'FileItem/FileName': {'type': 'filename'}, + 'FileItem/FullPath': {'type': 'filename'}, + 'FileItem/FilePath': {'type': 'filename'}, + + 'Network/URI': {'type': 'uri'}, + 'Network/DNS': {'type': 'domain'}, + 'Network/String': {'type': 'ip-dst'}, + 'Network/UserAgent': {'type': 'user-agent'}, + + 'PortItem/localIP': {'type': 'ip-dst'}, + + 'ProcessItem/name': {'type': 'pattern-in-memory', 'comment': 'ProcessName.'}, + 'ProcessItem/path': {'type': 'pattern-in-memory', 'comment': 'ProcessPath.'}, + 'ProcessItem/Mutex': {'type': 'mutex'}, + 'ProcessItem/Pipe/Name': {'type': 'named pipe'}, + 'ProcessItem/Mutex/Name': {'type': 'mutex', 'comment': 'MutexName.'}, + + # Is it the regkey value? + # 'RegistryItem/Text': {'type': 'regkey', 'RegistryText. '}, + 'RegistryItem/Path': {'type': 'regkey'}, + + 'ServiceItem/name': {'type': 'windows-service-name'}, + 'ServiceItem/type': {'type': 'pattern-in-memory', 'comment': 'ServiceType. '}, + + 'Snort/Snort': {'type': 'snort'}, +} + + +def extract_field(report, field_name): + data = report.find(field_name.lower()) + if data and hasattr(data, 'text'): + return data.text + return None + + +def load_openioc(openioc): + if not has_bs4: + raise Exception('You need to install BeautifulSoup: pip install bs4') + misp_event = MISPEvent() + with open(openioc, "r") as ioc_file: + iocreport = BeautifulSoup(ioc_file, "lxml") + # Set event fields + info = extract_field(iocreport, 'short_description') + if info: + misp_event.info = info + date = extract_field(iocreport, 'authored_date') + if date: + misp_event.set_date(date) + # Set special attributes + description = extract_field(iocreport, 'description') + if description: + misp_event.add_attribute('comment', description) + author = extract_field(iocreport, 'authored_by') + if author: + misp_event.add_attribute('comment', author) + misp_event = set_all_attributes(iocreport, misp_event) + return misp_event + + +def get_mapping(openioc_type): + t = openioc_type.lower() + for k, v in iocMispMapping.items(): + if k.lower() == t: + return v + return False + + +def set_all_attributes(openioc, misp_event): + for item in openioc.find_all("indicatoritem"): + print(item) + attribute_values = {'comment': ''} + if item.find('context'): + mapping = get_mapping(item.find('context')['search']) + if mapping: + attribute_values.update(mapping) + else: + # Unknown mapping, ignoring + # print(item.find('context')) + continue + else: + continue + value = extract_field(openioc, 'Content') + if value: + attribute_values['value'] = value + else: + # No value, ignoring + continue + comment = extract_field(openioc, 'Comment') + if comment: + attribute_values["comment"] = '{} {}'.format(attribute_values["comment"], comment) + misp_event.add_attribute(**attribute_values) + return misp_event From 9f0737c34a965938fc3608bb080a8b83e263a4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 3 Nov 2016 16:01:48 -0400 Subject: [PATCH 09/11] Add some mapping to openioc, add python version in the user agent --- pymisp/api.py | 3 ++- pymisp/tools/openioc.py | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 7566086..113c691 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -3,6 +3,7 @@ """Python API using the REST interface of MISP""" +import sys import json import datetime import os @@ -136,7 +137,7 @@ class PyMISP(object): {'Authorization': self.key, 'Accept': 'application/{}'.format(output), 'content-type': 'application/{}'.format(output), - 'User-Agent': 'PyMISP {}'.format(__version__)}) + 'User-Agent': 'PyMISP {} - Python {}.{}.{}'.format(__version__, *sys.version_info)}) return session def flatten_error_messages(self, response): diff --git a/pymisp/tools/openioc.py b/pymisp/tools/openioc.py index 7c89b95..e6be33d 100644 --- a/pymisp/tools/openioc.py +++ b/pymisp/tools/openioc.py @@ -23,14 +23,17 @@ iocMispMapping = { 'FileItem/Md5sum': {'type': 'md5'}, 'FileItem/Sha1sum': {'type': 'sha1'}, + 'TaskItem/Sha1sum': {'type': 'sha1'}, 'FileItem/Sha256sum': {'type': 'sha256'}, 'FileItem/FileName': {'type': 'filename'}, 'FileItem/FullPath': {'type': 'filename'}, 'FileItem/FilePath': {'type': 'filename'}, + 'DriverItem/DriverName': {'type': 'filename'}, 'Network/URI': {'type': 'uri'}, 'Network/DNS': {'type': 'domain'}, 'Network/String': {'type': 'ip-dst'}, + 'RouteEntryItem/Destination': {'type': 'ip-dst'}, 'Network/UserAgent': {'type': 'user-agent'}, 'PortItem/localIP': {'type': 'ip-dst'}, @@ -41,8 +44,16 @@ iocMispMapping = { 'ProcessItem/Pipe/Name': {'type': 'named pipe'}, 'ProcessItem/Mutex/Name': {'type': 'mutex', 'comment': 'MutexName.'}, + 'CookieHistoryItem/HostName': {'type': 'hostname'}, + 'FormHistoryItem/HostName': {'type': 'hostname'}, + 'SystemInfoItem/HostName': {'type': 'hostname'}, + 'UrlHistoryItem/HostName': {'type': 'hostname'}, + 'DnsEntryItem/RecordName': {'type': 'hostname'}, + 'DnsEntryItem/Host': {'type': 'hostname'}, + # Is it the regkey value? # 'RegistryItem/Text': {'type': 'regkey', 'RegistryText. '}, + 'RegistryItem/KeyPath': {'type': 'regkey'}, 'RegistryItem/Path': {'type': 'regkey'}, 'ServiceItem/name': {'type': 'windows-service-name'}, @@ -93,7 +104,6 @@ def get_mapping(openioc_type): def set_all_attributes(openioc, misp_event): for item in openioc.find_all("indicatoritem"): - print(item) attribute_values = {'comment': ''} if item.find('context'): mapping = get_mapping(item.find('context')['search']) From bbf919878712a8f334b79ed21c28b950c86ce269 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Fri, 4 Nov 2016 09:31:31 +0100 Subject: [PATCH 10/11] Moving Neo4j into graphdb --- examples/make_neo4j.py | 45 ------------------------------------------ 1 file changed, 45 deletions(-) delete mode 100755 examples/make_neo4j.py diff --git a/examples/make_neo4j.py b/examples/make_neo4j.py deleted file mode 100755 index 6393813..0000000 --- a/examples/make_neo4j.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pymisp import PyMISP -from pymisp import Neo4j -from pymisp import MISPEvent -from keys import misp_url, misp_key -import argparse - -""" -Sample Neo4J query: - - -MATCH ()-[r:has]->(n) -WITH n, count(r) as rel_cnt -WHERE rel_cnt > 5 -MATCH (m)-[r:has]->(n) -RETURN m, n LIMIT 200; -""" - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Get all the events matching a value.') - parser.add_argument("-s", "--search", required=True, help="String to search.") - parser.add_argument("--host", default='localhost:7474', help="Host where neo4j is running.") - parser.add_argument("-u", "--user", default='neo4j', help="User on neo4j.") - parser.add_argument("-p", "--password", default='neo4j', help="Password on neo4j.") - parser.add_argument("-d", "--deleteall", action="store_true", default=False, help="Delete all nodes from the database") - args = parser.parse_args() - - neo4j = Neo4j(args.host, args.user, args.password) - if args.deleteall: - neo4j.del_all() - misp = PyMISP(misp_url, misp_key) - result = misp.search_all(args.search) - for json_event in result['response']: - if not json_event['Event']: - print(json_event) - continue - print('Importing', json_event['Event']['info'], json_event['Event']['id']) - try: - misp_event = MISPEvent() - misp_event.load(json_event) - neo4j.import_event(misp_event) - except: - print('broken') From 55b4a0725bcd091c959df1b4b9b29d50980a3d5d Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Fri, 4 Nov 2016 09:31:52 +0100 Subject: [PATCH 11/11] Neo4j stuff moved into graphdb directory --- examples/graphdb/make_neo4j.py | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 examples/graphdb/make_neo4j.py diff --git a/examples/graphdb/make_neo4j.py b/examples/graphdb/make_neo4j.py new file mode 100755 index 0000000..6393813 --- /dev/null +++ b/examples/graphdb/make_neo4j.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import PyMISP +from pymisp import Neo4j +from pymisp import MISPEvent +from keys import misp_url, misp_key +import argparse + +""" +Sample Neo4J query: + + +MATCH ()-[r:has]->(n) +WITH n, count(r) as rel_cnt +WHERE rel_cnt > 5 +MATCH (m)-[r:has]->(n) +RETURN m, n LIMIT 200; +""" + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Get all the events matching a value.') + parser.add_argument("-s", "--search", required=True, help="String to search.") + parser.add_argument("--host", default='localhost:7474', help="Host where neo4j is running.") + parser.add_argument("-u", "--user", default='neo4j', help="User on neo4j.") + parser.add_argument("-p", "--password", default='neo4j', help="Password on neo4j.") + parser.add_argument("-d", "--deleteall", action="store_true", default=False, help="Delete all nodes from the database") + args = parser.parse_args() + + neo4j = Neo4j(args.host, args.user, args.password) + if args.deleteall: + neo4j.del_all() + misp = PyMISP(misp_url, misp_key) + result = misp.search_all(args.search) + for json_event in result['response']: + if not json_event['Event']: + print(json_event) + continue + print('Importing', json_event['Event']['info'], json_event['Event']['id']) + try: + misp_event = MISPEvent() + misp_event.load(json_event) + neo4j.import_event(misp_event) + except: + print('broken')