diff --git a/analyzers/C1fApp/C1fApp_osint.json b/analyzers/C1fApp/C1fApp_osint.json new file mode 100644 index 000000000..77f9aed72 --- /dev/null +++ b/analyzers/C1fApp/C1fApp_osint.json @@ -0,0 +1,17 @@ +{ + "name": "C1fApp", + "version": "1.0", + "author": "etz69", + "url": "https://github.com/CERT-BDF/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Query C1fApp OSINT Aggregator for IPs, domains and URLs", + "dataTypeList": ["url", "domain", "ip"], + "baseConfig": "C1fApp", + "config": { + "check_tlp":true, + "max_tlp": 4, + "service": "query" + + }, + "command": "C1fApp/cifquery.py" +} diff --git a/analyzers/C1fApp/README b/analyzers/C1fApp/README new file mode 100644 index 000000000..a7cf23ef9 --- /dev/null +++ b/analyzers/C1fApp/README @@ -0,0 +1,24 @@ +C1fApp is a free threat feed aggregator. It queries the most common +OSINT threat feeds. + +Add the following to application.conf to enable analyzer + +``` +C1fApp { + service="query" + key="Get your key from www.c1fapp.com" + api_url="https://www.c1fapp.com/cifapp/api/" + } +``` + +To test the analyzer from cmdline + +python cifquery.py < input + +Testing +-------- +cd /opt/thehive + +bin/thehive -Dconfig.file=conf/application.conf + +bin/cortex -Dconfig.file=/opt/cortex/conf/application.conf \ No newline at end of file diff --git a/analyzers/C1fApp/cifquery.py b/analyzers/C1fApp/cifquery.py new file mode 100755 index 000000000..c571d66c2 --- /dev/null +++ b/analyzers/C1fApp/cifquery.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# encoding: utf-8 +import json +import requests + +from cortexutils.analyzer import Analyzer + + +class C1fQueryAnalyzer(Analyzer): + + def __init__(self): + Analyzer.__init__(self) + self.service = self.getParam( + 'config.service', None, 'Service parameter is missing') + self.cif_key = self.getParam('config.key', None, 'Missing C1fApp API key') + self.api_url = self.getParam('config.api_url', None, 'Missing API URL') + + @staticmethod + def _getheaders(): + return { + 'user-agent': "cortex-analyzer-v1.0", + 'Accept': 'application/json' + } + + @staticmethod + def cleanup(return_data): + + response = dict() + assessments = [] + feed_labels = [] + descriptions = [] + asns = [] + asn_descs = [] + countries = [] + domains = [] + ip_addresses = [] + + found = False + count = 0 + + for entry in return_data: + found = True + assessments.append(entry.get('assessment')) + feed_labels.append(entry.get('feed_label')) + descriptions.append(entry.get('description')) + asns.append(entry.get('asn')) + asn_descs.append(entry.get('asn_desc')) + countries.append(entry.get('country')) + domains.append(entry.get('domain')) + dga_indication = entry.get('dga') + + if len(list(entry.get('ip_address'))) > 0: + for ip in entry.get('ip_address'): + ip_addresses.append(ip) + else: + ip_addresses.append(entry.get('ip_address')) + + response['assessment'] = list(set(assessments[0])) + response['feed_label'] = list(set(feed_labels[0])) + response['description'] = list(set(descriptions[0])) + response['asn'] = list(set(asns[0])) + response['asn_desc'] = list(set(asn_descs[0])) + response['country'] = list(set(countries[0])) + response['domains'] = list(set(domains[0])) + response['ip_addresses'] = list(set(ip_addresses)) + response['dga'] = dga_indication + response['found'] = found + response['count'] = len(return_data) + + return response + + def c1f_query(self, data): + headers = self._getheaders() + results = dict() + + try: + _session = requests.Session() + + payload = {'key': self.cif_key, + 'format': 'json', + 'backend': 'es', + 'request': data + } + + _query = _session.post(self.api_url, headers=headers, + data=json.dumps(payload)) + if _query.status_code == 200: + if _query.text == "[]": + return dict() + else: + return self.cleanup(_query.json()) + else: + self.error('API Access error: %s' % _query.text) + + except Exception as e: + self.error('API Request error') + + return results + + @staticmethod + def summary(raw): + return { + "count": raw["count"] + } + + def run(self): + + if self.service == 'query': + if self.data_type == 'url' or self.data_type == 'domain' \ + or self.data_type == 'ip': + data = self.getParam('data', None, 'Data is missing') + + rep = self.c1f_query(data) + self.report(rep) + + else: + self.error('Invalid data type') + else: + self.error('Invalid service') + + +if __name__ == '__main__': + C1fQueryAnalyzer().run() diff --git a/analyzers/C1fApp/input b/analyzers/C1fApp/input new file mode 100644 index 000000000..87f62b464 --- /dev/null +++ b/analyzers/C1fApp/input @@ -0,0 +1,10 @@ +{ + "dataType":"domain", + "data": "38.229.72.16", + "config":{ + "service": "query", + "key": "YOUR_KEY", + "api_url": "https://www.c1fapp.com/cifapp/api/" + + } +} diff --git a/thehive-templates/C1fApp_1_0/long.html b/thehive-templates/C1fApp_1_0/long.html new file mode 100644 index 000000000..c8266a4d1 --- /dev/null +++ b/thehive-templates/C1fApp_1_0/long.html @@ -0,0 +1,47 @@ + +