diff --git a/analyzers/NSRL/NSRL.json b/analyzers/NSRL/NSRL.json new file mode 100644 index 000000000..526207cb2 --- /dev/null +++ b/analyzers/NSRL/NSRL.json @@ -0,0 +1,37 @@ +{ + "name": "NSRL", + "author": "Andrea Garavaglia, Davide Arcuri - LDO-CERT", + "license": "AGPL-V3", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "version": "1.0", + "description": "Query NSRL", + "dataTypeList": [ + "hash", + "filename" + ], + "baseConfig": "NSRL", + "command": "NSRL/nsrl.py", + "configurationItems": [ + { + "name": "conn", + "description": "sqlalchemy connection string", + "multi": false, + "required": false, + "type": "string" + }, + { + "name": "grep_path", + "description": "path of grep", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "nsrl_folder", + "description": "path of NSRL folder", + "type": "string", + "multi": false, + "required": false + } + ] +} \ No newline at end of file diff --git a/analyzers/NSRL/create_db.py b/analyzers/NSRL/create_db.py new file mode 100644 index 000000000..0dcd48dd2 --- /dev/null +++ b/analyzers/NSRL/create_db.py @@ -0,0 +1,43 @@ +import os +import sqlalchemy as db +from glob import glob + +conn_string = "" +NSRL_folder_path = "/path/to/NSRLFolder/*" + +engine = db.create_engine(conn_string) +metadata = db.MetaData() + +nsrl = db.Table( + "nsrl", + metadata, + db.Column("id", db.Integer, primary_key=True, autoincrement=True), + db.Column("sha1", db.String), + db.Column("md5", db.String), + db.Column("crc32", db.String), + db.Column("filename", db.String), + db.Column("filesize", db.String), + db.Column("productcode", db.String), + db.Column("opsystemcode", db.String), + db.Column("specialcode", db.String), + db.Column("dbname", db.String), + db.Column("release", db.String), + db.Index("idx_sha1", "sha1"), + db.Index("idx_md5", "md5"), +) +metadata.create_all(engine) + +conn = engine.raw_connection() +cursor = conn.cursor() +for NSRL_file_path in glob(NSRL_folder_path): + dbname, release = NSRL_file_path.split("/")[-1].replace(".txt","").split("_") + print(dbname, release) + with open(NSRL_file_path, "r", encoding="latin-1") as f: + cmd = 'COPY nsrl("sha1", "md5", "crc32", "filename", "filesize", "productcode", "opsystemcode", "specialcode") FROM STDIN WITH (FORMAT CSV, DELIMITER ",", HEADER TRUE)' + cursor.copy_expert(cmd, f) + conn.commit() + engine.execute("update nsrl set dbname='%s', release='%s' where dbname is null" % (dbname, release)) + conn.commit() +cursor.close() +conn.close() +engine.dispose() \ No newline at end of file diff --git a/analyzers/NSRL/nsrl.py b/analyzers/NSRL/nsrl.py new file mode 100755 index 000000000..98ee4627a --- /dev/null +++ b/analyzers/NSRL/nsrl.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +# encoding: utf-8 +import re +import os +import subprocess +from cortexutils.analyzer import Analyzer + +try: + import sqlalchemy as db + + USE_DB = True +except ImportError: + USE_DB = False + +FIELDS = [ + "sha1", + "md5", + "crc32", + "filename", + "filesize", + "productcode", + "opsystemcode", + "specialcode", +] + + +class NsrlAnalyzer(Analyzer): + def __init__(self): + Analyzer.__init__(self) + conn = self.get_param("config.conn", None) + self.engine = None + self.grep_path = self.get_param("config.grep_path", None) + self.nsrl_folder = self.get_param("config.nsrl_folder", None) + + if conn and USE_DB: + self.engine = db.create_engine(conn) + elif self.grep_path and self.nsrl_folder: + pass + else: + self.error("No valid configuration found") + + def summary(self, raw): + taxonomies = [] + if raw["found"]: + taxonomies.append(self.build_taxonomy("safe", "NSRL", "lookup", "found")) + else: + taxonomies.append( + self.build_taxonomy("info", "NSRL", "lookup", "not found") + ) + return {"taxonomies": taxonomies} + + def run(self): + Analyzer.run(self) + + data = self.get_param("data", None, "Data is missing") + data = data.upper() + + if self.data_type not in ['filename', "hash"]: + self.error("Invalid data type") + + if self.data_type == 'hash': + + md5_re = re.compile(r"^[a-f0-9]{32}(:.+)?$", re.IGNORECASE) + sha1_re = re.compile(r"^[a-f0-9]{40}(:.+)?$", re.IGNORECASE) + + if md5_re.match(data): + variable = "md5" + elif sha1_re.match(data): + variable = "sha1" + else: + self.error("Invalid hash type") + + else: + variable = "filename" + + results = {} + results["records"] = [] + if not self.engine: + if not os.path.exists(self.nsrl_folder) and not os.path.isdir( + self.nsrl_folder + ): + self.error("NSRL folder not found or not valid") + try: + output = subprocess.Popen( + [self.grep_path, "-r", "-i", data, self.nsrl_folder], + stdout=subprocess.PIPE, + universal_newlines=True, + ) + for line in output.stdout.readlines(): + tmp = {} + file_path, values = line.strip().split(":") + values = [ + x.replace('"', "") for x in values.split(",") + ] + for key, value in zip(FIELDS, values): + tmp[key] = value + tmp["dbname"], tmp["release"] = ( + file_path.split("/")[-1].replace(".txt", "").split("_") + ) + results["records"].append(tmp) + results["found"] = True + except subprocess.CalledProcessError as e: + results["found"] = False + results["mode"] = "file" + + else: + if variable != 'filename': + sql = "SELECT %s FROM nsrl WHERE %s='%s'" % ( + ", ".join(FIELDS + ["dbname", "release"]), + variable, + data + ) + else: + sql = "SELECT %s FROM nsrl WHERE %s ilike '%s'" % ( + ", ".join(FIELDS + ["dbname", "release"]), + variable, + "%%{}%%".format(data) + ) + values = self.engine.execute(sql) + self.engine.dispose() + if values.rowcount > 0: + for row in values: + results["records"].append( + { + key: value + for (key, value) in zip(FIELDS + ["dbname", "release"], row) + } + ) + results["found"] = True + else: + results["found"] = False + results["mode"] = "db" + + self.report(results) + + +if __name__ == "__main__": + NsrlAnalyzer().run() diff --git a/analyzers/NSRL/requirements.txt b/analyzers/NSRL/requirements.txt new file mode 100644 index 000000000..b060f9ec3 --- /dev/null +++ b/analyzers/NSRL/requirements.txt @@ -0,0 +1,3 @@ +cortexutils +sqlalchemy +psycopg2-binary diff --git a/thehive-templates/NSRL_Lookup_1_0/long.html b/thehive-templates/NSRL_Lookup_1_0/long.html new file mode 100644 index 000000000..c35927f68 --- /dev/null +++ b/thehive-templates/NSRL_Lookup_1_0/long.html @@ -0,0 +1,53 @@ +
+ +
+ NSRL lookup +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Sha1md5crc32File NameFile SizeProduct CodeOperating System CodeSpecial CodeModeNSRL File Name
{{result.sha1}}{{result.md5}}{{result.crc32}}{{result.filename}}{{result.filesize}}{{result.productcode}}{{result.opsystemcode}}{{result.specialcode}}{{content.mode}}{{result.dbname}} {{result.release}}
+
+
+ +
+
+ NSRL lookup: No match found +
+
+ + +
+
+ FNSRL lookup Error +
+
+
+
Error:
+
{{content.errorMessage}}
+
+
+
\ No newline at end of file diff --git a/thehive-templates/NSRL_Lookup_1_0/short.html b/thehive-templates/NSRL_Lookup_1_0/short.html new file mode 100644 index 000000000..5fc0dabfb --- /dev/null +++ b/thehive-templates/NSRL_Lookup_1_0/short.html @@ -0,0 +1,3 @@ + + {{t.namespace}}:{{t.predicate}}="{{t.value}}" +