diff --git a/analyzers/Mimecast/Mimecast_Decode_URL.json b/analyzers/Mimecast/Mimecast_Decode_URL.json new file mode 100644 index 000000000..7702df62e --- /dev/null +++ b/analyzers/Mimecast/Mimecast_Decode_URL.json @@ -0,0 +1,56 @@ +{ + "name": "Mimecast_Decode_URL", + "version": "0.3", + "author": "Jared Jennings ", + "license": "AGPL-V3", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "description": "Decode Mimecast-protected URLs from emails", + "dataTypeList": ["url"], + "command": "Mimecast/mimecast_analyzer.py", + "baseConfig": "Mimecast API", + "config": { + "service": "decode_url", + "max_tlp": 2, + "check_tlp": true, + "max_pap": 2, + "check_pap": true + }, + "configurationItems": [ + { + "name": "base_url", + "description": "Base URL", + "type": "string", + "multi": false, + "required": true, + "defaultValue": "https://us-api.mimecast.com" + }, + { + "name": "app_id", + "description": "Application ID, a GUID", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "app_key", + "description": "App key, a GUID", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "access_key", + "description": "Access key, some Base64 text", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "secret_key", + "description": "Secret key, some Base64 text", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/analyzers/Mimecast/Mimecast_Recent_Recipients_From.json b/analyzers/Mimecast/Mimecast_Recent_Recipients_From.json new file mode 100644 index 000000000..6555e0c13 --- /dev/null +++ b/analyzers/Mimecast/Mimecast_Recent_Recipients_From.json @@ -0,0 +1,63 @@ +{ + "name": "Mimecast_Recent_Recipients_From", + "version": "0.3", + "author": "Jared Jennings ", + "license": "AGPL-V3", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "description": "Find out who received an email message from an address recently", + "dataTypeList": ["mail"], + "command": "Mimecast/mimecast_analyzer.py", + "baseConfig": "Mimecast API", + "config": { + "service": "list_recent_recipients_from", + "max_tlp": 2, + "check_tlp": true, + "max_pap": 2, + "check_pap": true + }, + "configurationItems": [ + { + "name": "base_url", + "description": "Base URL", + "type": "string", + "multi": false, + "required": true, + "defaultValue": "https://us-api.mimecast.com" + }, + { + "name": "app_id", + "description": "Application ID, a GUID", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "app_key", + "description": "App key, a GUID", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "access_key", + "description": "Access key, some Base64 text", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "secret_key", + "description": "Secret key, some Base64 text", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "find_messages_since_days_ago", + "description": "Number of days to reach back into the past for messages", + "type": "number", + "required": false, + "defaultValue": 2 + } + ] +} diff --git a/analyzers/Mimecast/mimecast_analyzer.py b/analyzers/Mimecast/mimecast_analyzer.py new file mode 100755 index 000000000..cbcd938a9 --- /dev/null +++ b/analyzers/Mimecast/mimecast_analyzer.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +from urllib.parse import urlsplit +from mimecast_api import MimecastAPI, URLDecodeFail +from cortexutils.analyzer import Analyzer + +class MimecastAnalyzer(Analyzer): + def __init__(self): + super().__init__() + self.service = self.get_param('config.service', None, + 'Service parameter is missing') + mimecast_config = { + 'base_url': self.get_param('config.base_url', None, + 'Mimecast API base URL is missing'), + 'app_id': self.get_param('config.app_id', None, + 'App ID is missing'), + 'app_key': self.get_param('config.app_key', None, + 'App key is missing'), + 'access_key': self.get_param('config.access_key', None, + 'Access key is missing'), + 'secret_key': self.get_param('config.secret_key', None, + 'Secret key is missing'), + } + self.mimecast_api = MimecastAPI(**mimecast_config) + + def _looks_like_mimecast_protected_url(self, url): + pieces = urlsplit(url) + return (pieces.scheme == 'https' and + pieces.netloc.startswith('protect-') and + pieces.netloc.endswith('.mimecast.com')) + + def artifacts(self, raw): + if self.service == 'decode_url': + if 'decoded_url' in raw: + return [{'type': 'url', 'value': raw['decoded_url']}] + else: + return [] + elif self.service == 'list_recent_recipients_from': + if 'recipients' in raw: + return [self.build_artifact('mail', recipient_address, + tags=['recipient']) + for recipient_address in raw['recipients']] + else: + return [] + else: + return [] + + + def summary(self, raw): + if self.service == 'decode_url': + if 'decoded_url' in raw: + # it was a URL Protect URL + return {'taxonomies': [ + self.build_taxonomy('info', 'MC', 'URLProtect', 'True')]} + else: + return {} + elif self.service == 'list_recent_recipients_from': + if 'recipients' in raw: + return {'taxonomies': [ + self.build_taxonomy('info', 'MC', 'MessagesSentToUs', + len(raw['recipients']))]} + else: + return {} + else: + return {} + + def run(self): + super().run() + try: + if self.data_type == 'url': + url = self.get_data() + if self.service == 'decode_url': + if self._looks_like_mimecast_protected_url(url): + try: + decoded = self.mimecast_api.decode_url(url) + self.report({"decoded_url": decoded}) + except URLDecodeFail as e: + self.report({"undecodable": repr(e)}) + else: + self.report({"invalid": + "does not look like a Mimecast-protected URL"}) + else: + self.notSupported() + elif self.data_type == 'mail': + email_address = self.get_data() + if self.service == 'list_recent_recipients_from': + since_days_ago = self.get_param( + 'config.find_messages_since_days_ago', 2, + 'find_messages_since_days_ago parameter is missing') + recipients = self.mimecast_api.list_recent_recipients_from( + email_address, since_days_ago) + self.report({"recipients": recipients}) + else: + self.notSupported() + except Exception as e: + self.unexpectedError("Unhandled exception: " + repr(e)) + + +if __name__ == '__main__': + MimecastAnalyzer().run() diff --git a/analyzers/Mimecast/requirements.txt b/analyzers/Mimecast/requirements.txt new file mode 100644 index 000000000..ff6b8fee6 --- /dev/null +++ b/analyzers/Mimecast/requirements.txt @@ -0,0 +1,6 @@ +certifi==2020.4.5.1 +chardet==3.0.4 +idna==2.9 +requests==2.23.0 +urllib3==1.25.9 +mimecast-api==0.3 diff --git a/thehive-templates/Mimecast_Decode_URL_0.3/long.html b/thehive-templates/Mimecast_Decode_URL_0.3/long.html new file mode 100644 index 000000000..b98932f1d --- /dev/null +++ b/thehive-templates/Mimecast_Decode_URL_0.3/long.html @@ -0,0 +1,32 @@ +
+
+ URL decode result +
+
+
+ Original URL: {{artifact.data | fang}} +
+

+ {{ content.invalid }} +

+

+

{{ content.undecodable }}
+

+

+ Decoded result: {{content.decoded_url | fang}} +

+
+
+ +
+
+ Error in decoding +
+
+
+ Original URL: {{artifact.data | fang}} +
+ {{content.errorMessage}} +
+
+ diff --git a/thehive-templates/Mimecast_Decode_URL_0.3/short.html b/thehive-templates/Mimecast_Decode_URL_0.3/short.html new file mode 100644 index 000000000..57f9d29cf --- /dev/null +++ b/thehive-templates/Mimecast_Decode_URL_0.3/short.html @@ -0,0 +1,3 @@ + + {{t.namespace}}:{{t.predicate}}={{t.value}} +