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

NERD analyzer added

parent 9893dad1
Branches
No related tags found
No related merge requests found
# Cortex analyzers # Cortex analyzers
Custom Cortex analyzers and responders
{
"name": "NERD",
"version": "1.0",
"author": "Vaclav Bartos, CESNET",
"url": "TODO (not public yet)",
"license": "AGPL-V3",
"description": "Get Reputation score and other basic information from Network Entity Reputation Database (NERD)",
"dataTypeList": ["ip"],
"baseConfig": "NERD",
"command": "NERD/nerd_analyzer.py",
"configurationItems": [
{
"name": "key",
"description": "API key",
"type": "string",
"multi": false,
"required": true
},
{
"name": "url",
"description": "Base URL of the NERD instance",
"type": "string",
"multi": false,
"required": false,
"defaultValue": "https://nerd.cesnet.cz/nerd/"
}
]
}
\ No newline at end of file
#!/usr/bin/env python3
# encoding: utf-8
import requests
from cortexutils.analyzer import Analyzer
class NERDAnalyzer(Analyzer):
def __init__(self):
Analyzer.__init__(self)
self.base_url = self.get_param('config.url', None, 'Missing URL of NERD.')
if not self.base_url.endswith('/'):
self.base_url += '/'
self.api_key = self.get_param('config.key', None, 'Missing API key for NERD.')
def summary(self, raw):
"""Returns a summary, needed for 'short.html' template, based on the full report"""
taxonomies = []
if 'message' in raw:
# IP wasn't found
taxonomies.append(self.build_taxonomy('safe', 'NERD', 'Rep', 'no-data'))
else:
# Reputation score (set level/color according to the score)
rep = round(raw['rep'], 3)
rep_level = 'safe' if rep < 0.02 else ('suspicious' if rep <= 0.5 else 'malicious')
taxonomies.append(self.build_taxonomy(rep_level, 'NERD', 'Rep', rep))
# Number of blacklists
if raw['blacklists']:
taxonomies.append(self.build_taxonomy('malicious', 'NERD', 'Blacklists', len(raw['blacklists'])))
# Tags
for tag in raw['tags']:
# TODO: filter tags, set different levels
taxonomies.append(self.build_taxonomy('info', 'NERD', 'Tag', tag))
return {'taxonomies': taxonomies}
def artifacts(self, raw):
"""Returns a list of indicators extracted from reply (empty in this case)"""
return [] # TODO add hostname as a new indicator?
def run(self):
"""Main function run by Cortex to analyze an observable."""
print("RUN")
if self.data_type != 'ip':
self.error("Invalid data type, only IP addresses are supported")
return
ip = self.get_data()
print("ip:", ip)
# Get data from server
url = '{}api/v1/ip/{}'.format(self.base_url, ip)
headers = {'Authorization': self.api_key}
try:
resp = requests.get(url, headers=headers)
except Exception as e:
self.error("Error when trying to contact server: {}".format(e))
return
# Parse received data
try:
data = resp.json()
except ValueError:
self.error("Invalid response received from server.")
return
if resp.status_code == 404:
# IP not found in NERD's DB (i.e. it wasn't reported as malicious)
self.report({
'rep': 0.0,
'message': '{} not found in NERD, i.e. there are no recent reports of malicious activity.'.format(ip)
})
return
elif resp.status_code == 200:
# Success, IP data received - format as output for Cortex
try:
self.report({
'rep': data['rep'], # reputation score (number between 0.0 to 1.0)
'hostname': data['hostname'], # result of DNS PTR qeury
'asn': data['asn'], # list of ASNs announcing the IP (usually just one)
'country': data['geo']['ctry'], # Geolocation - two-letter country code
'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%)
})
except KeyError as e:
self.error("Invalid response received from server, missing field: {}".format(e))
else:
# Unexpected status code, there should be an 'error' field with error message
self.error("Error: {} {}".format(resp.status_code, data.get('error', '(no error message)')))
return
if __name__ == '__main__':
NERDAnalyzer().run()
requests
cortexutils
\ 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