diff --git a/analyzers/RiskIQ/RiskIQ_Articles.json b/analyzers/RiskIQ/RiskIQ_Articles.json new file mode 100644 index 000000000..7dcead066 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Articles.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "articles" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: OSINT articles that reference an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Articles", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Artifacts.json b/analyzers/RiskIQ/RiskIQ_Artifacts.json new file mode 100644 index 000000000..d367b0416 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Artifacts.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "artifacts" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: Illuminate / PassiveTotal project artifacts that match an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Artifacts", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Certificates.json b/analyzers/RiskIQ/RiskIQ_Certificates.json new file mode 100644 index 000000000..1b457e3a6 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Certificates.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "certificates" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: SSL/TLS certificates associated with an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Certificates", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Components.json b/analyzers/RiskIQ/RiskIQ_Components.json new file mode 100644 index 000000000..a132b80f9 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Components.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "components" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: web components observed during crawls on a hostname.", + "license": "AGPL-V3", + "name": "RiskIQ_Components", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Cookies.json b/analyzers/RiskIQ/RiskIQ_Cookies.json new file mode 100644 index 000000000..363f1e0b7 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Cookies.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "cookies" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: cookies observed during crawls on a hostname.", + "license": "AGPL-V3", + "name": "RiskIQ_Cookies", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_HostpairChildren.json b/analyzers/RiskIQ/RiskIQ_HostpairChildren.json new file mode 100644 index 000000000..ff378f789 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_HostpairChildren.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "hostpair_children" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: hosts with a child web component relationship to an IOC.", + "license": "AGPL-V3", + "name": "RiskIQ_HostpairChildren", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_HostpairParents.json b/analyzers/RiskIQ/RiskIQ_HostpairParents.json new file mode 100644 index 000000000..78cb4ec5c --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_HostpairParents.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "hostpair_parents" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: hosts with a parent web component relationship to an IOC.", + "license": "AGPL-V3", + "name": "RiskIQ_HostpairParents", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Malware.json b/analyzers/RiskIQ/RiskIQ_Malware.json new file mode 100644 index 000000000..d9c2f686e --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Malware.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "malware" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: malware hashes from various sources associated with an IOC.", + "license": "AGPL-V3", + "name": "RiskIQ_Malware", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Projects.json b/analyzers/RiskIQ/RiskIQ_Projects.json new file mode 100644 index 000000000..cc6845a78 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Projects.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "projects" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: Illuminate / PassiveTotal projects that contain an artifact which matches an IOC.", + "license": "AGPL-V3", + "name": "RiskIQ_Projects", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Reputation.json b/analyzers/RiskIQ/RiskIQ_Reputation.json new file mode 100644 index 000000000..882d84b06 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Reputation.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "reputation" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ Illuminate Reputation Score for an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Reputation", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Resolutions.json b/analyzers/RiskIQ/RiskIQ_Resolutions.json new file mode 100644 index 000000000..84fb93e23 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Resolutions.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "resolutions" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: PDNS resolutions for an IOC.", + "license": "AGPL-V3", + "name": "RiskIQ_Resolutions", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Services.json b/analyzers/RiskIQ/RiskIQ_Services.json new file mode 100644 index 000000000..6910d9f4b --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Services.json @@ -0,0 +1,41 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "services" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "ip" + ], + "description": "RiskIQ: services observed on an IP address.", + "license": "AGPL-V3", + "name": "RiskIQ_Services", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Subdomains.json b/analyzers/RiskIQ/RiskIQ_Subdomains.json new file mode 100644 index 000000000..f4b5245a7 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Subdomains.json @@ -0,0 +1,42 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "subdomains" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "fqdn", + "domain" + ], + "description": "RiskIQ: subdomains observed historically in pDNS records.", + "license": "AGPL-V3", + "name": "RiskIQ_Subdomains", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Summary.json b/analyzers/RiskIQ/RiskIQ_Summary.json new file mode 100644 index 000000000..21b0a2b8e --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Summary.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "summary" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ Illuminate and PassiveTotal datasets with records for an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Summary", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Trackers.json b/analyzers/RiskIQ/RiskIQ_Trackers.json new file mode 100644 index 000000000..eb492af25 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Trackers.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "trackers" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ: trackers observed during a crawl on a host.", + "license": "AGPL-V3", + "name": "RiskIQ_Trackers", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/RiskIQ_Whois.json b/analyzers/RiskIQ/RiskIQ_Whois.json new file mode 100644 index 000000000..a9eb09e60 --- /dev/null +++ b/analyzers/RiskIQ/RiskIQ_Whois.json @@ -0,0 +1,43 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_analyzer.py", + "config": { + "auto_extract": true, + "property": "whois" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": 180, + "description": "Number of days back to search for date-bounded historical queries", + "multi": false, + "name": "days_back", + "required": false, + "type": "number" + } + ], + "dataTypeList": [ + "domain", + "fqdn", + "ip" + ], + "description": "RiskIQ Whois lookup for an indicator.", + "license": "AGPL-V3", + "name": "RiskIQ_Whois", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/analyzers/RiskIQ/_analyzer.py b/analyzers/RiskIQ/_analyzer.py new file mode 100755 index 000000000..eb5c010cb --- /dev/null +++ b/analyzers/RiskIQ/_analyzer.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.analyzer import Analyzer + +from passivetotal import analyzer as riqanalyzer +from _services import SERVICES + +VERSION = '1.0' + + + +class IlluminateAnalyzer(Analyzer): + def __init__(self): + Analyzer.__init__(self) + self._property = self.get_param('config.property', None, 'RiskIQ Illuminate Analyzer object property is missing') + self._username = self.get_param('config.username', None, 'RiskIQ Illuminate username is missing') + self._api_key = self.get_param('config.api_key', None, 'RiskIQ Illuminate api_key is missing') + self._days_back = self.get_param('config.days_back', None, 'RiskIQ Illuminate days_back is missing') + riqanalyzer.init(username=self._username, api_key=self._api_key) + riqanalyzer.set_date_range(days_back=self._days_back) + riqanalyzer.set_context('thehive','riq-analyzer',VERSION,'analyzer') + if self._property not in SERVICES: + self.error('Unknown property {}'.format(self._property)) + self._svc = SERVICES[self._property]() + + def run(self): + ioc = self.get_data() + try: + ioc_obj = riqanalyzer.get_object(ioc) + except riqanalyzer.AnalyzerError as e: + self.error('Cannot instantiate object for that type of input: {}'.format(e)) + try: + value = getattr(ioc_obj, self._property) + except AttributeError as e: + self.error('Unknown property {}'.format(self._property)) + except riqanalyzer.AnalyzerAPIError as e: + if e.status_code == 404: + self.report({'found': False, 'records': []}) + return + else: + self.error('API error while getting property "{0}": {1}'.format(self._property, e)) + except riqanalyzer.AnalyzerError as e: + self.error('Analyzer error while getting property "{0}": {1}'.format(self._property, e)) + try: + data = value.as_dict + except Exception as e: + self.error('Cannot transform property "{0}" to dictionary: {1}'.format(self._property, e)) + data = self._svc.transform(data) + self.report(data) + + def summary(self, raw): + return self._svc.summarize(raw) + + def artifacts(self, report): + svc_artifacts = self._svc.build_artifacts(report) + if svc_artifacts is None: + return super().artifacts(report) + return svc_artifacts + + + + +if __name__ == '__main__': + IlluminateAnalyzer().run() + + diff --git a/analyzers/RiskIQ/_services.py b/analyzers/RiskIQ/_services.py new file mode 100644 index 000000000..2b5162f3a --- /dev/null +++ b/analyzers/RiskIQ/_services.py @@ -0,0 +1,495 @@ +import json + + +class IlluminateServiceFile(): + """Base service class for all RiskIQ service files.""" + + def __init__(self): + self._name = '' + self._version = '1.0' + self._author = 'RiskIQ' + self._url = 'https://github.com/TheHive-Project/Cortex-Analyzers' + self._license = 'AGPL-V3' + self._command = 'RiskIQ/_analyzer.py' + self._baseconfig = 'RiskIQ' + self._description = '' + self._dataTypeList = ["domain","fqdn","ip"] + self._taxonomy_namespace = 'RIQ' + self._taxonomy_predicate = 'RiskIQ' + self._taxonomy_valuekey = None + self._config = { + 'property': None, + 'auto_extract': True + } + self._configitems = [ + { + 'name': 'username', + 'description': 'API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)', + 'type': 'string', + 'multi': False, + 'required': True + }, + { + 'name': 'api_key', + 'description': 'API key of the RiskIQ Illuminate or PassiveTotal account', + 'type': 'string', + 'multi': False, + 'required': True + }, + { + 'name': 'days_back', + 'description': 'Number of days back to search for date-bounded historical queries', + 'type': 'number', + 'multi': False, + 'required': False, + 'defaultValue': 180 + }, + ] + + def generate(self): + """Creates and writes a JSON file to the local directory describing this service.""" + obj = { + 'name': self._name, + 'version': self._version, + 'author': self._author, + 'url': self._url, + 'license': self._license, + 'description': self._description, + 'dataTypeList': self._dataTypeList, + 'command': self._command, + 'baseConfig': self._baseconfig, + 'config': self._config, + 'configurationItems': self._configitems, + } + filename = '{}.json'.format(self._name) + with open(filename, 'w') as f: + json.dump(obj, f, indent=2, sort_keys=True) + + def get_taxonomies(self, data): + """Get a list of taxonomies for this service.""" + try: + level = self.get_taxonomy_level(data) + except AttributeError: + level = 'info' + return [ + { + 'level': level, + 'namespace': self._taxonomy_namespace, + 'predicate': self._taxonomy_predicate, + 'value': data.get(self._taxonomy_valuekey, None), + } + ] + + def summarize(self, data): + """Build summary data structure for data processed by this service.""" + return { 'taxonomies': self.get_taxonomies(data) } + + def transform(self, data): + """Optionally post-process report data. + + Used by IlluminateAnalyzer.run() to give a service an opportunity to transform + data before sending it upstream. + """ + return data + + def build_artifacts(self, report): + return None + + + +class Reputation(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Reputation' + self._description = 'RiskIQ Illuminate Reputation Score for an indicator.' + self._taxonomy_predicate = 'ReputationScore' + self._taxonomy_valuekey = 'score' + self._config['property'] = 'reputation' + + + def get_taxonomy_level(self, data): + levels = { + 'SUSPICIOUS': 'suspicious', + 'MALICIOUS': 'malicious', + 'GOOD': 'info', + 'UNKOWN': 'info' + } + return levels.get(data['classification'],'info') + + def transform(self, data): + classes = { + 'SUSPICIOUS': 'warning', + 'MALICIOUS': 'danger', + 'GOOD': 'success', + 'UNKOWN': 'info' + } + data['uicontext'] = classes.get(data['classification'],'info') + for index, rule in enumerate(data['rules']): + if rule['severity'] >= 4: + uicontext = 'danger' + elif rule['severity'] >= 2: + uicontext = 'warning' + else: + uicontext = 'info' + data['rules'][index]['uicontext'] = uicontext + return data + + + +class Summary(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Summary' + self._description = 'RiskIQ Illuminate and PassiveTotal datasets with records for an indicator.' + self._taxonomy_predicate = 'Summary' + self._config['property'] = 'summary' + + def get_taxonomies(self, data): + levels = { + 'malware_hashes': 'malicious', + 'articles': 'suspicious', + 'projects': 'suspicious' + } + taxonomies = [] + for dataset, count in data.items(): + if not type(count) is int: + continue + if dataset in levels.keys() and count > 0: + level = levels[dataset] + else: + level = 'info' + if dataset == 'total': + continue + if dataset == 'malware_hashes': + dataset = 'malware' + taxonomies.append({ + 'level': level, + 'namespace': self._taxonomy_namespace, + 'predicate': dataset.title(), + 'value': count + }) + return taxonomies + + def transform(self, data): + levels = { + 'malware_hashes': 'danger', + 'projects': 'warning', + 'articles': 'danger' + } + uicontexts = {} + for field in ['resolutions','certificates','malware_hashes','projects','articles', + 'trackers','components','hostpairs','cookies','services']: + uicontexts[field] = levels.get(field,'info') + data['uicontexts'] = uicontexts + return data + + + +class Whois(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Whois' + self._description = 'RiskIQ Whois lookup for an indicator.' + self._taxonomy_predicate = 'Whois' + self._config['property'] = 'whois' + + def get_taxonomies(self, data): + taxonomies = [] + if 'age' in data: + age = data['age'] + if age < 180: + level = 'suspicious' + taxonomies.append({ + 'level': 'suspicious' if age < 180 else 'info', + 'namespace': self._taxonomy_namespace, + 'predicate': 'Whois Age (days)', + 'value': age + }) + for email in data.get('emails',[]): + taxonomies.append({ + 'level': 'info', + 'namespace': self._taxonomy_namespace, + 'predicate': 'Whois Email', + 'value': email + }) + return taxonomies + + + +class SuspiciousCount: + + def get_taxonomy_level(self, data): + return 'suspicious' if data.get('totalrecords',0) > 0 else 'info' + + + +class Articles(IlluminateServiceFile, SuspiciousCount): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Articles' + self._description = 'RiskIQ: OSINT articles that reference an indicator.' + self._taxonomy_predicate = 'Articles' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'articles' + + + +class Artifacts(IlluminateServiceFile, SuspiciousCount): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Artifacts' + self._description = 'RiskIQ: Illuminate / PassiveTotal project artifacts that match an indicator.' + self._taxonomy_predicate = 'Artifacts' + self._taxonomy_level = 'suspicious' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'artifacts' + + + +class Certificates(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Certificates' + self._description = 'RiskIQ: SSL/TLS certificates associated with an indicator.' + self._taxonomy_predicate = 'Certificates' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'certificates' + + + +class Components(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Components' + self._description = 'RiskIQ: web components observed during crawls on a hostname.' + self._taxonomy_predicate = 'Components' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'components' + + + +class Cookies(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Cookies' + self._description = 'RiskIQ: cookies observed during crawls on a hostname.' + self._taxonomy_predicate = 'Cookies' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'cookies' + + + +class HostpairParents(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_HostpairParents' + self._description = 'RiskIQ: hosts with a parent web component relationship to an IOC.' + self._taxonomy_predicate = 'HostpairParents' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'hostpair_parents' + + + +class HostpairChildren(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_HostpairChildren' + self._description = 'RiskIQ: hosts with a child web component relationship to an IOC.' + self._taxonomy_predicate = 'HostpairChildren' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'hostpair_children' + + + +class Malware(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Malware' + self._description = 'RiskIQ: malware hashes from various sources associated with an IOC.' + self._taxonomy_predicate = 'Malware' + self._taxonomy_level = 'malicious' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'malware' + + + +class Projects(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Projects' + self._description = 'RiskIQ: Illuminate / PassiveTotal projects that contain an artifact which matches an IOC.' + self._taxonomy_predicate = 'Projects' + self._taxonomy_level = 'suspicious' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'projects' + + + +class Resolutions(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Resolutions' + self._description = 'RiskIQ: PDNS resolutions for an IOC.' + self._taxonomy_predicate = 'Resolutions' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'resolutions' + + + +class Subdomains(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Subdomains' + self._description = 'RiskIQ: subdomains observed historically in pDNS records.' + self._dataTypeList = ['fqdn','domain'] + self._taxonomy_predicate = 'Subdomains' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'subdomains' + + def build_artifacts(self, report): + return [ { 'dataType': 'fqdn', 'data': r.get('hostname') } for r in report.get('records', []) ] + + + +class Trackers(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Trackers' + self._description = 'RiskIQ: trackers observed during a crawl on a host.' + self._taxonomy_predicate = 'Trackers' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'trackers' + + + +class Services(IlluminateServiceFile): + + def __init__(self): + super().__init__() + self._name = 'RiskIQ_Services' + self._description = 'RiskIQ: services observed on an IP address.' + self._dataTypeList = ['ip'] + self._taxonomy_predicate = 'Services' + self._taxonomy_level = 'info' + self._taxonomy_valuekey = 'totalrecords' + self._config['property'] = 'services' + + + +SERVICES = { + 'artifacts': Artifacts, + 'articles': Articles, + 'certificates': Certificates, + 'components': Components, + 'cookies': Cookies, + 'hostpair_parents': HostpairParents, + 'hostpair_children': HostpairChildren, + 'malware': Malware, + 'projects': Projects, + 'reputation': Reputation, + 'resolutions': Resolutions, + 'services': Services, + 'subdomains': Subdomains, + 'trackers': Trackers, + 'summary': Summary, + 'whois': Whois, +} + + +if __name__ == '__main__': + import argparse + import subprocess + + parser = argparse.ArgumentParser() + cmdgroup = parser.add_mutually_exclusive_group() + cmdgroup.add_argument('--generate', dest='cmd', action='store_const', const='generate', + help='Generate service files for each service.') + cmdgroup.add_argument('--test', dest='cmd', action='store_const',const='test', + help='Test a service') + parser.add_argument('--property', choices=SERVICES.keys(), + help='Analyzer object property to test.') + parser.add_argument('--input', + help='Input value of the IOC to test.') + parser.add_argument('--type', choices=['fqdn','domain','ip'], + help='TheHive type of the IOC to test.') + parser.add_argument('--username', + help='API username; will be read from passivetotal lib if not provided') + parser.add_argument('--apikey', + help='API key; will be read from passivetotal lib if not provided') + parser.add_argument('--days-back', default=180, type=int, + help='Number of days back to search.') + args = parser.parse_args() + + if args.cmd is None: + parser.print_help() + exit(1) + + if args.cmd == 'generate': + if args.property is not None: + SERVICES[args.property]().generate() + else: + for svc in SERVICES.values(): + svc().generate() + exit(0) + + if args.cmd == 'test': + if args.property is None: + print('Property (--property) is required for a test') + exit(1) + if args.input is None: + print('Input value (--input) is required for a test') + exit(1) + if args.type is None: + print('Input type (--type) is required for a test') + if args.username is None or args.apikey is None: + from passivetotal.libs.account import AccountClient + client = AccountClient.from_config() + username = client.username if args.username is None else args.username + apikey = client.api_key if args.apikey is None else args.apikey + test = { + "data": args.input, + "dataType": args.type, + "tlp":0, + "config":{ + "key":"1234567890abcdef", + "max_tlp":3, + "check_tlp":True, + "property":args.property, + "days_back": args.days_back, + "username": username, + "api_key": apikey, + "service": 'RiskIQ_{}'.format(args.property.title()), + } + } + result = subprocess.run( + ['python3','_analyzer.py'], + input=json.dumps(test), + stdout=subprocess.PIPE, + text=True + ) + print(result.stdout) + + \ No newline at end of file diff --git a/analyzers/RiskIQ/requirements.txt b/analyzers/RiskIQ/requirements.txt new file mode 100644 index 000000000..6d082c473 --- /dev/null +++ b/analyzers/RiskIQ/requirements.txt @@ -0,0 +1,2 @@ +cortexutils +passivetotal>=2.5.2 \ No newline at end of file diff --git a/responders/RiskIQ/RiskIQ_PushArtifactToProject.json b/responders/RiskIQ/RiskIQ_PushArtifactToProject.json new file mode 100644 index 000000000..1472565c9 --- /dev/null +++ b/responders/RiskIQ/RiskIQ_PushArtifactToProject.json @@ -0,0 +1,62 @@ +{ + "author": "RiskIQ", + "baseConfig": "RiskIQ", + "command": "RiskIQ/_responder.py", + "config": { + "service": "PushArtifactToProject" + }, + "configurationItems": [ + { + "description": "API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)", + "multi": false, + "name": "username", + "required": true, + "type": "string" + }, + { + "description": "API key of the RiskIQ Illuminate or PassiveTotal account", + "multi": false, + "name": "api_key", + "required": true, + "type": "string" + }, + { + "defaultValue": "analyst", + "description": "Visiblity for new RiskIQ Illuminate projects (analyst, team, or public).", + "multi": false, + "name": "project_visibility", + "required": true, + "type": "string" + }, + { + "defaultValue": "Hive:", + "description": "Prefix to add when auto-generating project names from case names.", + "multi": false, + "name": "project_prefix", + "required": false, + "type": "string" + }, + { + "description": "Tag to apply to artifact in TheHive when is has been pushed to a RiskIQ Illuminate Project (leave blank to skip tagging).", + "multi": false, + "name": "thehive_artifact_tag", + "required": false, + "type": "string" + }, + { + "description": "Tag to apply to artifact in RiskIQ Illuminate when is has been pushed to an Illuminate Project (leave blank to skip tagging).", + "multi": false, + "name": "riq_artifact_tag", + "required": false, + "type": "string" + } + ], + "dataTypeList": [ + "thehive:case_artifact" + ], + "description": "Push a case to a RiskIQ Illuminate project.", + "license": "AGPL-V3", + "name": "RiskIQ_PushArtifactToProject", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0" +} \ No newline at end of file diff --git a/responders/RiskIQ/_responder.py b/responders/RiskIQ/_responder.py new file mode 100755 index 000000000..4fd4066d0 --- /dev/null +++ b/responders/RiskIQ/_responder.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + + +from cortexutils.responder import Responder +from _services import SERVICES + + + +class RiskIQIlluminate(Responder): + def __init__(self): + Responder.__init__(self) + self._username = self.get_param('config.username', None, 'RiskIQ Illuminate username is missing') + self._api_key = self.get_param('config.api_key', None, 'RiskIQ Illuminate api_key is missing') + self._service_name = self.get_param('config.service', None, 'Service name is required') + self._project_visibility = self.get_param('config.project_visiblity','analyst') + self._project_prefix = self.get_param('config.project_prefix', 'Hive:') + self._thehive_artifact_tag = self.get_param('config.thehive_artifact_tag',None) + self._riq_artifact_tag = self.get_param('config.riq_artifact_tag',None) + self._service = SERVICES[self._service_name]( + visibility = self._project_visibility, + prefix = self._project_prefix, + thehive_artifact_tag = self._thehive_artifact_tag, + riq_artifact_tag = self._riq_artifact_tag, + username = self._username, + api_key = self._api_key + ) + + def run(self): + Responder.run(self) + self._service.run(self.get_param('data')) + report = self._service.get_report() + if 'error' in report: + self.error(report['error']) + self.report(report) + + def operations(self, raw): + ops = [] + for op in self._service.get_operations(): + ops.append(self.build_operation(op['name'], **op['kwargs'])) + return ops + + + +if __name__ == '__main__': + RiskIQIlluminate().run() \ No newline at end of file diff --git a/responders/RiskIQ/_services.py b/responders/RiskIQ/_services.py new file mode 100644 index 000000000..41956907a --- /dev/null +++ b/responders/RiskIQ/_services.py @@ -0,0 +1,199 @@ +import json +from passivetotal import ProjectsRequest, ArtifactsRequest + +VERSION = '1.0' + + + +class IlluminateServiceFile(): + """Base service class for all RiskIQ service files.""" + + def __init__(self, **kwargs): + self._name = 'RiskIQ_{}'.format(self.__class__.__name__) + self._version = VERSION + self._author = 'RiskIQ' + self._url = 'https://github.com/TheHive-Project/Cortex-Analyzers' + self._license = 'AGPL-V3' + self._command = 'RiskIQ/_responder.py' + self._baseconfig = 'RiskIQ' + self._description = '' + self._dataTypeList = [] + self._config = { 'service': self.__class__.__name__ } + self._report = {} + self._operations = [] + self._params = kwargs + self._configitems = [ + { + 'name': 'username', + 'description': 'API username of the RiskIQ Illuminate or PassiveTotal account (usually an email address)', + 'type': 'string', + 'multi': False, + 'required': True + }, + { + 'name': 'api_key', + 'description': 'API key of the RiskIQ Illuminate or PassiveTotal account', + 'type': 'string', + 'multi': False, + 'required': True + }, + { + 'name': 'project_visibility', + 'description': 'Visiblity for new RiskIQ Illuminate projects (analyst, team, or public).', + 'type': 'string', + 'multi': False, + 'required': True, + 'defaultValue': 'analyst' + }, + { + 'name': 'project_prefix', + 'description': 'Prefix to add when auto-generating project names from case names.', + 'type': 'string', + 'multi': False, + 'required': False, + 'defaultValue': 'Hive:' + }, + { + 'name': 'thehive_artifact_tag', + 'description': 'Tag to apply to artifact in TheHive when is has been pushed to a RiskIQ Illuminate Project (leave blank to skip tagging).', + 'type': 'string', + 'multi': False, + 'required': False + }, + { + 'name': 'riq_artifact_tag', + 'description': 'Tag to apply to artifact in RiskIQ Illuminate when is has been pushed to an Illuminate Project (leave blank to skip tagging).', + 'type': 'string', + 'multi': False, + 'required': False + } + ] + + def generate(self): + """Creates and writes a JSON file to the local directory describing this service.""" + obj = { + 'name': self._name, + 'version': self._version, + 'author': self._author, + 'url': self._url, + 'license': self._license, + 'description': self._description, + 'dataTypeList': self._dataTypeList, + 'command': self._command, + 'baseConfig': self._baseconfig, + 'config': self._config, + 'configurationItems': self._configitems, + } + filename = '{}.json'.format(self._name) + with open(filename, 'w') as f: + json.dump(obj, f, indent=2, sort_keys=True) + + def add_operation(self, opname, **kwargs): + self._operations.append({ 'name': opname, 'kwargs': kwargs}) + + def run(self, input): + return + + def get_report(self): + return self._report + + def get_operations(self): + return self._operations + + + +class PushArtifactToProject(IlluminateServiceFile): + + CUSTOMFIELD = 'riq-project-guid' + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._description = 'Push a case to a RiskIQ Illuminate project.' + self._dataTypeList = ["thehive:case_artifact"] + + def run(self, data): + project_name = '{0}Case #{1} - {2}'.format( + self._params.get('prefix',''), + data['case']['caseId'], + data['case']['title'] + ) + self._report['case'] = data['case'] + project_description = data['case'].get('description','') + project_visibility = self._params['visibility'] + request = ProjectsRequest(username=self._params['username'], api_key=self._params['api_key']) + request.set_context('thehive','riq-responder',VERSION,self.__class__.__name__) + projects = request.find_projects(project_name, visibility=project_visibility) + if len(projects) > 1: + self._report['error'] = 'Found more than one project with the same name' + return + if len(projects) == 0: + project = request.create_project(project_name, visibility=project_visibility, description=project_description) + self._report['riq_project'] = project + else: + project = projects[0] + project_guid = project['guid'] + request = ArtifactsRequest(username=self._params['username'], api_key=self._params['api_key']) + request.set_context('thehive','riq-responder',VERSION,self.__class__.__name__) + artifact_tag = self._params.get('riq_artifact_tag') + if artifact_tag is not None: + tags = [artifact_tag] + else: + tags = None + self._report['riq_artifact'] = request.upsert_artifact(project_guid, data['data'], tags=tags) + thehive_artifact_tag = self._params.get('thehive_artifact_tag') + if thehive_artifact_tag is not None: + if thehive_artifact_tag not in data['tags']: + self.add_operation('AddTagToArtifact', tag=thehive_artifact_tag) + #self._report['ops'] = self._operations + + + + + + + +SERVICES = { + 'PushArtifactToProject': PushArtifactToProject, +} + + +if __name__ == '__main__': + import argparse + import subprocess + + parser = argparse.ArgumentParser() + cmdgroup = parser.add_mutually_exclusive_group() + cmdgroup.add_argument('--generate', dest='cmd', action='store_const', const='generate', + help='Generate service files for each service.') + cmdgroup.add_argument('--test', dest='cmd', action='store_const',const='test', + help='Test a service') + parser.add_argument('--responder', choices=SERVICES.keys(), + help='Responder to test.') + parser.add_argument('--input', + help='Input value of the IOC to test.') + parser.add_argument('--type', choices=['fqdn','domain','ip'], + help='TheHive type of the IOC to test.') + parser.add_argument('--username', + help='API username; will be read from passivetotal lib if not provided') + parser.add_argument('--apikey', + help='API key; will be read from passivetotal lib if not provided') + parser.add_argument('--days-back', default=180, type=int, + help='Number of days back to search.') + args = parser.parse_args() + + if args.cmd is None: + parser.print_help() + exit(1) + + if args.cmd == 'generate': + if args.responder is not None: + SERVICES[args.responder]().generate() + else: + for svc in SERVICES.values(): + svc().generate() + exit(0) + + if args.cmd == 'test': + print('Sorry, testing responders is not yet implemented.') + + \ No newline at end of file diff --git a/responders/RiskIQ/requirements.txt b/responders/RiskIQ/requirements.txt new file mode 100644 index 000000000..e468bfcf1 --- /dev/null +++ b/responders/RiskIQ/requirements.txt @@ -0,0 +1,2 @@ +cortexutils +passivetotal diff --git a/thehive-templates/RiskIQ_Articles_1_0/long.html b/thehive-templates/RiskIQ_Articles_1_0/long.html new file mode 100644 index 000000000..21d9ca406 --- /dev/null +++ b/thehive-templates/RiskIQ_Articles_1_0/long.html @@ -0,0 +1,47 @@ +
+ + + +
+
+
+ No articles available for this IOC. +
+
+
+ RiskIQ OSINT Articles +
+
+
+
+

{{art.title}}

+

+ {{tag}} +

+

Published {{art.date_published}} ({{art.type}})

+

{{art.summary}}

+ + +
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Artifacts_1_0/long.html b/thehive-templates/RiskIQ_Artifacts_1_0/long.html new file mode 100644 index 000000000..9c7008258 --- /dev/null +++ b/thehive-templates/RiskIQ_Artifacts_1_0/long.html @@ -0,0 +1,81 @@ +
+ + + +
+
+
+ No RiskIQ artifacts reference this IOC. +
+
+
+ RiskIQ Artifacts +
+
+
+
+
+
Project GUID
+
{{art.project_guid}}
+
+
+
Article GUID
+
{{art.artifact_guid}}
+
+
+
Is monitored?
+
Created
+
+
+
{{art.is_monitored}}
+
{{art.created}}
+
+
+
Owner
+
Creator
+
+
+
{{art.owner}}
+
{{art.creator}}
+
+
+
User Tags
+
Global Tags
+
+
+
+ {{tag}} +
+
+ {{tag}} +
+
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Certificates_1_0/long.html b/thehive-templates/RiskIQ_Certificates_1_0/long.html new file mode 100644 index 000000000..e644dc578 --- /dev/null +++ b/thehive-templates/RiskIQ_Certificates_1_0/long.html @@ -0,0 +1,96 @@ +
+ + + +
+
+
+ No certificates available for this IOC. +
+
+
+ RiskIQ TLS/SSL Certificates +
+
+
+
+
+
+
Certificate
+
+
+
+
{{key}}
+
+ {{value}} + +
+
+
+
+
+
+
+
+
+
Subject
+
+
+
+
{{key|limitTo:50:7}}
+
+ {{value}} + +
+
+
+
+
+
+
+
+
Issuer
+
+
+
+
{{key|limitTo:50:6}}
+
+ {{value}} + +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Components_1_0/long.html b/thehive-templates/RiskIQ_Components_1_0/long.html new file mode 100644 index 000000000..45a048364 --- /dev/null +++ b/thehive-templates/RiskIQ_Components_1_0/long.html @@ -0,0 +1,54 @@ +
+ + + +
+
+
+ No web components available for this IOC. +
+
+
+ RiskIQ Web Components +
+
+ + + + + + + + + + + + + + + + + + + + + +
CategoryComponentVersionHostFirst SeenLast Seen
{{comp.category}}{{comp.label}}{{comp.version}}{{comp.hostname}}{{comp.firstseen}}{{comp.lastseen}}
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Cookies_1_0/long.html b/thehive-templates/RiskIQ_Cookies_1_0/long.html new file mode 100644 index 000000000..dff655a01 --- /dev/null +++ b/thehive-templates/RiskIQ_Cookies_1_0/long.html @@ -0,0 +1,83 @@ +
+ + + +
+
+
+ No cookies available for this IOC. +
+
+
+ RiskIQ Host Cookies +
+
+
+
+
+
Distinct Domains
+
+ + + + +
{{d}}
+
+
+
+
+
+
Distinct Cookie Names
+
+ + + + +
{{d}}
+
+
+
+
+
+
Cookie History
+
+ + + + + + + + + + + + + + + + + + + +
Cookie NameCookie DomainHostFirst SeenLast Seen
{{cook.name}}{{cook.domain}}{{cook.hostname}}{{cook.firstseen}}{{cook.lastseen}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_HostpairChildren_1_0/long.html b/thehive-templates/RiskIQ_HostpairChildren_1_0/long.html new file mode 100644 index 000000000..499c03f1a --- /dev/null +++ b/thehive-templates/RiskIQ_HostpairChildren_1_0/long.html @@ -0,0 +1,81 @@ +
+ + + +
+
+
+ No child hostpairs available for this IOC. +
+
+
+ RiskIQ Child Hostpairs +
+
+
+
+
+
Distinct Hosts
+
+ + + + +
{{d}}
+
+
+
+
+
+
Distinct Causes
+
+ + + + +
{{d}}
+
+
+
+
+
+
Child Hostpair History
+
+ + + + + + + + + + + + + + + + + +
CauseChildFirst SeenLast Seen
{{hp.cause}}{{hp.child}}{{hp.firstseen}}{{hp.lastseen}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_HostpairParents_1_0/long.html b/thehive-templates/RiskIQ_HostpairParents_1_0/long.html new file mode 100644 index 000000000..d6bb8e566 --- /dev/null +++ b/thehive-templates/RiskIQ_HostpairParents_1_0/long.html @@ -0,0 +1,81 @@ +
+ + + +
+
+
+ No parent hostpairs available for this IOC. +
+
+
+ RiskIQ Parent Hostpairs +
+
+
+
+
+
Distinct Hosts
+
+ + + + +
{{d}}
+
+
+
+
+
+
Distinct Causes
+
+ + + + +
{{d}}
+
+
+
+
+
+
Parent Hostpair History
+
+ + + + + + + + + + + + + + + + + +
CauseParentFirst SeenLast Seen
{{hp.cause}}{{hp.parent}}{{hp.firstseen}}{{hp.lastseen}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Malware_1_0/long.html b/thehive-templates/RiskIQ_Malware_1_0/long.html new file mode 100644 index 000000000..287351165 --- /dev/null +++ b/thehive-templates/RiskIQ_Malware_1_0/long.html @@ -0,0 +1,48 @@ +
+ + + +
+
+
+ No malware hashes found for this IOC. +
+
+
+ RiskIQ Malware Hashes +
+
+ + + + + + + + + + + + + + + +
HashSourceDate Collected
{{mal.hash}}{{mal.source}}{{mal.date_collected}}
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Projects_1_0/long.html b/thehive-templates/RiskIQ_Projects_1_0/long.html new file mode 100644 index 000000000..7c2292d77 --- /dev/null +++ b/thehive-templates/RiskIQ_Projects_1_0/long.html @@ -0,0 +1,80 @@ +
+ + + +
+
+
+ No projects found that reference this IOC. +
+
+
+ RiskIQ Projects +
+
+
+
{{proj.name}}
+
+
+
Description
+
{{proj.description}}
+
+
+
Created
+
{{proj.created}}
+
+
+
Visibility
+
{{proj.visibility}}
+
+
+
Tags
+
+ {{tag}} +
+
+
+
Owner
+
{{proj.owner}}
+
+
+
Creator
+
{{proj.creator}}
+
+
+
Organization
+
{{proj.organization}}
+
+
+
GUID
+
{{proj.project_guid}}
+
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Reputation_1_0/long.html b/thehive-templates/RiskIQ_Reputation_1_0/long.html new file mode 100644 index 000000000..223a1a806 --- /dev/null +++ b/thehive-templates/RiskIQ_Reputation_1_0/long.html @@ -0,0 +1,71 @@ +
+ + + +
+
+
+ No Reputation Score available for this IOC. +
+
+
+ RiskIQ Illuminate Reputation Score +
+
+
+
Score:
+
+
+
+ {{content.score}} / 100 ({{content.classification}}) +
+
+
+
+
+
+
+
+ Score Justification +
+
+ + + + + + + + + + + +
SeverityNameDescription
{{r.severity}}{{r.name || 'None'}}{{r.description || 'None'}}
+
+
+ +
+
+ +
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Resolutions_1_0/long.html b/thehive-templates/RiskIQ_Resolutions_1_0/long.html new file mode 100644 index 000000000..59737b40f --- /dev/null +++ b/thehive-templates/RiskIQ_Resolutions_1_0/long.html @@ -0,0 +1,87 @@ +
+ + + +
+
+
+
+ RiskIQ PDNS Resolutions +
+
+
+
+
+
+
Earliest Available Record
+
{{content.firstseen}}
+
+
+
Most Recent Record
+
{{content.lastseen}}
+
+
+
+
+
Query Start Date
+
{{content.datestart}}
+
+
+
Query End Date
+
{{content.dateend}}
+
+
+
+
+
+
pDNS Resolution History
+
+ + + + + + + + + + + + + + + + + + + +
TypeResolutionFirst SeenLast SeenSources
{{p.recordtype}}{{p.resolve}}{{p.firstseen}}{{p.lastseen}} + {{s}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Services_1_0/long.html b/thehive-templates/RiskIQ_Services_1_0/long.html new file mode 100644 index 000000000..e09d4d8dc --- /dev/null +++ b/thehive-templates/RiskIQ_Services_1_0/long.html @@ -0,0 +1,175 @@ +
+ + + +
+
+
+ No service history available for this IOC. +
+
+
+ RiskIQ Services +
+
+
+
{{svc.protocol}} {{svc.port}} ({{svc.status}}) +
+
+
+
First Seen
+
Last Seen
+
Observations
+
+
+
{{svc.firstseen}}
+
{{svc.lastseen}}
+
{{svc.count}}
+
+
+
+
Current Services
+
+
+
+ + + + + + + + + + + + + + + + + + + +
ServiceCategoryVersionFirst SeenLast Seen
{{s.label}}{{s.category}}{{s.version}}{{s.firstSeen}}{{s.lastSeen}}
+
+
+ +
+
+
Banners
+
+
+
+ + + + + + + + + + + + + + + + + + + +
Scan TypeObservationsFirst SeenLast SeenBanners
{{b.scanType}}{{b.count}}{{b.firstSeen}}{{b.lastSeen}} + + +
+
+
+ +
+
+
Recent Services
+
+
+
+ + + + + + + + + + + + + + + + + + + +
ServiceCategoryVersionFirst SeenLast Seen
{{s.label}}{{s.category}}{{s.version}}{{s.firstSeen}}{{s.lastSeen}}
+
+
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Subdomains_1_0/long.html b/thehive-templates/RiskIQ_Subdomains_1_0/long.html new file mode 100644 index 000000000..0df6b0a3c --- /dev/null +++ b/thehive-templates/RiskIQ_Subdomains_1_0/long.html @@ -0,0 +1,69 @@ +
+ + + +
+
+
+
+ RiskIQ Subdomains +
+
+
+
+
+
+
Primary Domain
+
{{content.primary_domain}}
+
+
+
+
+
+
Observed Subdomains
+
+ + + + + + + + + + + + + + + +
SubdomainPrimary DomainFQDN
{{p.subdomain}}{{p.primary_domain}}{{p.hostname}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
diff --git a/thehive-templates/RiskIQ_Summary_1_0/long.html b/thehive-templates/RiskIQ_Summary_1_0/long.html new file mode 100644 index 000000000..7fa855534 --- /dev/null +++ b/thehive-templates/RiskIQ_Summary_1_0/long.html @@ -0,0 +1,129 @@ +
+ + + +
+
+ RiskIQ Illuminate Available Datasets +
+
+
+
+
+
+ pDNS +
+
+

{{content.resolutions}}

+
+
+
+
+
+
+ TLS/SSL +
+
+

{{content.certificates}}

+
+
+
+
+
+
+ Articles +
+
+

{{content.articles}}

+
+
+
+
+
+
+ Projects +
+
+

{{content.projects}}

+
+
+
+
+
+
+ Malware +
+
+

{{content.malware_hashes}}

+
+
+
+
+
+
+ Trackers +
+
+

{{content.trackers}}

+
+
+
+
+
+
+ Components +
+
+

{{content.components}}

+
+
+
+
+
+
+ Cookies +
+
+

{{content.cookies}}

+
+
+
+
+
+
+ Host Pairs +
+
+

{{content.hostpairs}}

+
+
+
+
+
+
+ Services +
+
+

{{content.services}}

+
+
+
+
+ +
+
+ +
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Trackers_1_0/long.html b/thehive-templates/RiskIQ_Trackers_1_0/long.html new file mode 100644 index 000000000..28d4eba11 --- /dev/null +++ b/thehive-templates/RiskIQ_Trackers_1_0/long.html @@ -0,0 +1,81 @@ +
+ + + +
+
+
+ No trackers available for this IOC. +
+
+
+ RiskIQ Trackers +
+
+
+
+
+
Distinct Trackers
+
+ + + + +
{{d}}
+
+
+
+
+
+
Distinct Values
+
+ + + + +
{{d}}
+
+
+
+
+
+
Tracker History
+
+ + + + + + + + + + + + + + + + + +
TrackerValueFirst SeenLast Seen
{{t.trackertype}}{{t.value}}{{t.firstseen}}{{t.lastseen}}
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file diff --git a/thehive-templates/RiskIQ_Whois_1_0/long.html b/thehive-templates/RiskIQ_Whois_1_0/long.html new file mode 100644 index 000000000..06f649bb5 --- /dev/null +++ b/thehive-templates/RiskIQ_Whois_1_0/long.html @@ -0,0 +1,171 @@ +
+ + +
+
+
+ No Whois data available for this IOC. +
+
+
+ RiskIQ Whois Record +
+
+
+
+
+
+
+
Primary Contact
+
+
Name
+
{{content.name}} 
+
Organization
+
{{content.organization}} 
+
Telephone
+
{{content.telephone}} 
+
Email
+
{{content.email}} 
+
+
+
+
+
+
Domain Registration
+
+
Registered
+
+ {{content.registered}} + {{content.age}}days + {{content.age}} days + {{content.age}} days +
+
Expires
+
{{content.expiresAt}} 
+
Registrar
+
{{content.registrar}} 
+
Registry Updated
+
{{content.registryUpdatedAt}} 
+
Name Servers
+
{{ns}}
+
+
+
+
+
+
+
+
Admin Contact
+
+
Name
+
{{content.admin.name}} 
+
Organization
+
{{content.admin.organization}} 
+
Telephone
+
{{content.admin.telephone}} 
+
Email
+
{{content.admin.email}} 
+
State/Province/Region
+
{{content.admin.state}} 
+
Country
+
{{content.admin.country}} 
+
+
+
+
+
+
Registrant Contact
+
+
Name
+
{{content.registrant.name}} 
+
Organization
+
{{content.registrant.organization}} 
+
Telephone
+
{{content.registrant.telephone}} 
+
Email
+
{{content.registrant.email}} 
+
State/Province/Region
+
{{content.registrant.state}} 
+
Country
+
{{content.registrant.country}} 
+
+
+
+
+ +
+
+
+
Tech Contact
+
+
Name
+
{{content.tech.name}} 
+
Organization
+
{{content.tech.organization}} 
+
Telephone
+
{{content.tech.telephone}} 
+
Email
+
{{content.tech.email}} 
+
State/Province/Region
+
{{content.tech.state}} 
+
Country
+
{{content.tech.country}} 
+
+
+
+
+
+
Billing Contact
+
+
Name
+
{{content.billing.name}} 
+
Organization
+
{{content.billing.organization}} 
+
Telephone
+
{{content.billing.telephone}} 
+
Email
+
{{content.billing.email}} 
+
State/Province/Region
+
{{content.billing.state}} 
+
Country
+
{{content.billing.country}} 
+
+
+
+
+
+
+ Raw Whois Record +
+
+
{{content.rawText}}
+
+
+
+
+
+
+
+
+
+ +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
\ No newline at end of file