Repository: kevoreilly/CAPEv2

Issue:
Relying on a very outdated version of PyMISP
Someone mentioned an issue related to PyMISP using CAPEv2 and it seems that you're relying on an extremely outdated version of the API: most of the methods you're using have been spitting deprecation warning for over a year by now, and the PyMISP packages released after 2020-01-01 do not support them anymore at all.

I will try to provide a PR (if you're interested), but as I'm not using CAPEv2, I cannot promise the accuracy of the code.


Discussion:
hello @Rafiot, thanks, ya pymisp in my memory is always broken in cuckoo/cuckoo-modified/cape/capev2, is why i hardcoded a pymisp version, due to deprication of X, so i just stopped to follow and try to keep it up to date, if you can do that would be amazing as it would make a lot of people happy to be able to use latest pymisp, and i have few testers that have capev2 integrated with their misp so they can test it
i can fix code accuracy, what I just need is the correct pymisp calls to register the data

Resolving patch:
diff --git a/modules/reporting/misp.py b/modules/reporting/misp.py
--- a/modules/reporting/misp.py
+++ b/modules/reporting/misp.py
@@ -1,16 +1,10 @@
+# -*- coding: utf-8 -*-
 # Copyright (C) 2010-2015 Cuckoo Foundation.
 # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
 # See the file 'docs/LICENSE' for copying permission.
 
-"""
-  (1,"High","*high* means sophisticated APT malware or 0-day attack","Sophisticated APT malware or 0-day attack"),
-  (2,"Medium","*medium* means APT malware","APT malware"),
-  (3,"Low","*low* means mass-malware","Mass-malware"),
-  (4,"Undefined","*undefined* no risk","No risk");
-"""
-
-#Updated by doomedraven 30.11.2019 for NaxoneZ
-#Updated by NaxoneZ 20.12.2019 for the rest of the world :)
+# Updated by doomedraven 30.11.2019 for NaxoneZ
+# Updated by NaxoneZ 20.12.2019 for the rest of the world :)
 
 import os
 import logging
@@ -20,11 +14,17 @@
 from lib.cuckoo.common.config import Config
 from lib.cuckoo.common.abstracts import Report
 from lib.cuckoo.common.constants import CUCKOO_ROOT
-from urllib.parse import urlsplit
+
+"""
+  (1,"High","*high* means sophisticated APT malware or 0-day attack","Sophisticated APT malware or 0-day attack"),
+  (2,"Medium","*medium* means APT malware","APT malware"),
+  (3,"Low","*low* means mass-malware","Mass-malware"),
+  (4,"Undefined","*undefined* no risk","No risk");
+"""
+
 
 try:
-    import pymisp
-    from pymisp import MISPEvent, MISPAttribute
+    from pymisp import MISPEvent, PyMISP, MISPObject
     HAVE_PYMISP = True
 except ImportError:
     HAVE_PYMISP = True
@@ -53,24 +53,21 @@ def signature(self, results, event):
             for i in ttps_json.get("objects", []) or []:
                 try:
                     if i["external_references"][0]["external_id"] == ttp:
-                        self.misp.tag(event["uuid"], 'misp-galaxy:mitre-attack-pattern="'+i["name"]+' - '+ttp+'"')
-                except:
+                        self.misp.tag(event, f'misp-galaxy:mitre-attack-pattern="{i["name"]}-{ttp}"')
+                except Exception:
                     pass
 
-    #DeprecationWarning: Call to deprecated method add_hashes. (Use ExpandedPyMISP.add_attribute and MISPAttribute)
     def sample_hashes(self, results, event):
         if results.get("target", {}).get("file", {}):
             f = results["target"]["file"]
-            self.misp.add_hashes(
-                event,
-                category="Payload delivery",
-                filename=f["name"],
-                md5=f["md5"],
-                sha1=f["sha1"],
-                sha256=f["sha256"],
-                ssdeep=f["ssdeep"],
-                comment="File submitted to CAPEv2",
-            )
+            misp_object = MISPObject('file')
+            misp_object.comment = "File submitted to CAPEv2"
+            misp_object.add_attribute('filename', value=f["name"], category='Payload delivery')
+            misp_object.add_attribute('md5', value=f["md5"], category='Payload delivery')
+            misp_object.add_attribute('sha1', value=f["sha1"], category='Payload delivery')
+            misp_object.add_attribute('sha256', value=f["sha256"], category='Payload delivery')
+            misp_object.add_attribute('ssdeep', value=f["ssdeep"], category='Payload delivery')
+            self.misp.add_object(event, misp_object)
 
     def all_network(self, results, event):
         """All of the accessed URLS as per the PCAP."""
@@ -81,8 +78,7 @@ def all_network(self, results, event):
                 if "uri" in req and req["uri"] not in whitelist:
                     urls.add(req["uri"])
                 if "user-agent" in req:
-                    #self.misp.add_useragent(event, req["user-agent"])
-                    self.misp.add_named_attribute(event, 'user-agent', req["user-agent"])#, category, to_ids, comment, distribution, proposal, **kwargs)
+                    event.add_attribute('user-agent', req["user-agent"])
 
             domains, ips = {}, set()
             for domain in results.get("network", {}).get("domains", []):
@@ -94,14 +90,14 @@ def all_network(self, results, event):
                 if block["ip"] not in whitelist:
                     ips.add(block["ip"])
 
-            for block in results["network"].get("dns", []): #Added DNS
+            for block in results["network"].get("dns", []):  # Added DNS
                 if block.get("request", "") and (block["request"] not in whitelist):
                     if block["request"] not in domains and block["request"] not in whitelist:
                         if block["answers"]:
                             domains[block["request"]] = block["answers"][0]["data"]
                             ips.add(domain[block["answers"][0]["data"]])
 
-            #Added CAPE Addresses
+            # Added CAPE Addresses
             for section in results.get("CAPE", []) or []:
                 try:
                     if section.get("cape_config", {}).get("address", []) or []:
@@ -111,12 +107,17 @@ def all_network(self, results, event):
                 except Exception as e:
                     print(e)
 
-            if urls:
-                self.misp.add_named_attribute(event, 'url', sorted(list(urls)))
-            if domains:
-                self.misp.add_domains_ips(event, domains)
-            if ips:
-                self.misp.add_named_attribute(event, 'ip-dst', sorted(list(ips)))#, category, to_ids, comment, distribution, proposal, **kwargs)
+            for url in sorted(list(urls)):
+                event.add_attribute('url', url)
+            for ip in sorted(list(ips)):
+                event.add_attribute('ip-dst', ip)
+            for domain, ips in domains.items():
+                obj = MISPObject('domain-ip')
+                obj.add_attribute('domain', domain)
+                for ip in ips:
+                    obj.add_attribute('ip', ip)
+                event.add_object(obj)
+            self.misp.update_event(event)
 
     def dropped_files(self, results, event):
         """
@@ -131,9 +132,12 @@ def dropped_files(self, results, event):
         Add all the dropped files as MISP attributes.
         """
         # Upload all the dropped files at once
+        # TODO: Use expanded
         for r in results.get("dropped", []) or []:
             with open(r.get("path"), 'rb') as f:
                 event.add_attribute('malware-sample', value=os.path.basename(r.get("path")), data=BytesIO(f.read()), expand='binary')
+        event.run_expansions()
+        self.misp.update_event(event)
         """
         # Load the event from MISP (we cannot use event as it
         # does not contain the sample uploaded above, nor it is
@@ -164,16 +168,11 @@ def dropped_files(self, results, event):
         self.misp.update_event(event_id=event["Event"]["id"], event=e)
         """
 
-
     def run(self, results):
         """Run analysis.
         @return: MISP results dict.
         """
 
-        if pymisp.__version__ != '2.4.117.3':
-            log.warning("Unsuported version of pymisp detected, please install pymisp=2.4.117.3 or upgrade this code for latest pymisp")
-            return
-
         url = self.options.get("url", "")
         apikey = self.options.get("apikey", "")
 
@@ -181,7 +180,7 @@ def run(self, results):
             log.error("MISP URL or API key not configured.")
             return
 
-        self.misp = pymisp.ExpandedPyMISP(url, apikey, False, "json")
+        self.misp = PyMISP(url, apikey, False, "json")
 
         self.threads = self.options.get("threads", "")
         if not self.threads:
@@ -203,12 +202,11 @@ def run(self, results):
                 if results.get("detections", ""):
                     malfamily = results["detections"]
 
-                event = MISPEvent()
-                response = self.misp.search("attributes", value=results["target"]["file"]["sha256"], return_format="json")
+                response = self.misp.search("attributes", value=results["target"]["file"]["sha256"], return_format="json", pythonify=True)
                 if response.get("Attribute", []):
-                    res = self.misp.get_event(response["Attribute"][0]["event_id"])["Event"]
-                    event.load(res)
+                    event = self.misp.get_event(response[0].event_id, pythonify=True)
                 else:
+                    event = MISPEvent()
                     event.distribution = distribution
                     event.threat_level_id = threat_level_id
                     event.analysis = analysis
@@ -217,30 +215,27 @@ def run(self, results):
 
                 # Add a specific tag to flag Cuckoo's event
                 if tag:
-                    self.misp.tag(event["uuid"], tag)
-
+                    self.misp.tag(event, tag)
 
-                #ToDo?
+                # ToDo?
                 self.signature(results, event)
 
                 self.sample_hashes(results, event)
                 self.all_network(results, event)
                 self.dropped_files(results, event)
 
-
-                #DeprecationWarning: Call to deprecated method upload_samplelist. (Use MISPEvent.add_attribute with the expand='binary' key)
                 if upload_sample:
                     target = results.get("target", {})
                     f = target.get("file", {})
                     if target.get("category") == "file" and f:
                         with open(f["path"], 'rb') as f:
-                            event.add_attribute('malware-sample', value=os.path.basename(f["path"]), data=BytesIO(f.read()), expand='binary', comment="Sample run",)
+                            event.add_attribute('malware-sample', value=os.path.basename(f["path"]), data=BytesIO(f.read()), expand='binary', comment="Sample run")
 
                 if results.get("target", {}).get("url", "") and results["target"]["url"] not in whitelist:
-                    self.misp.add_named_attribute(event, 'url', [results["target"]["url"]])
+                    event.add_attribute('url', results["target"]["url"])
 
                 # ToDo migth be outdated!
-                #if self.options.get("ids_files", False) and "suricata" in results.keys():
+                # if self.options.get("ids_files", False) and "suricata" in results.keys():
                 #    for surifile in results["suricata"]["files"]:
                 #        if "file_info" in surifile.keys():
                 #            self.misper["iocs"].append({"md5": surifile["file_info"]["md5"]})
@@ -251,17 +246,19 @@ def run(self, results):
                     if "mutexes" in results.get("behavior", {}).get("summary", {}):
                         for mutex in results["behavior"]["summary"]["mutexes"]:
                             if mutex not in whitelist:
-                               self.misp.add_mutex(event, mutex)
+                                event.add_attribute('mutex', mutex)
 
                 if self.options.get("registry", False) and "behavior" in results and "summary" in results["behavior"]:
                     if "read_keys" in results["behavior"].get("summary", {}):
                         for regkey in results["behavior"]["summary"]["read_keys"]:
-                            self.misp.add_regkey(event, regkey)
+                            event.add_attribute('regkey', regkey)
+
+                event.run_expansions()
+                self.misp.update_event(event)
 
-                #Make event public
+                # Make event public
                 if self.options.get("published", True):
-                   event.published = True
-                   self.misp.publish(event)
+                    self.misp.publish(event)
 
         except Exception as e:
             log.error("Failed to generate JSON report: %s" % e, exc_info=True)


Test patch: