diff --git a/AUTHORS b/AUTHORS index f7c132919..35a0aad6c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,21 +13,27 @@ Contributors * Nils Kuhnert * CERT Banque de France (CERT-BDF) +* Rémi Allain +* Mehdy Aschy +* Davide Arcuri (LDO-CERT) * Adrien Barchapt -* Andrea Garavaglia (LDO-CERT) +* Pierre Baudry * Antoine Brodin -* Arcuri Davide (LDO-CERT) -* Daniil Yugoslavskiy Tieto -* Emmanuel Torquato -* etz69 * Eric Capuano -* Guillaume Rousse +* crackytsi +* Marc-André Doll (Starc, by EXAPROBE) +* etz69 +* Andrea Garavaglia (LDO-CERT) * Julian Gonzalez -* Marc-André oll Starc (EXAPROBE) -* Mehdy Aschy -* Pierre Baudry -* Sebastien Larinier -* Réii Pointel +* Sébastien Larinier +* Nclose +* Robert Nixon +* ph34tur3 +* Rémi Pointel +* Guillaume Rousse +* Michael Stensrud +* Emmanuel Torquato +* Daniil Yugoslavskiy Copyright (C) 2017-2018 Nabil Adouani Copyright (C) 2014-2018 Thomas Franco diff --git a/analyzers/Hashdd/Hashdd.py b/analyzers/Hashdd/Hashdd.py new file mode 100755 index 000000000..d570919dd --- /dev/null +++ b/analyzers/Hashdd/Hashdd.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# encoding: utf-8 +import requests +from cortexutils.analyzer import Analyzer + +class HashddAnalyzer(Analyzer): + + service = 'Status' + url = 'https://api.hashdd.com/' + hashdd_key = None + + def __init__(self): + Analyzer.__init__(self) + self.service = self.get_param('config.service', None, 'Service parameter is missing') + + if self.service == "status": + self.url = 'https://api.hashdd.com/' + elif self.service == "detail": + self.hashdd_key = self.get_param('config.api_key', None, 'Missing hashdd API key') + self.url = 'https://api.hashdd.com/detail' + + + def hashdd_check(self, data): + if self.hashdd_key is None: + postdata = {'hash': self.get_data()} + else: + postdata = {'hash': self.get_data(), 'api_key': self.hashdd_key} + + r = requests.post(self.url, data=postdata) + r.raise_for_status() # Raise exception on HTTP errors + return r.json() + + + def summary(self, raw): + + taxonomies = [] + namespace = 'Hashdd' + predicate = 'known_level' + value = "\0\"" + + level = 'info' # Default level: this assigned when known_level is unknown + + if 'known_level' in raw: + known_level = raw['known_level'] + if known_level == 'Good': + level = "safe" + elif known_level == 'Bad': + level = "malicious" + # else: + # level = "suspicious" # this one is not used + + value = "\"{}\"".format(known_level) # Value must be enclosed with double quotes + + taxonomies.append(self.build_taxonomy(level, namespace, predicate, value)) + + return {"taxonomies": taxonomies} + + + def run(self): + + if self.data_type != 'hash': + self.notSupported() + + data = self.get_param('data', None, 'Data is missing') + hash = data.upper() + + response = self.hashdd_check(data) + + if response['result'] == 'SUCCESS': + + if self.service == "status": + self.report({ + 'known_level': response[hash]['known_level'] + }) + elif self.service == "detail": + self.report({ + 'known_level': response[hash]['summary']['hashdd_known_level'], + 'file_name': response[hash]['summary']['hashdd_file_name'], + 'file_absolute_path': response[hash]['summary']['hashdd_file_absolute_path'], + 'size': response[hash]['summary']['hashdd_size'], + 'product_manufacturer': response[hash]['summary']['hashdd_product_manufacturer'], + 'product_name': response[hash]['summary']['hashdd_product_name'], + 'product_version': response[hash]['summary']['hashdd_product_version'], + 'architecture': response[hash]['summary']['hashdd_architecture'], + 'md5': response[hash]['summary']['hashdd_md5'], + 'sha1': response[hash]['summary']['hashdd_sha1'], + 'sha256': response[hash]['summary']['hashdd_sha256'], + 'ssdeep': response[hash]['summary']['hashdd_ssdeep'] + }) + else: + self.error('{}'.format(response['result'])) + + +if __name__ == '__main__': + HashddAnalyzer().run() diff --git a/analyzers/Hashdd/Hashdd_Detail.json b/analyzers/Hashdd/Hashdd_Detail.json new file mode 100644 index 000000000..34521d56a --- /dev/null +++ b/analyzers/Hashdd/Hashdd_Detail.json @@ -0,0 +1,23 @@ +{ + "name": "Hashdd_Detail", + "version": "1.0", + "author": "iosonogio", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPLv3", + "description": "Determine whether a hash is good or bad; if good then list what it is.", + "dataTypeList": ["hash"], + "baseConfig": "Hashdd", + "config": { + "service": "detail" + }, + "command": "Hashdd/Hashdd.py", + "configurationItems": [ + { + "name": "api_key", + "description": "API key for hashdd", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/analyzers/Hashdd/Hashdd_Status.json b/analyzers/Hashdd/Hashdd_Status.json new file mode 100644 index 000000000..104a6564c --- /dev/null +++ b/analyzers/Hashdd/Hashdd_Status.json @@ -0,0 +1,23 @@ +{ + "name": "Hashdd_Status", + "version": "1.0", + "author": "iosonogio", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPLv3", + "description": "Determine whether a hash is good or bad.", + "dataTypeList": ["hash"], + "baseConfig": "Hashdd", + "config": { + "service": "status" + }, + "command": "Hashdd/Hashdd.py", + "configurationItems": [ + { + "name": "api_key", + "description": "API key for hashdd", + "type": "string", + "multi": false, + "required": false + } + ] +} diff --git a/analyzers/Hashdd/requirements.txt b/analyzers/Hashdd/requirements.txt new file mode 100644 index 000000000..2cac23c03 --- /dev/null +++ b/analyzers/Hashdd/requirements.txt @@ -0,0 +1,2 @@ +requests +cortexutils diff --git a/images/cortex-main.png b/images/cortex-main.png index 90bfcf4e8..322dbe2b5 100644 Binary files a/images/cortex-main.png and b/images/cortex-main.png differ diff --git a/thehive-templates/Hashdd_Detail_1_0/long.html b/thehive-templates/Hashdd_Detail_1_0/long.html new file mode 100644 index 000000000..ee733fb80 --- /dev/null +++ b/thehive-templates/Hashdd_Detail_1_0/long.html @@ -0,0 +1,44 @@ + +
+
+ Hashdd report for {{artifact.data | fang}} +
+
+
+
Known Level
+
{{content.known_level || "No known level given."}}
+
File Name
+
{{content.file_name || "No file name given."}}
+
File Path
+
{{content.file_absolute_path || "No file path given."}}
+
File Size
+
{{content.size || "No size given."}}
+
Product Manufacturer
+
{{content.product_manufacturer || "No product manufacturer given."}}
+
Product Name
+
{{content.product_name || "No product name given."}}
+
Product Version
+
{{content.product_version || "No product version given."}}
+
Architecture
+
{{content.architecture || "No architecture given."}}
+
md5
+
{{content.md5 || "No md5 given."}}
+
sha1
+
{{content.sha1 || "No sha1 given."}}
+
sha256
+
{{content.sha256 || "No sha256 given."}}
+
ssdeep
+
{{content.ssdeep || "No ssdeep given."}}
+
+
+
+ + +
+
+ {{artifact.data | fang}} +
+
+ {{content.errorMessage}} +
+
diff --git a/thehive-templates/Hashdd_Detail_1_0/short.html b/thehive-templates/Hashdd_Detail_1_0/short.html new file mode 100644 index 000000000..57f9d29cf --- /dev/null +++ b/thehive-templates/Hashdd_Detail_1_0/short.html @@ -0,0 +1,3 @@ + + {{t.namespace}}:{{t.predicate}}={{t.value}} + diff --git a/thehive-templates/Hashdd_Status_1_0/long.html b/thehive-templates/Hashdd_Status_1_0/long.html new file mode 100644 index 000000000..4c0b2a095 --- /dev/null +++ b/thehive-templates/Hashdd_Status_1_0/long.html @@ -0,0 +1,22 @@ + +
+
+ Hashdd report for {{artifact.data | fang}} +
+
+
+
Known Level
+
{{content.known_level || "No known level given."}}
+
+
+
+ + +
+
+ {{artifact.data | fang}} +
+
+ {{content.errorMessage}} +
+
diff --git a/thehive-templates/Hashdd_Status_1_0/short.html b/thehive-templates/Hashdd_Status_1_0/short.html new file mode 100644 index 000000000..57f9d29cf --- /dev/null +++ b/thehive-templates/Hashdd_Status_1_0/short.html @@ -0,0 +1,3 @@ + + {{t.namespace}}:{{t.predicate}}={{t.value}} +