From 677641786fab7769398f2d80a755b5603aea3942 Mon Sep 17 00:00:00 2001 From: Xavier Mertens Date: Tue, 10 Jul 2018 09:23:47 +0200 Subject: [PATCH 1/2] Created --- analyzers/DShield/DShield_lookup.json | 14 +++ analyzers/DShield/DShield_lookup.py | 89 +++++++++++++++ .../DShield/DShield_lookup.report_template | 104 ++++++++++++++++++ analyzers/DShield/requirements.txt | 2 + 4 files changed, 209 insertions(+) create mode 100644 analyzers/DShield/DShield_lookup.json create mode 100755 analyzers/DShield/DShield_lookup.py create mode 100644 analyzers/DShield/DShield_lookup.report_template create mode 100644 analyzers/DShield/requirements.txt diff --git a/analyzers/DShield/DShield_lookup.json b/analyzers/DShield/DShield_lookup.json new file mode 100644 index 000000000..016ba4e93 --- /dev/null +++ b/analyzers/DShield/DShield_lookup.json @@ -0,0 +1,14 @@ +{ + "name": "DShield_lookup", + "version": "1.0", + "author": "Xavier Xavier, SANS ISC", + "url": "https://github.com/xme/thehive/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Query the SANS ISC DShield API to check for an IP address reputation.", + "dataTypeList": ["ip"], + "command": "DShield/DShield_lookup.py", + "baseConfig": "DShield", + "config": { + "service": "query" + } +} diff --git a/analyzers/DShield/DShield_lookup.py b/analyzers/DShield/DShield_lookup.py new file mode 100755 index 000000000..2f97c31ae --- /dev/null +++ b/analyzers/DShield/DShield_lookup.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# encoding: utf-8 +import json +import requests +import datetime +from cortexutils.analyzer import Analyzer + +class DShieldAnalyzer(Analyzer): + def __init__(self): + Analyzer.__init__(self) + + def dshield_checkip(self, data): + url = 'https://isc.sans.edu/api/ip/%s?json' % data + r = requests.get(url) + return json.loads(r.text) + + def summary(self, raw): + taxonomies = [] + value = '-' + level = 'safe' + + categories = raw.get("Categories", None) + blacklists = raw.get("Blacklists", None) + num_categories = raw.get("Categories Identifier", None) + + if 'maxrisk' in raw: + if 'threatfeedscount' in raw: + r = int(raw['maxrisk']) + raw['threatfeedscount'] + else: + r = int(raw['maxrisk']) + if r <= 1: + level = 'safe' + elif r <= 6: + level = 'suspicious' + else: + level = 'malicious' + + value = "\"{} count(s) / {} attack(s) / {} threatfeed(s)\"".format(raw['count'], raw['attacks'], raw['threatfeedscount']) + + taxonomies.append(self.build_taxonomy(level, "DShield", "Score", value)) + return {"taxonomies": taxonomies} + + def get_reputation(self, risk): + if risk <= 1: + return("Safe") + elif risk <= 6: + return("Suspicious") + else: + return("Malicious") + + def run(self): + if self.data_type == 'ip': + data = self.get_param('data', None, 'Data is missing') + r = self.dshield_checkip(data) + # Do we get valid results + if self.data_type in r.keys(): + info = r[self.data_type] + results = {} + results['ip'] = info['number'] + results['count'] = info['count'] if isinstance(info['count'], str) else '0' + results['attacks'] = info['attacks'] if isinstance(info['attacks'], str) else '0' + results['lastseen'] = info['maxdate'] if isinstance(info['maxdate'], str) else 'None' + results['firstseen'] = info['mindate'] if isinstance(info['mindate'], str) else 'None' + results['updated'] = info['updated'] if isinstance(info['updated'], str) else 'None' + results['comment'] = info['comment'] if isinstance(info['comment'], str) else 'None' + results['maxrisk'] = info['maxrisk'] if isinstance(info['maxrisk'], str) else '0' + results['asabusecontact'] = info['asabusecontact'] if isinstance(info['asabusecontact'], str) else 'Unknown' + results['as'] = info['as'] + results['asname'] = info['asname'] + results['ascountry'] = info['ascountry'] + results['assize'] = info['assize'] + results['network'] = info['network'] + results['threatfeedscount'] = 0 + if 'threatfeeds' not in info: + results['threatfeeds'] = '' + else: + results['threatfeedscount'] = len(json.loads(json.dumps(info['threatfeeds']))) + results['threatfeeds'] = info['threatfeeds'] + # We add the number of threat feeds to the maxrisk to increase the detection rate + results['reputation'] = self.get_reputation(int(results['maxrisk']) + results['threatfeedscount']) + self.report(results) + else: + self.error('No data found') + else: + self.error('Invalid data type') + + +if __name__ == '__main__': + DShieldAnalyzer().run() diff --git a/analyzers/DShield/DShield_lookup.report_template b/analyzers/DShield/DShield_lookup.report_template new file mode 100644 index 000000000..2e634feed --- /dev/null +++ b/analyzers/DShield/DShield_lookup.report_template @@ -0,0 +1,104 @@ +
+ + +
+
+ DShield IP Reputation Summary +
+
+
+ No records found +
+
+
+
IP:
+
{{content.ip|| "-"}}
+
+
+
Reputation:
+
{{content.reputation || "-"}}
+
+
+
Network:
+
{{content.network || "-"}}
+
+
+
AS:
+
{{content.as || "-"}}
+
+
+
AS Name:
+
{{content.asname || "-"}}
+
+
+
AS Country:
+
{{content.ascountry || "-"}}
+
+
+
AS Abuse Contact:
+
{{content.asabusecontact || "-"}}
+
+
+
Number of Attacks:
+
{{content.count || "-"}}
+
+
+
Unique Attacked Hosts:
+
{{content.attacks || "-"}}
+
+
+
First Reported Attack:
+
{{content.firstseen || "-"}}
+
+
+
Last Reported Attacks:
+
{{content.lastseen || "-"}}
+
+
+
Risk Level:
+
{{content.maxrisk || "-"}}
+
+
+
Comment:
+
{{content.comment || "-"}}
+
+
+
Threat Feeds:
+
{{content.threatfeedscount || "-"}}
+
+
+
+
+ +
+
+ Threat Feeds +
+
+
+ No threat feed found +
+
+
+
{{key}}
+
First Seen: {{value.firstseen || "-"}}
+
Last Seen: {{value.lastseen || "-"}}
+
+
+
+
+ + +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
diff --git a/analyzers/DShield/requirements.txt b/analyzers/DShield/requirements.txt new file mode 100644 index 000000000..e1b12824b --- /dev/null +++ b/analyzers/DShield/requirements.txt @@ -0,0 +1,2 @@ +cortexutils +urllib2 From ce2bb58844dd6d7f04d6f16983aeac62efeb32aa Mon Sep 17 00:00:00 2001 From: Xavier Mertens Date: Wed, 18 Jul 2018 22:28:31 -0400 Subject: [PATCH 2/2] Bug fix + compute maxrisk --- analyzers/DShield/DShield_lookup.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/analyzers/DShield/DShield_lookup.py b/analyzers/DShield/DShield_lookup.py index 2f97c31ae..7cea21c17 100755 --- a/analyzers/DShield/DShield_lookup.py +++ b/analyzers/DShield/DShield_lookup.py @@ -3,6 +3,7 @@ import json import requests import datetime +import math from cortexutils.analyzer import Analyzer class DShieldAnalyzer(Analyzer): @@ -16,7 +17,7 @@ def dshield_checkip(self, data): def summary(self, raw): taxonomies = [] - value = '-' + value = "-" level = 'safe' categories = raw.get("Categories", None) @@ -57,13 +58,12 @@ def run(self): info = r[self.data_type] results = {} results['ip'] = info['number'] - results['count'] = info['count'] if isinstance(info['count'], str) else '0' - results['attacks'] = info['attacks'] if isinstance(info['attacks'], str) else '0' + results['count'] = info['count'] if isinstance(info['count'], int) else 0 + results['attacks'] = info['attacks'] if isinstance(info['attacks'], int) else 0 results['lastseen'] = info['maxdate'] if isinstance(info['maxdate'], str) else 'None' results['firstseen'] = info['mindate'] if isinstance(info['mindate'], str) else 'None' results['updated'] = info['updated'] if isinstance(info['updated'], str) else 'None' results['comment'] = info['comment'] if isinstance(info['comment'], str) else 'None' - results['maxrisk'] = info['maxrisk'] if isinstance(info['maxrisk'], str) else '0' results['asabusecontact'] = info['asabusecontact'] if isinstance(info['asabusecontact'], str) else 'Unknown' results['as'] = info['as'] results['asname'] = info['asname'] @@ -76,6 +76,12 @@ def run(self): else: results['threatfeedscount'] = len(json.loads(json.dumps(info['threatfeeds']))) results['threatfeeds'] = info['threatfeeds'] + # Compute a risk level based on collected information + results['maxrisk'] = 0 + maxrisk = 10 + if results['attacks'] > 0: + results['maxrisk'] = round(min(math.log10(results['attacks']) * 2, maxrisk)) + # We add the number of threat feeds to the maxrisk to increase the detection rate results['reputation'] = self.get_reputation(int(results['maxrisk']) + results['threatfeedscount']) self.report(results)