From 2ec63778d32b49f8d2efcd19801be7e7fe614a8a Mon Sep 17 00:00:00 2001 From: doomedraven Date: Wed, 8 Feb 2023 12:42:12 +0100 Subject: [PATCH] misp --- lib/cuckoo/common/integrations/misp.py | 174 ++++++++++++++++++++++ web/templates/analysis/generic/_misp.html | 131 ++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 lib/cuckoo/common/integrations/misp.py create mode 100644 web/templates/analysis/generic/_misp.html diff --git a/lib/cuckoo/common/integrations/misp.py b/lib/cuckoo/common/integrations/misp.py new file mode 100644 index 00000000..33a7d047 --- /dev/null +++ b/lib/cuckoo/common/integrations/misp.py @@ -0,0 +1,174 @@ +# Disclaimer this code is not maintained by core devs +# pymisp is known to break api on updates. +# So you need it? You fix it! + +import os +import json +import logging + +from lib.cuckoo.common.config import Config +from lib.cuckoo.common.constants import CUCKOO_ROOT + +try: + from pymisp import PyMISP + from pymisp import logger as pymisp_logger + + pymisp_logger.setLevel(logging.ERROR) + HAVE_MISP = True +except ImportError: + print("Missed pymisp dependency. Run: poetry run pip install pymisp==2.4.168") + HAVE_MISP = False + +log = logging.getLogger() + +external_cfg = Config("externalservices") +misp_url = "" +MISP_HASH_LOOKUP = False + +if HAVE_MISP: + misp_url = external_cfg.misp.url + misp = PyMISP(misp_url, external_cfg.misp.apikey, False, "json") + MISP_HASH_LOOKUP = external_cfg.misp.hash_lookup + + +def misp_hash_lookup(sha256: str, task_id: str, file_info: dict): + + if not MISP_HASH_LOOKUP: + return + + # Initialize MISP Variables + threat_actor_tag = "" + threat_actor = "Not Applicable" + threat_actor_list = [] + threat_actor_dict = {} + event_link = [] + link_list = [] + event_tag = "" + tag_dict = {} + tag = "" + related_events_dict = {} + galaxy_cluster_dict = {} + + # Search MISP for any events with attributes having the same hash as the submitted sample + response = misp.search("attributes", value=sha256, return_format="json", pythonify=True) + + # For exporting of MISP Attribute and MISP Event JSON File + attribute_json_response = misp.search("attributes", value=sha256, return_format="json", includeCorrelations=1) + event_json_response = misp.get_event(response[0].event_id, pythonify=False) + try: + analysis_path = os.path.join(CUCKOO_ROOT, "storage", "analyses", task_id) + attribute_json = json.dumps(attribute_json_response, indent=4) + with open(os.path.join(analysis_path, "misp_attribute.json"), "w") as outfile: + outfile.write(attribute_json) + event_json = json.dumps(event_json_response, indent=4) + with open(os.path.join(analysis_path, "misp_event.json"), "w") as outfile: + outfile.write(event_json) + except Exception as e: + log.error("Exporting of MISP JSON Files have been skipped: " + e) + + # Retrieve desired information regarding the event if there is a relevant response + if response: + event = misp.get_event(response[0].event_id, pythonify=True) + event_link = f"{misp_url}/events/view/" + str(response[0].event_id) + galaxy_link = f"{misp_url}/galaxy_clusters/view/" + search_tag_link = f"{misp_url}/events/index/searchtag:" + ids_links = [ + (f"{misp_url}/events/nids/snort/download/{response[0].event_id}"), + (f"{misp_url}/events/nids/suricata/download/{response[0].event_id}"), + ] + event_info = str(event).split("info=")[1].rsplit(")", 1)[0] + + log.debug("Submitted samples is related to MISP event: %s", str(event)) + for attribute in event["Attribute"]: + if "type=link" in str(attribute): + link_list = [value for key, value in attribute.items() if key == "value"] + + # Get descriptions for Galaxy Clusters that match associated Tags + for galaxy in event["Galaxy"]: + for key, value in galaxy.items(): + galaxy_cluster_dict = { + cluster["value"].title(): [cluster["id"], cluster["description"]] for cluster in value if key == "GalaxyCluster" + } + + for tag in event["Tag"]: + event_tag_dict = {} + event_tag = "" + # Iterate through every tag to get the tag key and value for display in web UI + for key, value in tag.items(): + if any(pattern in str(tag) for pattern in ("threat-actor", "intrusion-set", "group")): + threat_actor_tag = str(tag) + threat_actor = threat_actor_tag.split('="')[1].split('")>')[0] + threat_actor_list.append(threat_actor) + # Filter out irrelevant tags + elif key == "id" and any(pattern not in str(tag) for pattern in ("workflow", "tlp", "type", "osint", "OSINT")): + # e.g. mitre-attack-pattern + event_tag_name = str(tag).split("name=")[1].split('")>')[0].split(":")[1].split('="')[0].title() + # e.g. Symmetric Cryptography - T1573.001 + event_tag = str(tag).split("name=")[1].split('")>')[0].split(":")[1].split('="')[1].title() + if event_tag in galaxy_cluster_dict: + event_tag_dict[event_tag] = [value, galaxy_cluster_dict[event_tag][1]] + else: + event_tag_dict[event_tag] = [value, 0] + if event_tag_name not in tag_dict.keys(): + tag_dict[event_tag_name] = event_tag_dict + else: + # e.g. 'Mitre-Enterprise-Attack-Intrusion-Set': {'Dragonok - G0017': ['1099', '...'], 'Winnti Group - G0044': ['1107', '...']} + tag_dict[event_tag_name].update(event_tag_dict) + # Get a list of MISP event/s related to the current MISP event (if any) + related_events = event["RelatedEvent"] + for related_event in related_events: + for key, value in related_event.items(): + related_event_dict = {} + dict_id = misp_url + "/events/view/" + str(value["id"]) + related_event_dict[dict_id] = value["info"] + related_events_dict.update(related_event_dict) + + # initialize list of threat actors + all_threat_actors = [] + all_intrusion_sets = [] + all_enterprise_attack_intrusion_sets = [] + all_microsoft_activity_groups = [] + + try: + # Search for threat actor description (id 59 --> misp threat actor galaxy) + all_threat_actors = misp.search_galaxy_clusters(59) + # Search for intrusion set description (id 35 --> misp intrusion set galaxy) + all_intrusion_sets = misp.search_galaxy_clusters(35) + # Search for enterprise attack intrusion set description (id 26 --> enterprise attack intrusion set galaxy) + all_enterprise_attack_intrusion_sets = misp.search_galaxy_clusters(26) + # Search for microsoft activity groups description (id 20 --> microsoft activity groups galaxy) + all_microsoft_activity_groups = misp.search_galaxy_clusters(20) + # CURRENTLY USELESS BECAUSE NO ASSOCIATION WITH CURRENT EVENTS + # # Search for 360.net threat actors description (id 1 --> 360.net threat actor galaxy) + # all_360net_threat_actors = misp.search_galaxy_clusters(1) + except Exception as e: + log.error("Could not access MISP Galaxy Information: %s", str(e)) + + all_galaxies = all_threat_actors + all_intrusion_sets + all_enterprise_attack_intrusion_sets + all_microsoft_activity_groups + + # Loop through list of threat actor(s) to retrieve their description(s) + for threat_actor in threat_actor_list: + # this line will ensure that threat actors appear even if they do not have related description in MISP + threat_actor_dict[threat_actor] = [0, 0] + for galaxy_cluster in all_galaxies: + if galaxy_cluster["GalaxyCluster"]["value"] == threat_actor: + # e.g. "threat_actor" : { "Sofacy" : [ "The Sofacy Group is ..." , "9926" ] } + threat_actor_dict[threat_actor] = [ + galaxy_cluster["GalaxyCluster"]["description"], + galaxy_cluster["GalaxyCluster"]["id"], + ] + + + file_info.setdefault("misp", {}) + file_info["misp"] = { + "threat_actor": threat_actor_dict, + "event_link": event_link, + "event_info": event_info, + "event_tags": tag_dict, + "galaxy_link": galaxy_link, + "search_tag_link": search_tag_link, + "ids_links": ids_links, + "links": link_list, + "related_events": related_events_dict, + "url": misp_url, + } diff --git a/web/templates/analysis/generic/_misp.html b/web/templates/analysis/generic/_misp.html new file mode 100644 index 00000000..2f0ebbfa --- /dev/null +++ b/web/templates/analysis/generic/_misp.html @@ -0,0 +1,131 @@ +{% load key_tags %} + +{% if file.misp.event_link %} +
+
+
+ +
+
+ {% if file.misp.event_info %} + +

+

{{file.misp.event_info}}

+ {% endif %} + + + {% if file.misp.related_events %} + + + + + {% endif %} + {% if file.misp.threat_actor %} + + + + + {% endif %} + {% if file.misp.event_tags %} + {% for tag_name, tag_value in file.misp.event_tags.items %} + + {% if tag_name == "Topic" %} + + {% elif tag_name == "Malware-Category" %} + + {% elif tag_name == "Mitre-Enterprise-Attack-Malware" %} + + {% elif tag_name == "Mitre-Malware" %} + + {% elif tag_name == "Tool" %} + + {% elif tag_name == "Incident-Classification" %} + + {% elif tag_name == "Mitre-Enterprise-Attack-Attack-Pattern" %} + + {% elif tag_name == "Mitre-Attack-Pattern" %} + + {% elif tag_name == "Rat" %} + + {% elif tag_name == "Confidence-In-Analytic-Judgment" %} + + {% elif tag_name == "Sector" %} + + {% elif tag_name == "Country" %} + + {% elif tag_name == "Target-Information" %} + + {% elif tag_name == "Malpedia" %} + + {% elif tag_name == "Lifetime" %} + + {% elif tag_name == "Certainty" %} + + {% elif tag_name == "Backdoor" %} + + {% else %} + + {% endif %} + + + {% endfor %} + {% endif %} + {% if file.misp.links %} + + + + + {% endif %} +
Related Events [{{file.misp.related_events|length}}] +
    + {% for event_link, event_info in file.misp.related_events.items %} +
  • {{event_info}}
  • + {% endfor %} +
+
Threat Actor(s) [{{file.misp.threat_actor|length}}] + +
  Topic(s) [{{tag_value|length}}]  Malware Categorie(s) [{{tag_value|length}}] MITRE Enterprise Attack Malware [{{tag_value|length}}] MITRE Malware [{{tag_value|length}}]  Tool(s) [{{tag_value|length}}]  Incident Classification(s) [{{tag_value|length}}]  MITRE Enterprise Attack Pattern(s) [{{tag_value|length}}]  MITRE Attack Pattern(s) [{{tag_value|length}}]  Remote Access Tool(s) [{{tag_value|length}}] Confidence in Analytic Judgment  Sectors Involved [{{tag_value|length}}] Countries [{{tag_value|length}}] Target(s) Information [{{tag_value|length}}] Malpedia Archives Information [{{tag_value|length}}] Lifetime Certainty Backdoor(s) [{{tag_value|length}}]{{tag_name}} +
    + {% for event_tag, event_tag_value in tag_value.items %} + {% if 'str' in event_tag_value|gettype %} +
  • {{event_tag}}
  • + {% else %} + {% if 'int' in event_tag_value.1|gettype %} +
  • {{event_tag}}
  • + {% else %} +
  • {{event_tag}}
  • + {% endif %} + {% endif %} + {% endfor %} +
+
External Analysis Link(s) [{{file.misp.links|length}}] +
    + {% for link in file.misp.links %} +
  • {{link}}
  • + {% endfor %} +
+
+
+
+{% endif %}