Skip to content
Snippets Groups Projects
Commit 8432a89e authored by Václav Bartoš's avatar Václav Bartoš
Browse files

NERD: Templates added

+ some related changes in the analyzer itself
parent a6fd60ee
No related branches found
No related tags found
No related merge requests found
...@@ -25,10 +25,10 @@ tag_map = { ...@@ -25,10 +25,10 @@ tag_map = {
class NERDAnalyzer(Analyzer): class NERDAnalyzer(Analyzer):
def __init__(self): def __init__(self):
Analyzer.__init__(self) Analyzer.__init__(self)
self.base_url = self.get_param('config.url', None, 'Missing URL of NERD.') self.base_url = self.get_param('config.url', None, 'Config error: Missing URL of NERD.')
if not self.base_url.endswith('/'): if not self.base_url.endswith('/'):
self.base_url += '/' self.base_url += '/'
self.api_key = self.get_param('config.key', None, 'Missing API key for NERD.') self.api_key = self.get_param('config.key', None, 'Config error: Missing API key for NERD.')
def summary(self, raw): def summary(self, raw):
"""Returns a summary, needed for 'short.html' template, based on the full report""" """Returns a summary, needed for 'short.html' template, based on the full report"""
...@@ -48,11 +48,7 @@ class NERDAnalyzer(Analyzer): ...@@ -48,11 +48,7 @@ class NERDAnalyzer(Analyzer):
taxonomies.append(self.build_taxonomy('malicious', 'NERD', 'Blacklists', len(raw['blacklists']))) taxonomies.append(self.build_taxonomy('malicious', 'NERD', 'Blacklists', len(raw['blacklists'])))
# Tags # Tags
for tag in raw['tags']: for tag_name,level in raw['translated_tags']:
try:
tag_name, level = tag_map[tag]
except KeyError:
continue
taxonomies.append(self.build_taxonomy(level, 'NERD', 'Tag', tag_name)) taxonomies.append(self.build_taxonomy(level, 'NERD', 'Tag', tag_name))
return {'taxonomies': taxonomies} return {'taxonomies': taxonomies}
...@@ -65,12 +61,10 @@ class NERDAnalyzer(Analyzer): ...@@ -65,12 +61,10 @@ class NERDAnalyzer(Analyzer):
def run(self): def run(self):
"""Main function run by Cortex to analyze an observable.""" """Main function run by Cortex to analyze an observable."""
print("RUN")
if self.data_type != 'ip': if self.data_type != 'ip':
self.error("Invalid data type, only IP addresses are supported") self.error("Invalid data type, only IP addresses are supported")
return return
ip = self.get_data() ip = self.get_data()
print("ip:", ip)
# Get data from server # Get data from server
url = '{}api/v1/ip/{}'.format(self.base_url, ip) url = '{}api/v1/ip/{}'.format(self.base_url, ip)
...@@ -85,26 +79,39 @@ class NERDAnalyzer(Analyzer): ...@@ -85,26 +79,39 @@ class NERDAnalyzer(Analyzer):
try: try:
data = resp.json() data = resp.json()
except ValueError: except ValueError:
self.error("Invalid response received from server.") self.error("Unexpected or invalid response received from server (can't parse as JSON). A possible reason can be wrong URL.")
return return
if resp.status_code == 404: if resp.status_code == 404:
# IP not found in NERD's DB (i.e. it wasn't reported as malicious) # IP not found in NERD's DB (i.e. it wasn't reported as malicious)
self.report({ self.report({
'rep': 0.0, 'rep': 0.0,
'message': '{} not found in NERD, i.e. there are no recent reports of malicious activity.'.format(ip) 'message': '{} not found in NERD, i.e. there are no recent reports of malicious activity.'.format(ip),
'nerd_url': '{}ip/{}'.format(self.base_url, ip), # Link to IP's page at NERD web
}) })
return return
elif resp.status_code == 200: elif resp.status_code == 200:
# Success, IP data received - format as output for Cortex # Success, IP data received - format as output for Cortex
try: try:
# Translate tags
translated_tags = []
tag_ids = [t['n'] for t in data['tags'] if t.get('c', 1.0) >= 0.5] # List of tags with confidence >= 50%
for tag in tag_ids:
try:
tag_name, level = tag_map[tag]
except KeyError:
continue
translated_tags.append([tag_name, level])
# Create report
self.report({ self.report({
'rep': data['rep'], # reputation score (number between 0.0 to 1.0) 'rep': data['rep'], # reputation score (number between 0.0 to 1.0)
'hostname': data['hostname'], # result of DNS PTR qeury 'hostname': data['hostname'], # result of DNS PTR qeury
'asn': data['asn'], # list of ASNs announcing the IP (usually just one) 'asn': data['asn'], # list of ASNs announcing the IP (usually just one)
'country': data['geo']['ctry'], # Geolocation - two-letter country code 'country': data['geo'].get('ctry', ''), # Geolocation - two-letter country code
'blacklists': data['bl'], # List of blacklists the IP is listed on 'blacklists': data['bl'], # List of blacklists the IP is listed on
'tags': [t['n'] for t in data['tags'] if t.get('c', 1.0) >= 0.5] # List of tags (with confidence >= 50%) 'tags': tag_ids, # Original Tags as in NERD
'translated_tags': translated_tags, # Tags filtered and translated to nicer names
'nerd_url': '{}ip/{}'.format(self.base_url, ip), # Link to IP's page at NERD web
}) })
except KeyError as e: except KeyError as e:
self.error("Invalid response received from server, missing field: {}".format(e)) self.error("Invalid response received from server, missing field: {}".format(e))
......
<div class="panel panel-info" ng-if="success">
<div class="panel-heading">
NERD information for <strong>{{artifact.data}}</strong>
</div>
<div class="panel-body" ng-if="content.message">
<p>{{content.message}}</p>
<p>Current info at: <a href="{{content.nerd_url}}" target="_blank">{{content.nerd_url}}</a></p>
</div>
<div class="panel-body" ng-if="!content.message">
<dl class="dl-horizontal">
<dt class="text-bold">
Reputation score
<sup style="color: #999" title="A score computed from the number of recent alerts, their age, and the number of distinct sources (0.0 = no alerts, 1.0 = lots of alerts from multiple sources)">(?)</sup>
</dt>
<dd><span style="color: hsl({{ (100 - 100*content.rep | number: 2) }}, 85%, 50%); margin-right: 5px">&#x2B24;</span>{{content.rep | number: 3}}</dd>
</dl>
<dl class="dl-horizontal">
<dt class="text-bold">Hostname</dt>
<dd>{{content.hostname || "&mdash;"}}</dd>
</dl>
<dl class="dl-horizontal">
<dt class="text-bold">Blacklists</dt>
<dd>{{content.blacklists.join(", ") || "&mdash;"}}</dd>
</dl>
<dl class="dl-horizontal">
<dt class="text-bold">Tags</dt>
<dd>
<span ng-repeat="t in content.translated_tags" class="label" style="margin-right: 5px" ng-class="{'info': 'label-info', 'safe': 'label-success', 'suspicious': 'label-warning', 'malicious':'label-danger'}[t[1]]">{{t[0]}}</span>
<span ng-if="!content.translated_tags.length">&mdash;</span>
</dd>
</dl>
<dl class="dl-horizontal">
<dt class="text-bold">ASN</dt>
<dd>{{content.asn.join(", ") || "unknown"}}</dd>
</dl>
<dl class="dl-horizontal">
<dt class="text-bold">Country</dt>
<dd>{{content.country || "unknown"}}</dd>
</dl>
<p>Full info at: <a href="{{content.nerd_url}}" target="_blank">{{content.nerd_url}}</a></p>
</div>
</div>
<!-- General error -->
<div class="panel panel-danger" ng-if="!success">
<div class="panel-heading">
<strong>{{artifact.data}}</strong>
</div>
<div class="panel-body">
{{content.errorMessage}}
</div>
</div>
\ No newline at end of file
<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>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment