diff --git a/documentation/logos/defender_endpoing.png b/documentation/logos/defender_endpoing.png new file mode 100644 index 0000000..efc7ace Binary files /dev/null and b/documentation/logos/defender_endpoing.png differ diff --git a/documentation/website/export_mod/defender_endpoint_export.json b/documentation/website/export_mod/defender_endpoint_export.json new file mode 100644 index 0000000..ee45766 --- /dev/null +++ b/documentation/website/export_mod/defender_endpoint_export.json @@ -0,0 +1,11 @@ +{ + "description": "Defender for Endpoint KQL hunting query export module", + "requirements": [], + "features": "This module export an event as Defender for Endpoint KQL queries that can then be used in your own python3 or Powershell tool. If you are using Microsoft Sentinel, you can directly connect your MISP instance to Sentinel and then create queries using the `ThreatIntelligenceIndicator` table to match events against imported IOC.", + "references": [ + "https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/advanced-hunting-schema-reference" + ], + "input": "MISP Event attributes", + "output": "Defender for Endpoint KQL queries", + "logo": "defender_endpoint.png" +} \ No newline at end of file diff --git a/misp_modules/modules/export_mod/__init__.py b/misp_modules/modules/export_mod/__init__.py index 1b0e1d0..5b69d02 100644 --- a/misp_modules/modules/export_mod/__init__.py +++ b/misp_modules/modules/export_mod/__init__.py @@ -1,2 +1,2 @@ __all__ = ['cef_export', 'mass_eql_export', 'liteexport', 'goamlexport', 'threat_connect_export', 'pdfexport', - 'threatStream_misp_export', 'osqueryexport', 'nexthinkexport', 'vt_graph'] + 'threatStream_misp_export', 'osqueryexport', 'nexthinkexport', 'vt_graph', 'defender_endpoint_export'] diff --git a/misp_modules/modules/export_mod/defender_endpoint_export.py b/misp_modules/modules/export_mod/defender_endpoint_export.py new file mode 100755 index 0000000..eea929c --- /dev/null +++ b/misp_modules/modules/export_mod/defender_endpoint_export.py @@ -0,0 +1,102 @@ +""" +Export module for coverting MISP events into Defender for Endpoint KQL queries. +Config['Period'] : allows to define period over witch to look for IOC from now +""" + +import base64 +import json + +misperrors = {"error": "Error"} + +types_to_use = ['sha1', 'md5', 'domain', 'ip', 'url'] + +userConfig = { + +} + +moduleconfig = ["Period"] +inputSource = ['event'] + +outputFileExtension = 'kql' +responseType = 'application/txt' + +moduleinfo = {'version': '1.0', 'author': 'Julien Bachmann, Hacknowledge', + 'description': 'Defender for Endpoint KQL hunting query export module', + 'module-type': ['export']} + +def handle_sha1(value, period): + query = f"""find in (DeviceAlertEvents, DeviceFileEvents, DeviceImageLoadEvents, DeviceProcessEvents) + where SHA1 == '{value}' or InitiatingProcessSHA1 == '{value}'""" + return query.replace('\n', ' ') + +def handle_md5(value, period): + query = f"""find in (DeviceAlertEvents, DeviceFileEvents, DeviceImageLoadEvents, DeviceProcessEvents) + where MD5 == '{value}' or InitiatingProcessMD5 == '{value}'""" + return query.replace('\n', ' ') + +def handle_domain(value, period): + query = f"""find in (DeviceAlertEvents, DeviceNetworkEvents) + where RemoteUrl contains '{value}'""" + return query.replace('\n', ' ') + +def handle_ip(value, period): + query = f"""find in (DeviceAlertEvents, DeviceNetworkEvents) + where RemoteIP == '{value}'""" + return query.replace('\n', ' ') + +def handle_url(value, period): + query = f"""find in (DeviceAlertEvents, DeviceNetworkEvents) + where RemoteUrl startswith '{value}'""" + return query.replace('\n', ' ') + +handlers = { + 'sha1': handle_sha1, + 'md5': handle_md5, + 'domain': handle_domain, + 'ip': handle_ip, + 'url': handle_url +} + + +def handler(q=False): + if q is False: + return False + 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