From 5ab8b605bbfcab03328c47db90adceb4ed699a6a Mon Sep 17 00:00:00 2001 From: milkmix Date: Mon, 24 Dec 2018 14:39:25 +0100 Subject: [PATCH 1/6] first export feature: sha1 attributes nxql query --- misp_modules/modules/export_mod/__init__.py | 2 +- .../modules/export_mod/nexthinkexport.py | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100755 misp_modules/modules/export_mod/nexthinkexport.py diff --git a/misp_modules/modules/export_mod/__init__.py b/misp_modules/modules/export_mod/__init__.py index 7f1fa50..1affbd2 100644 --- a/misp_modules/modules/export_mod/__init__.py +++ b/misp_modules/modules/export_mod/__init__.py @@ -1,2 +1,2 @@ __all__ = ['cef_export', 'liteexport', 'goamlexport', 'threat_connect_export', 'pdfexport', - 'threatStream_misp_export', 'osqueryexport'] + 'threatStream_misp_export', 'osqueryexport', 'nexthinkexport'] diff --git a/misp_modules/modules/export_mod/nexthinkexport.py b/misp_modules/modules/export_mod/nexthinkexport.py new file mode 100755 index 0000000..92af800 --- /dev/null +++ b/misp_modules/modules/export_mod/nexthinkexport.py @@ -0,0 +1,86 @@ +""" +Export module for coverting MISP events into Nexthink NXQL queries. +Source: https://github.com/HacknowledgeCH/misp-modules/blob/master/misp_modules/modules/export_mod/nexthinkexport.py +Config['Period'] : allows to define period over witch to look for IOC from now (15m, 1d, 2w, 30d, ...) +""" + +import base64 +import json +import re + +misperrors = {"error": "Error"} + +types_to_use = ['sha1'] + +userConfig = { + +} + +moduleconfig = ["Period"] +inputSource = ['event'] + +outputFileExtension = 'conf' +responseType = 'application/txt' + + +moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', + 'description': 'Nexthink NXQL query export module', + 'module-type': ['export']} + + +def handle_sha1(value, period): + return ''' + (select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) + (from (binary user device execution) + (where binary (eq hash (sha1 %s)))) + (between now-%s now) + (limit 1000)) + ''' % (value, period) + +handlers = { + 'sha1': handle_sha1 +} + +def handler(q=False): + if q is False: + return False + r = {'results': []} + request = json.loads(q) + config = request.get("config", {"Period": ""}) + output = '' + + for event in request["data"]: + for attribute in event["Attribute"]: + if attribute['type'] in types_to_use: + output = output + handlers[attribute['type']](attribute['value'], config['Period']) + '\n' + r = {"response": [], "data": str(base64.b64encode(bytes(output, 'utf-8')), 'utf-8')} + return r + + +def introspection(): + modulesetup = {} + try: + responseType + modulesetup['responseType'] = responseType + except NameError: + pass + try: + userConfig + modulesetup['userConfig'] = userConfig + except NameError: + pass + try: + outputFileExtension + modulesetup['outputFileExtension'] = outputFileExtension + except NameError: + pass + try: + inputSource + modulesetup['inputSource'] = inputSource + except NameError: + pass + return modulesetup + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo From 537f9132f518fc702eecc0adb03ce7cbeda9c446 Mon Sep 17 00:00:00 2001 From: milkmix Date: Mon, 24 Dec 2018 16:40:31 +0100 Subject: [PATCH 2/6] support for md5 and sha1 hashes --- .../modules/export_mod/nexthinkexport.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/misp_modules/modules/export_mod/nexthinkexport.py b/misp_modules/modules/export_mod/nexthinkexport.py index 92af800..ee05923 100755 --- a/misp_modules/modules/export_mod/nexthinkexport.py +++ b/misp_modules/modules/export_mod/nexthinkexport.py @@ -10,7 +10,7 @@ import re misperrors = {"error": "Error"} -types_to_use = ['sha1'] +types_to_use = ['sha1', 'md5'] userConfig = { @@ -29,16 +29,26 @@ moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', def handle_sha1(value, period): - return ''' - (select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) - (from (binary user device execution) - (where binary (eq hash (sha1 %s)))) - (between now-%s now) - (limit 1000)) + query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) +(from (binary user device execution) +(where binary (eq sha1 (sha1 %s))) +(between now-%s now)) +(limit 1000) ''' % (value, period) + return query.replace('\n', ' ') + +def handle_md5(value, period): + query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) +(from (binary user device execution) +(where binary (eq hash (md5 %s))) +(between now-%s now)) +(limit 1000) + ''' % (value, period) + return query.replace('\n', ' ') handlers = { - 'sha1': handle_sha1 + 'sha1': handle_sha1, + 'md5': handle_md5 } def handler(q=False): @@ -56,7 +66,6 @@ def handler(q=False): r = {"response": [], "data": str(base64.b64encode(bytes(output, 'utf-8')), 'utf-8')} return r - def introspection(): modulesetup = {} try: From b64c3e4bf4f2af06257cf196388429d3db959034 Mon Sep 17 00:00:00 2001 From: milkmix Date: Mon, 24 Dec 2018 17:07:45 +0100 Subject: [PATCH 3/6] added domain attributes support --- .../modules/export_mod/nexthinkexport.py | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/misp_modules/modules/export_mod/nexthinkexport.py b/misp_modules/modules/export_mod/nexthinkexport.py index ee05923..eaa2f7a 100755 --- a/misp_modules/modules/export_mod/nexthinkexport.py +++ b/misp_modules/modules/export_mod/nexthinkexport.py @@ -1,7 +1,7 @@ """ Export module for coverting MISP events into Nexthink NXQL queries. Source: https://github.com/HacknowledgeCH/misp-modules/blob/master/misp_modules/modules/export_mod/nexthinkexport.py -Config['Period'] : allows to define period over witch to look for IOC from now (15m, 1d, 2w, 30d, ...) +Config['Period'] : allows to define period over witch to look for IOC from now (15m, 1d, 2w, 30d, ...), see Nexthink data model documentation """ import base64 @@ -10,7 +10,7 @@ import re misperrors = {"error": "Error"} -types_to_use = ['sha1', 'md5'] +types_to_use = ['sha1', 'sha256', 'md5', 'domain'] userConfig = { @@ -19,7 +19,7 @@ userConfig = { moduleconfig = ["Period"] inputSource = ['event'] -outputFileExtension = 'conf' +outputFileExtension = 'nxql' responseType = 'application/txt' @@ -27,7 +27,6 @@ moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', 'description': 'Nexthink NXQL query export module', 'module-type': ['export']} - def handle_sha1(value, period): query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) (from (binary user device execution) @@ -37,6 +36,15 @@ def handle_sha1(value, period): ''' % (value, period) return query.replace('\n', ' ') +def handle_sha256(value, period): + query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) +(from (binary user device execution) +(where binary (eq sha256 (sha256 %s))) +(between now-%s now)) +(limit 1000) + ''' % (value, period) + return query.replace('\n', ' ') + def handle_md5(value, period): query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) (from (binary user device execution) @@ -46,9 +54,21 @@ def handle_md5(value, period): ''' % (value, period) return query.replace('\n', ' ') +def handle_domain(value, period): + query = '''select ((device name) (device (name last_ip_address)) (user name)(user department) (binary executable_name)(binary application_name)(binary description)(binary application_category)(binary (executable_name version)) (binary #"Suspicious binary")(binary first_seen)(binary last_seen)(binary threat_level)(binary hash) (binary paths) +(destination name)(domain name) (domain domain_category)(domain hosting_country)(domain protocol)(domain threat_level) (port port_number)(web_request incoming_traffic)(web_request outgoing_traffic)) +(from (web_request device user binary executable destination domain port) +(where domain (eq name(string %s))) +(between now-%s now)) +(limit 1000) + ''' % (value, period) + return query.replace('\n', ' ') + handlers = { 'sha1': handle_sha1, - 'md5': handle_md5 + 'sha256': handle_sha256, + 'md5': handle_md5, + 'domain': handle_domain } def handler(q=False): From ae5747efd5a878efe7c137a5f88780befadccfa0 Mon Sep 17 00:00:00 2001 From: milkmix Date: Mon, 24 Dec 2018 17:18:31 +0100 Subject: [PATCH 4/6] added documentation --- doc/export_mod/nexthinkexport.json | 9 +++++++++ doc/logos/nexthink.svg | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 doc/export_mod/nexthinkexport.json create mode 100644 doc/logos/nexthink.svg diff --git a/doc/export_mod/nexthinkexport.json b/doc/export_mod/nexthinkexport.json new file mode 100644 index 0000000..182448c --- /dev/null +++ b/doc/export_mod/nexthinkexport.json @@ -0,0 +1,9 @@ +{ + "description": "Nexthink NXQL query export module", + "requirements": [], + "features": "This module export an event as Nexthink NXQL queries that can then be used in your own python3 tool or from wget/powershell", + "references": ["https://doc.nexthink.com/Documentation/Nexthink/latest/APIAndIntegrations/IntroducingtheWebAPIV2"], + "input": "MISP Event attributes", + "output": "Nexthink NXQL queries", + "logo": "logos/nexthink.svg" +} diff --git a/doc/logos/nexthink.svg b/doc/logos/nexthink.svg new file mode 100644 index 0000000..f18ba8f --- /dev/null +++ b/doc/logos/nexthink.svg @@ -0,0 +1,22 @@ + + + + nexthink + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file From 615a56f9bbb8e59cb38f82405cef14a15f93f5bb Mon Sep 17 00:00:00 2001 From: milkmix Date: Mon, 24 Dec 2018 17:32:47 +0100 Subject: [PATCH 5/6] removed unused re module --- misp_modules/modules/export_mod/nexthinkexport.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/misp_modules/modules/export_mod/nexthinkexport.py b/misp_modules/modules/export_mod/nexthinkexport.py index eaa2f7a..0123808 100755 --- a/misp_modules/modules/export_mod/nexthinkexport.py +++ b/misp_modules/modules/export_mod/nexthinkexport.py @@ -6,7 +6,6 @@ Config['Period'] : allows to define period over witch to look for IOC from now ( import base64 import json -import re misperrors = {"error": "Error"} @@ -22,7 +21,6 @@ inputSource = ['event'] outputFileExtension = 'nxql' responseType = 'application/txt' - moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', 'description': 'Nexthink NXQL query export module', 'module-type': ['export']} @@ -36,6 +34,7 @@ def handle_sha1(value, period): ''' % (value, period) return query.replace('\n', ' ') + def handle_sha256(value, period): query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) (from (binary user device execution) @@ -45,6 +44,7 @@ def handle_sha256(value, period): ''' % (value, period) return query.replace('\n', ' ') + def handle_md5(value, period): query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) (from (binary user device execution) @@ -54,6 +54,7 @@ def handle_md5(value, period): ''' % (value, period) return query.replace('\n', ' ') + def handle_domain(value, period): query = '''select ((device name) (device (name last_ip_address)) (user name)(user department) (binary executable_name)(binary application_name)(binary description)(binary application_category)(binary (executable_name version)) (binary #"Suspicious binary")(binary first_seen)(binary last_seen)(binary threat_level)(binary hash) (binary paths) (destination name)(domain name) (domain domain_category)(domain hosting_country)(domain protocol)(domain threat_level) (port port_number)(web_request incoming_traffic)(web_request outgoing_traffic)) @@ -64,6 +65,7 @@ def handle_domain(value, period): ''' % (value, period) return query.replace('\n', ' ') + handlers = { 'sha1': handle_sha1, 'sha256': handle_sha256, @@ -86,6 +88,7 @@ def handler(q=False): r = {"response": [], "data": str(base64.b64encode(bytes(output, 'utf-8')), 'utf-8')} return r + def introspection(): modulesetup = {} try: @@ -110,6 +113,7 @@ def introspection(): pass return modulesetup + def version(): moduleinfo['config'] = moduleconfig return moduleinfo From 02cdc11445e62766b80b913dde4613dcf9fe3217 Mon Sep 17 00:00:00 2001 From: milkmix Date: Wed, 26 Dec 2018 08:33:21 +0100 Subject: [PATCH 6/6] added 2 blank lines to comply w/ pep8 --- misp_modules/modules/export_mod/nexthinkexport.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misp_modules/modules/export_mod/nexthinkexport.py b/misp_modules/modules/export_mod/nexthinkexport.py index 0123808..f1a0d79 100755 --- a/misp_modules/modules/export_mod/nexthinkexport.py +++ b/misp_modules/modules/export_mod/nexthinkexport.py @@ -25,6 +25,7 @@ moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', 'description': 'Nexthink NXQL query export module', 'module-type': ['export']} + def handle_sha1(value, period): query = '''select ((binary (executable_name version)) (user (name)) (device (name last_ip_address)) (execution (binary_path start_time))) (from (binary user device execution) @@ -73,6 +74,7 @@ handlers = { 'domain': handle_domain } + def handler(q=False): if q is False: return False