Skip to content

Mimecast analyzer #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions analyzers/Mimecast/Mimecast_Decode_URL.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "Mimecast_Decode_URL",
"version": "0.3",
"author": "Jared Jennings <jjennings@fastmail.fm>",
"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
}
]
}
63 changes: 63 additions & 0 deletions analyzers/Mimecast/Mimecast_Recent_Recipients_From.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "Mimecast_Recent_Recipients_From",
"version": "0.3",
"author": "Jared Jennings <jjennings@fastmail.fm>",
"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
}
]
}
100 changes: 100 additions & 0 deletions analyzers/Mimecast/mimecast_analyzer.py
Original file line number Diff line number Diff line change
@@ -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()
6 changes: 6 additions & 0 deletions analyzers/Mimecast/requirements.txt
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions thehive-templates/Mimecast_Decode_URL_0.3/long.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="panel panel-info" ng-if="success">
<div class="panel-heading">
URL decode result
</div>
<div class="panel-body">
<div>
Original URL: <strong>{{artifact.data | fang}}</strong>
</div>
<p ng-if="content.invalid">
{{ content.invalid }}
</p>
<p ng-if="content.undecodable">
<pre>{{ content.undecodable }}</pre>
</p>
<p ng-if="content.decoded_url">
Decoded result: <strong>{{content.decoded_url | fang}}</strong>
</p>
</div>
</div>

<div class="panel panel-danger" ng-if="!success">
<div class="panel-heading">
Error in decoding
</div>
<div class="panel-body">
<div>
Original URL: <strong>{{artifact.data | fang}}</strong>
</div>
{{content.errorMessage}}
</div>
</div>

3 changes: 3 additions & 0 deletions thehive-templates/Mimecast_Decode_URL_0.3/short.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<span class="label" ng-repeat="t in content.taxonomies" ng-class="{'info': 'label-info', 'safe': 'label-success', 'suspicious': 'label-warning', 'malicious':'label-danger'}[t.level]">
{{t.namespace}}:{{t.predicate}}={{t.value}}
</span>