-
Notifications
You must be signed in to change notification settings - Fork 385
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #448 from ottimo/develop
Maltiverse Analyzer
- Loading branch information
Showing
6 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ thehive-templates/*.sh | |
|
||
.idea | ||
.DS_Store | ||
.vscode | ||
|
||
Cortex-analyzers.iml | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"name": "Maltiverse_Report", | ||
"version": "1.0", | ||
"author": "ottimo", | ||
"url": "https://github.com/TheHive-Project/Cortex-Analyzers", | ||
"license": "AGPL-V3", | ||
"description": "Get the latest Maltiverse report for an hash, domain or an IP address.", | ||
"dataTypeList": ["hash", "domain", "ip", "url"], | ||
"command": "Maltiverse/maltiverse-client.py", | ||
"baseConfig": "Maltiverse", | ||
"config": { | ||
"service": "get" | ||
}, | ||
"configurationItems": [ | ||
{ | ||
"name": "polling_interval", | ||
"description": "Define time interval between two requests attempts for the report", | ||
"type": "number", | ||
"multi": false, | ||
"required": false, | ||
"defaultValue": 60 | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
import sys | ||
import time | ||
import hashlib | ||
import urllib | ||
|
||
from cortexutils.analyzer import Analyzer | ||
from maltiverse import Maltiverse | ||
|
||
class MaltiverseAnalyzer(Analyzer): | ||
|
||
def __init__(self): | ||
Analyzer.__init__(self) | ||
self.service = self.get_param('config.service', None, 'Service parameter is missing') | ||
# self.username = self.get_param('config.username', None, 'Missing Maltiverse API Username') | ||
# self.password = self.get_param('config.password', None, 'Missing Maltiverse API Password') | ||
self.polling_interval = self.get_param('config.polling_interval', 60) | ||
self.proxies = self.get_param('config.proxy', None) | ||
self.m = Maltiverse() | ||
|
||
def maltiverse_query_ip(self, data): | ||
try: | ||
result = self.m.ip_get(data) | ||
self.report({ | ||
'registrant_name': result.get("registrant_name","-"), | ||
'last_updated': result.get("last_updated","-"), | ||
'asn_registry': result.get("asn_registry","-"), | ||
'classification': result.get("classification","-"), | ||
'asn_country_code': result.get("asn_country_code","-"), | ||
'creation_time': result.get("creation_time","-"), | ||
'visits': result.get("visits","-"), | ||
'blacklist': result.get("blacklist","-"), | ||
'asn_date': result.get("asn_date","-"), | ||
'modification_time': result.get("modification_time","-"), | ||
'asn_cidr': result.get("asn_cidr","-"), | ||
'location': result.get("location","-"), | ||
'country_code': result.get("country_code","-"), | ||
'address': result.get("address","-"), | ||
'ip_addr': result.get("ip_addr","-"), | ||
'cidr': result.get("cidr","-"), | ||
'tag': result.get("tag","-"), | ||
'type': result.get("type","-"), | ||
'email': result.get("email","-") | ||
}) | ||
except Exception: | ||
self.error('API Error! Please verify data type is correct.') | ||
|
||
def maltiverse_query_domain(self, data): | ||
try: | ||
result = self.m.hostname_get(data) | ||
self.report({ | ||
'domain': result.get("domain","-"), | ||
'classification': result.get("classification","-"), | ||
'hostname': result.get("hostname","-"), | ||
'creation_time': result.get("creation_time","-"), | ||
'domain_lenght': result.get("domain_lenght","-"), | ||
'resolved_ip': result.get("resolved_ip","-"), | ||
'modification_time': result.get("modification_time","-"), | ||
'domain_consonants': result.get("domain_consonants","-"), | ||
'visits': result.get("visits","-"), | ||
'tld': result.get("tld","-"), | ||
'entropy': result.get("entropy","-"), | ||
'type': result.get("type","-"), | ||
'as_name': result.get("as_name","-") | ||
}) | ||
except Exception: | ||
self.error('API Error! Please verify data type is correct.') | ||
|
||
def maltiverse_query_file(self, data): | ||
try: | ||
result = self.m.sample_get(data) | ||
self.report(result) | ||
except Exception: | ||
self.error('API Error! Please verify data type is correct.') | ||
|
||
def maltiverse_query_url(self, data): | ||
# urlencode the URL that we are searching for | ||
#data = urllib.quote_plus(data) | ||
try: | ||
result = self.m.url_get(data) | ||
self.report({ | ||
'original': data, | ||
'hash': hash, | ||
'url': result.get("url","-"), | ||
'type': result.get("type","-"), | ||
'classification': result.get("classification","-"), | ||
'tag': result.get("tag","-"), | ||
'blacklist': result.get("blacklist","-"), | ||
'creation_time': result.get("creation_time","-"), | ||
'modification_time': result.get("modification_time","-") | ||
}) | ||
except: | ||
self.error('API Error! Please verify data type is correct.') | ||
|
||
def summary(self, raw): | ||
taxonomies = [] | ||
level = "info" | ||
namespace = "Maltiverse" | ||
predicate = "Report" | ||
value = "{}".format("n/a") | ||
if "classification" in raw: | ||
if raw["classification"] == "malicious": | ||
level = "malicious" | ||
elif raw["classification"] == "suspicious": | ||
level = "suspicious" | ||
else: | ||
level = "safe" | ||
value = "{}".format(raw["classification"]) | ||
|
||
|
||
taxonomies.append(self.build_taxonomy(level, namespace, predicate, value)) | ||
|
||
return {"taxonomies": taxonomies} | ||
|
||
def run(self): | ||
Analyzer.run(self) | ||
if self.data_type == 'file': | ||
hashes = self.get_param('attachment.hashes', None) | ||
if hashes is None: | ||
filepath = self.get_param('file', None, 'File is missing') | ||
sha256 = hashlib.sha256() | ||
with io.open(filepath, 'rb') as fh: | ||
while True: | ||
data = fh.read(4096) | ||
if not data: | ||
break | ||
sha256.update(data) | ||
hash = sha256.hexdigest() | ||
else: | ||
# find SHA256 hash | ||
hash = next(h for h in hashes if len(h) == 64) | ||
self.maltiverse_query_file(hash) | ||
elif self.data_type == 'url': | ||
data = self.get_param('data', None, 'Data is missing') | ||
self.maltiverse_query_url(data) | ||
elif self.data_type == 'domain': | ||
data = self.get_param('data', None, 'Data is missing') | ||
self.maltiverse_query_domain(data) | ||
elif self.data_type == 'ip': | ||
data = self.get_param('data', None, 'Data is missing') | ||
self.maltiverse_query_ip(data) | ||
elif self.data_type == 'hash': | ||
data = self.get_param('data', None, 'Data is missing') | ||
self.maltiverse_query_file(data) | ||
else: | ||
self.error('Invalid data type') | ||
|
||
if __name__ == '__main__': | ||
MaltiverseAnalyzer().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
cortexutils | ||
future | ||
requests | ||
git+https://github.com/maltiverse/python-maltiverse | ||
PyJWT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<div class="panel panel-danger" ng-if="!success"> | ||
<div class="panel-heading"> | ||
<strong>{{(artifact.data || artifact.attachment.name) | fang}}</strong> | ||
</div> | ||
<div class="panel-body"> | ||
{{content.errorMessage}} | ||
</div> | ||
</div> | ||
|
||
<div ng-if="success"> | ||
<div class="panel panel-info"> | ||
<div class="panel-heading"> | ||
Maltiverse record for "{{artifact.data}}"</a> | ||
<br/> | ||
<a target="_blank" href="https://www.maltiverse.com/{{content.type}}/{{artifact.data}}">view more on www.maltiverse.com</a> | ||
</div> | ||
<div class="panel-body"> | ||
<dl class="dl-horizontal" ng-if="content.classification"> | ||
<dt>Classification</dt> | ||
<dd class="wrap">{{content.classification}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.type"> | ||
<dt>Type</dt> | ||
<dd class="wrap">{{content.type}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.tag"> | ||
<dt>Tag</dt> | ||
<dd class="wrap"> | ||
<span class="label label-default" style="margin-right:1px" ng-repeat="tag in ::content.tag"> | ||
{{tag}} | ||
</span> | ||
</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.creation_time"> | ||
<dt>Creation Time</dt> | ||
<dd class="wrap">{{content.creation_time}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.modification_time"> | ||
<dt>Modification Time</dt> | ||
<dd class="wrap">{{content.modification_time}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.subdomains"> | ||
<dt>Sub domains</dt> | ||
<dd class="wrap">{{content.subdomains.join(', ')}}</dd> | ||
</dl> | ||
|
||
<dl class="dl-horizontal" ng-if="content.filetype"> | ||
<dt>File Type</dt> | ||
<dd class="wrap">{{content.filetype}}</dd> | ||
</dl> | ||
|
||
<dl class="dl-horizontal" ng-if="content.score"> | ||
<dt>Score</dt> | ||
<dd class="wrap">{{content.score}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.resolved_ip && content.resolved_ip.length > 0"> | ||
<dt>Resolutions</dt> | ||
<dd> | ||
<div ng-if="::artifact.dataType === 'domain'"> | ||
<strong>This domain has been seen to resolve to the following IP addresses.</strong> | ||
</div> | ||
<div ng-repeat="resolution in ::content.resolved_ip | limitTo:20"> | ||
<p class="text-danger wrap">{{(resolution.ip_addr | fang)}}</p> | ||
</div> | ||
</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="content.filename && content.filename.length > 0"> | ||
<dt>File names</dt> | ||
<dd> | ||
<div ng-if="::artifact.dataType === 'domain'"> | ||
<strong>This sample has been seen with the following filename.</strong> | ||
</div> | ||
<div ng-repeat="name in ::content.filename | limitTo:20"> | ||
<p class="text-danger wrap">{{(name | fang)}}</p> | ||
</div> | ||
</dd> | ||
</dl> | ||
</div> | ||
</div> | ||
|
||
|
||
|
||
<div class="panel panel-info" ng-if="::content.blacklist" ng-init="blacklists_limit = 5"> | ||
<div class="panel-heading"> | ||
<strong>Blacklists</strong> | ||
<span class="pull-right" ng-show="::content.blacklist.length > 5"> | ||
<a href ng-show="blacklists_limit===5" ng-click="blacklists_limit = undefined">Show All ({{::content.blacklist.length}})</a> | ||
<a href ng-show="!blacklists_limit"ng-click="blacklists_limit = 5">Show less</a> | ||
</span> | ||
</div> | ||
|
||
<div class="panel-body"> | ||
<p>The observable is present in the following blacklists: | ||
</p> | ||
<table class="table table-hover"> | ||
<tr> | ||
<th>Source</th> | ||
<th>Description</th> | ||
<th>First seen</th> | ||
<th>Last seen</th> | ||
</tr> | ||
<tr ng-repeat="bl in content.blacklist | limitTo:blacklists_limit"> | ||
<td>{{bl.source}}</td> | ||
<td>{{bl.description}}</td> | ||
<td>{{bl.first_seen}}</td> | ||
<td>{{bl.last_seen}}</td> | ||
</tr> | ||
</table> | ||
</div> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |