From 191906ab0c03d78e193576a6b5bbc3b45a76e44f Mon Sep 17 00:00:00 2001 From: Pierre Lalet Date: Sat, 9 Jan 2021 03:54:41 +0100 Subject: [PATCH] Add IVRE Analyzer --- analyzers/IVRE/IVRE.json | 59 +++++ analyzers/IVRE/assets/ivre_logo.png | Bin 0 -> 24127 bytes analyzers/IVRE/ivre_analyzer.py | 367 ++++++++++++++++++++++++++++ analyzers/IVRE/requirements.txt | 2 + 4 files changed, 428 insertions(+) create mode 100644 analyzers/IVRE/IVRE.json create mode 100644 analyzers/IVRE/assets/ivre_logo.png create mode 100755 analyzers/IVRE/ivre_analyzer.py create mode 100644 analyzers/IVRE/requirements.txt diff --git a/analyzers/IVRE/IVRE.json b/analyzers/IVRE/IVRE.json new file mode 100644 index 000000000..2ce248b00 --- /dev/null +++ b/analyzers/IVRE/IVRE.json @@ -0,0 +1,59 @@ +{ + "name": "IVRE", + "version": 1.0, + "author": "Pierre Lalet", + "license": "AGPL-V3", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "service_homepage": "https://ivre.rocks/", + "version": "1.0", + "description": "Fetch details from an IVRE instance.", + "dataTypeList": [ + "autonomous-system", + "certificate_hash", + "domain", + "fqdn", + "ip", + "network", + "port", + "user-agent" + ], + "command": "IVRE/ivre_analyzer.py", + "baseConfig": "IVRE", + "configurationItems": [ + { + "name": "use_data", + "description": "Use data from the data purpose (MaxMind)", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": true + }, + { + "name": "use_passive", + "description": "Use data from the passive purpose", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": true + }, + { + "name": "use_scans", + "description": "Use data from the scans (nmap) purpose", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": true + } + ], + "config": { + "check_tlp": false, + "max_tlp": 3, + "check_pap": false, + "max_pap": 3, + "auto_extract": false + }, + "service_logo": { + "path": "assets/ivre_logo.png", + "caption": "Logo" + } +} diff --git a/analyzers/IVRE/assets/ivre_logo.png b/analyzers/IVRE/assets/ivre_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a22935b0ced17a773705923cf9d35ae0dd918aba GIT binary patch literal 24127 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 + + +"""Cortex Analyzer that queries an IVRE instance. + +""" + + +from datetime import datetime + + +from cortexutils.analyzer import Analyzer +from ivre.db import db +from ivre import utils + + +# TODO: extracted data should depend on the data type! + + +DATABASES = { + "data": db.data, + "passive": db.passive, + "scans": db.nmap, +} + + +class Processor: + + databases = [] + + def __init__(self, analyzer): + self.analyzer = analyzer + self.data = analyzer.get_data() + + def flt(self, dbase): + raise NotImplementedError() + + def run(self): + result = {} + for dbname in self.databases: + if not self.analyzer.get_param("config.use_%s" % dbname, True): + continue + res = self.get(dbname) + if res: + result[dbname] = res + return result + + def get(self, dbase): + # By default, report all IP addresses + result = sorted( + DATABASES[dbase].distinct("addr", flt=self.flt(dbase)), key=utils.ip2int + ) + self.analyzer._artifacts.update(("ip", addr) for addr in result) + return result + + @staticmethod + def from_analyzer(analyzer): + return { + "autonomous-system": ProcessorAsnum, + "certificate_hash": ProcessorCert, + "domain": ProcessorDomain, + "fqdn": ProcessorFqdn, + "ip": ProcessorIp, + "network": ProcessorNet, + "port": ProcessorPort, + "user-agent": ProcessorUserAgent, + }[analyzer.data_type](analyzer) + + +class ProcessorIp(Processor): + """IP addresses processor + + output contains intelligence about the IP address; the format is + different from one database to another. + + """ + + databases = ["data", "passive", "scans"] + keep_addresses = False + + def flt(self, dbase): + return DATABASES[dbase].searchhost(self.data) + + def get_scans(self, dbase): + if self.keep_addresses: + all_results = {} + else: + result = {} + for rec in DATABASES[dbase].get(self.flt(dbase)): + if self.keep_addresses: + result = all_results.setdefault(rec["addr"], {}) + self.analyzer._artifacts.add(("ip", rec["addr"])) + firstseen = rec.get('starttime', rec.get('endtime')) + lastseen = rec.get('endtime', rec.get('starttime')) + if firstseen: + if "firstseen" in result: + result["firstseen"] = min(result["firstseen"], firstseen) + else: + result["firstseen"] = firstseen + if lastseen: + if "lastseen" in result: + result["lastseen"] = min(result["lastseen"], firstseen) + else: + result["lastseen"] = firstseen + if rec.get("categories"): + result.setdefault("categories", set()).update( + c for c in rec["categories"] if not c.startswith("_") + ) + if rec.get("source"): + result.setdefault("source", set()).add(rec["source"]) + if rec.get("hostnames"): + result.setdefault("hostnames", set()).update( + hn["name"] for hn in rec["hostnames"] + ) + for port in rec.get("ports", []): + if port.get("state_state") == "open": + result.setdefault("openports", set()).add( + "%(protocol)s/%(port)d" % port + ) + if port.get("service_name"): + result.setdefault("services", set()).add(port["service_name"]) + if port.get("service_product"): + result.setdefault("products", set()).add(port["service_product"]) + for script in port.get("scripts", []): + if script["id"] == "ssl-cert": + for cert in script.get("ssl-cert", []): + result.setdefault("certs", set()).add( + ( + cert["subject_text"], + cert["issuer_text"], + cert["md5"], + cert["sha1"], + cert["sha256"], + ) + ) + for subr in (all_results.values() if self.keep_addresses else [result]): + self.clean_results(subr) + if self.keep_addresses: + return [{"addr": addr, "data": data} for addr, data in all_results.items()] + return result + + def get_passive(self, dbase): + if self.keep_addresses: + all_results = {} + else: + result = {} + for rec in DATABASES[dbase].get(self.flt(dbase)): + if self.keep_addresses: + result = all_results.setdefault(rec["addr"], {}) + firstseen = rec.get('firstseen', rec.get('lastseen')) + lastseen = rec.get('lastseen', rec.get('firstseen')) + if firstseen: + if "firstseen" in result: + result["firstseen"] = min(result["firstseen"], firstseen) + else: + result["firstseen"] = firstseen + if lastseen: + if "lastseen" in result: + result["lastseen"] = min(result["lastseen"], firstseen) + else: + result["lastseen"] = firstseen + recontype = rec["recontype"] + result.setdefault("categories", set()).add(recontype) + if rec.get("sensor"): + result.setdefault("source", set()).add(rec["sensor"]) + if recontype == 'DNS_ANSWER': + result.setdefault("hostnames", set()).add(rec["value"]) + self.analyzer._artifacts.add(("fqdn", rec["value"])) + continue + if recontype == 'OPEN_PORT': + port = rec["value"] + try: + protocol, port = port.split('/', 1) + except ValueError: + protocol = "tcp" + port = int(port) + result.setdefault("openports", set()).add( + "%s/%d" % (protocol, port) + ) + continue + if recontype in {"TCP_SERVER_BANNER", "SSH_SERVER", "HTTP_SERVER_HEADER"}: + result.setdefault("openports", set()).add("tcp/%(port)d" % rec) + if "infos" not in rec: + continue + info = rec["infos"] + if info.get("service_name"): + result.setdefault("services", set()).add(info["service_name"]) + if info.get("service_product"): + result.setdefault("products", set()).add(info["service_product"]) + continue + if recontype == "SSL_SERVER": + if recontype != "cert": + # not handled yet + continue + if "infos" not in rec: + continue + cert = rec["infos"] + result.setdefault("certs", set()).add( + ( + cert["subject_text"], + cert["issuer_text"], + cert["md5"], + cert["sha1"], + cert["sha256"], + ) + ) + self.analyzer._artifacts.add(("certificate_hash", cert["sha1"])) + continue + for subr in (all_results.values() if self.keep_addresses else [result]): + self.clean_results(subr) + if self.keep_addresses: + return [{"addr": addr, "data": data} for addr, data in all_results.items()] + return result + + @staticmethod + def clean_results(result): + for key, value in result.items(): + if isinstance(value, datetime): + result[key] = str(value) + if isinstance(value, set): + if key == "ports": + result[key] = sorted( + value, + key=lambda x: [ + [str, int][i](y) for i, y in enumerate(x.split("/", 1)) + ], + ) + elif key == "certs": + result[key] = [ + dict( + zip( + ["subject", "issuer", "md5", "sha1", "sha256"], cert + ) + ) + for cert in sorted(value) + ] + else: + result[key] = sorted(value) + + def get(self, dbase): + if dbase == "data": + result = DATABASES[dbase].infos_byip(self.data) + if "as_num" in result: + self.analyzer._artifacts.add(("autonomous-system", result["as_num"])) + return result + if dbase == "scans": + return self.get_scans(dbase) + if dbase == "passive": + return self.get_passive(dbase) + raise ValueError() + + +class ProcessorNet(ProcessorIp): + """Network processor + + data is a network, output is similar to ProcessorIp. + + """ + + databases = ["passive", "scans"] + keep_addresses = True + + def flt(self, dbase): + return DATABASES[dbase].searchnet(self.data) + + +class ProcessorAsnum(ProcessorNet): + """AS number processor + + data is an AS number, output is similar to ProcessorIp. + + """ + + def flt(self, dbase): + return DATABASES[dbase].searchasnum(int(self.data)) + + +class ProcessorPort(Processor): + + databases = ["passive", "scans"] + + def flt(self, dbase): + if "/" in self.data: + proto, port = self.data.split("/", 1) + port = int(port) + else: + proto = "tcp" + port = int(self.data) + if proto != "udp" and dbase == "passive": + return DATABASES[dbase].searchnonexistent() + return DATABASES[dbase].searchport(port, protocol=proto) + + +class ProcessorCert(Processor): + + databases = ["passive", "scans"] + + def flt(self, dbase): + return DATABASES[dbase].searchcert( + **{{32: "md5", 40: "sha1", 64: "sha256"}[len(self.data)]: self.data} + ) + + +class ProcessorFqdn(Processor): + + databases = ["passive", "scans"] + + def flt(self, dbase): + if dbase == "passive": + return DATABASES[dbase].searchdns(name=self.data) + return DATABASES[dbase].searchhostname(self.data) + + def rev_flt(self, dbase): + return DATABASES[dbase].searchdns(name=self.data, reverse=True) + + def get(self, dbase): + if dbase == "passive": + # specific case: two filters (w/ & w/o reverse=True) + result = sorted( + DATABASES[dbase].distinct("value", flt=self.rev_flt(dbase)), + key=lambda v: v.strip().split(".")[::-1], + ) + self.analyzer._artifacts.update(("fqdn", value) for value in result) + return super().get(dbase) + result + return super().get(dbase) + + +class ProcessorDomain(ProcessorFqdn): + def flt(self, dbase): + if dbase == "passive": + return DATABASES[dbase].searchdns(name=self.data, subdomains=True) + return DATABASES[dbase].searchdomain(self.data) + + def rev_flt(self, dbase): + return DATABASES[dbase].searchdns(name=self.data, subdomains=True, reverse=True) + + +class ProcessorUserAgent(Processor): + + databases = ["passive"] + + def flt(self, dbase): + return dbase.searchuseragent(self.data) + + +class IVREAnalyzer(Analyzer): + def __init__(self): + Analyzer.__init__(self) + self._artifacts = set() + + @staticmethod + def summary(raw): + return {"results": sorted(raw) or None} + + def artifacts(self, raw): + return [{"type": atype, "value": value} + for atype, value in sorted(self._artifacts)] + + def run(self): + self.report(Processor.from_analyzer(self).run()) + + +if __name__ == "__main__": + IVREAnalyzer().run() diff --git a/analyzers/IVRE/requirements.txt b/analyzers/IVRE/requirements.txt new file mode 100644 index 000000000..0c29adb96 --- /dev/null +++ b/analyzers/IVRE/requirements.txt @@ -0,0 +1,2 @@ +cortexutils +ivre