From 851da3ff53c146faeac2915c263504356661fb24 Mon Sep 17 00:00:00 2001 From: remiallain Date: Wed, 4 Jul 2018 12:26:11 +0200 Subject: [PATCH 1/2] add hunter.io analyzer --- analyzers/Hunterio/Hunterio_domainsearch.json | 22 ++++++++++ analyzers/Hunterio/hunterio_analyzer.py | 44 +++++++++++++++++++ analyzers/Hunterio/requirements.txt | 2 + 3 files changed, 68 insertions(+) create mode 100644 analyzers/Hunterio/Hunterio_domainsearch.json create mode 100755 analyzers/Hunterio/hunterio_analyzer.py create mode 100644 analyzers/Hunterio/requirements.txt diff --git a/analyzers/Hunterio/Hunterio_domainsearch.json b/analyzers/Hunterio/Hunterio_domainsearch.json new file mode 100644 index 000000000..4857d6c0f --- /dev/null +++ b/analyzers/Hunterio/Hunterio_domainsearch.json @@ -0,0 +1,22 @@ +{ + "name": "Hunterio_DomainSearch", + "author": "RĂ©mi Allain, Cyberprotect", + "license": "AGPL-V3", + "url": "https://github.com/Cyberprotect/Cortex-Analyzers", + "version": "1.0", + "description": "hunter.io is a service to find email addresses from a domain.", + "dataTypeList": ["domain", "fqdn"], + "command": "Hunterio/hunterio_analyzer.py", + "baseConfig": "Hunterio", + "config": { + "service": "domainsearch", + "check_tlp": false + }, + "configurationItems": [{ + "name": "key", + "description": "api key of hunter.io", + "type": "string", + "multi": false, + "required": true + }] +} \ No newline at end of file diff --git a/analyzers/Hunterio/hunterio_analyzer.py b/analyzers/Hunterio/hunterio_analyzer.py new file mode 100755 index 000000000..4752e95c9 --- /dev/null +++ b/analyzers/Hunterio/hunterio_analyzer.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import requests +from cortexutils.analyzer import Analyzer + + +class Hunterio(Analyzer): + URI = "https://api.hunter.io/v2/" + + + def __init__(self): + Analyzer.__init__(self) + self.service = self.get_param('config.service', None, 'Service parameter is missing') + self.key = self.get_param('config.key', None, 'Missing hunter.io API key') + + def summary(self, raw): + + taxonomies = [] + namespace = "Hunter.io" + if self.service == 'domainsearch': + found = 0 + if(raw.get('meta') and raw['meta'].get('results')): + found = raw['meta'].get('results') + taxonomies.append(self.build_taxonomy('info', namespace, "Emails found", found)) + + return {"taxonomies": taxonomies} + + + def run(self): + Analyzer.run(self) + + if self.service == 'domainsearch' and (self.data_type == 'domain' or self.data_type == 'fqdn'): + try: + response = requests.get("{}domain-search?domain={}&api_key={}".format(self.URI, self.get_data(), self.key)) + self.report(response.json()) + except Exception as e: + self.unexpectedError(e) + else: + self.notSupported() + + +if __name__ == '__main__': + Hunterio().run() diff --git a/analyzers/Hunterio/requirements.txt b/analyzers/Hunterio/requirements.txt new file mode 100644 index 000000000..4a21dbf63 --- /dev/null +++ b/analyzers/Hunterio/requirements.txt @@ -0,0 +1,2 @@ +cortexutils +requests \ No newline at end of file From 161ecd4395d80ed0673f642b9c70a7c347adcf2a Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Jul 2018 16:20:39 +0200 Subject: [PATCH 2/2] Add report templates and modify request to get all results --- analyzers/Hunterio/hunterio_analyzer.py | 18 ++++- .../Hunterio_DomainSearch_1_0/long.html | 66 +++++++++++++++++++ .../Hunterio_DomainSearch_1_0/short.html | 3 + 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 thehive-templates/Hunterio_DomainSearch_1_0/long.html create mode 100644 thehive-templates/Hunterio_DomainSearch_1_0/short.html diff --git a/analyzers/Hunterio/hunterio_analyzer.py b/analyzers/Hunterio/hunterio_analyzer.py index 4752e95c9..b687e15c2 100755 --- a/analyzers/Hunterio/hunterio_analyzer.py +++ b/analyzers/Hunterio/hunterio_analyzer.py @@ -32,8 +32,22 @@ def run(self): if self.service == 'domainsearch' and (self.data_type == 'domain' or self.data_type == 'fqdn'): try: - response = requests.get("{}domain-search?domain={}&api_key={}".format(self.URI, self.get_data(), self.key)) - self.report(response.json()) + offset = 0 + firstResponse = requests.get("{}domain-search?domain={}&api_key={}&limit=100&offset={}".format(self.URI, self.get_data(), self.key, offset)) + firstResponse = firstResponse.json() + + if firstResponse.get('meta'): + meta = firstResponse.get('meta') + + while meta.get('results') > offset: + offset = meta.get('limit') + meta.get('offset') + additionalResponse = requests.get("{}domain-search?domain={}&api_key={}&limit=100&offset={}".format( + self.URI, self.get_data(), self.key, offset)) + additionalResponse = additionalResponse.json() + meta = additionalResponse.get('meta') + firstResponse['data']['emails'] += additionalResponse['data']['emails'] + + self.report(firstResponse) except Exception as e: self.unexpectedError(e) else: diff --git a/thehive-templates/Hunterio_DomainSearch_1_0/long.html b/thehive-templates/Hunterio_DomainSearch_1_0/long.html new file mode 100644 index 000000000..3766ce905 --- /dev/null +++ b/thehive-templates/Hunterio_DomainSearch_1_0/long.html @@ -0,0 +1,66 @@ +
+
+ hunter.io domain search to find email addresses +
Report for + {{artifact.data}} +
+
+ +

{{content.meta.results}} addresses found.

+ + +
+ +
+ Pattern : {{content.data.pattern}} +
+ +
+ Organization: {{content.data.organization}} +
+ + + + + + + + + + + + + + + + + + + + + + + + +
EmailNamePositionTypeTwitterLinkedInPhoneConfidenceSources
{{email.value}}{{email.fisrtname}} {{email.lastname}}{{email.position}}{{email.type}}{{email.twitter}}{{email.linkedin}}{{email.phone_number}} + {{email.confidence}} + +
    +
  • {{src.domain}}
  • +
+
+
+ +
+ No results found +
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/Hunterio_DomainSearch_1_0/short.html b/thehive-templates/Hunterio_DomainSearch_1_0/short.html new file mode 100644 index 000000000..57f9d29cf --- /dev/null +++ b/thehive-templates/Hunterio_DomainSearch_1_0/short.html @@ -0,0 +1,3 @@ + + {{t.namespace}}:{{t.predicate}}={{t.value}} +