Beispiel #1
0
    def init_once(cls):
        """Connect to Elasticsearch.
        @raise CuckooReportError: if unable to connect.
        """
        # Do not change these types without changing the elasticsearch
        # template as well.
        cls.report_type = "cuckoo"
        cls.call_type = "call"

        if not elastic.init():
            return

        cls.template_name = "%s_template" % elastic.index

        try:
            elastic.connect()
        except CuckooOperationalError as e:
            raise CuckooReportError(
                "Error running ElasticSearch reporting module: %s" % e
            )

        # check to see if the template exists apply it if it does not
        if not elastic.client.indices.exists_template(cls.template_name):
            if not cls.apply_template():
                raise CuckooReportError("Cannot apply Elasticsearch template")
    def run(self, results):
        sigs, urls = [], []
        for sig in results.get("signatures", []):
            sigs.append(sig.get("name"))
            if sig.get("name") == "network_http":
                for http in sig.get("marks"):
                    urls.append(http.get("ioc"))

        post = "Finished analyze ::: [{0}]({1}{0}) ::: ".format(
            results.get("info", {}).get("id"),
            self.options.get("myurl")
        )

        if results.get("info", {}).get("category") == "file":
            target = results.get("target", {}).get("file", {}).get("name", "")
            if self.options.get("hash_filename"):
                target = hashlib.sha256(target).hexdigest()
        elif results.get("info", {}).get("category") == "url":
            target = results.get("target", {}).get("url", "")
            if self.options.get("hash_url"):
                target = hashlib.sha256(target).hexdigest()
        else:
            target = "???"

        post += "Target : {0} ::: Score : **{1}** ::: ".format(
            target, results.get("info", {}).get("score")
        )

        if self.options.get("show_virustotal"):
            post += "**VT : {0} / {1}**\n".format(
                results.get("virustotal", {}).get("positives"),
                results.get("virustotal", {}).get("total"),
            )

        if self.options.get("show_signatures"):
            post += "**Signatures** ::: {0} \n".format(" : ".join(sigs))

        if self.options.get("show_urls"):
            post += "**URLS**\n`{0}`".format(
                "\n".join(urls).replace(".", "[.]")
            )

        data = {
            "username": self.options.get("username"),
            "text": post,
        }

        try:
            r = requests.post(self.options.get("url"), json=data)

            # Note that POST max size is 4000 chars by default.
            if r.status_code != 200:
                raise CuckooReportError(
                    "Failed posting message due to : {0}".format(r.text)
                )
        except Exception as e:
            raise CuckooReportError(
                "Failed posting message to Mattermost: {0}".format(e)
            )
 def do_bulk_index(self, bulk_reqs):
     try:
         elasticsearch.helpers.bulk(elastic.client, bulk_reqs)
     except Exception as e:
         raise CuckooReportError(
             "Failed to save results in ElasticSearch for "
             "task #%d: %s" % (self.task["id"], e))
Beispiel #4
0
    def init_once(cls):
        if not mongo.init():
            return

        mongo.connect()
        cls.db = mongo.db
        cls.fs = mongo.grid

        # Set MongoDB schema version.
        if "cuckoo_schema" in mongo.collection_names:
            version = mongo.db.cuckoo_schema.find_one()["version"]
            if version != cls.SCHEMA_VERSION:
                raise CuckooReportError(
                    "Unknown MongoDB version schema version found. Cuckoo "
                    "doesn't really know how to proceed now.."
                )
        else:
            mongo.db.cuckoo_schema.save({"version": cls.SCHEMA_VERSION})

        # Set an unique index on stored files to avoid duplicates. As per the
        # pymongo documentation this is basically a no-op if the index already
        # exists. So we don't have to do that check ourselves.
        mongo.db.fs.files.ensure_index(
            "sha256", unique=True, sparse=True, name="sha256_unique"
        )
Beispiel #5
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        # Determine whether we want to include the behavioral data in the
        # JSON report.
        if "json.calls" in self.task["options"]:
            self.calls = int(self.task["options"]["json.calls"])
        else:
            self.calls = self.options.get("calls", True)

        self.erase_calls(results)
        try:
            filepath = os.path.join(self.reports_path, "report.json")
            with open(filepath, "wb", buffering=1024 * 1024) as report:
                json.dump(results,
                          report,
                          default=default,
                          sort_keys=False,
                          indent=self.options.indent,
                          encoding="latin-1")
        except (TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate JSON report: %s" % e)
        finally:
            self.restore_calls(results)
Beispiel #6
0
    def run(self, results):
        report = self.generate_jinja2_template(results)

        if self.options.get("html"):
            report_path = os.path.join(self.reports_path, "report.html")
            try:
                report_data = report
            except:
                report_data = report.encode('utf-8', 'replace')
            codecs.open(report_path, "wb").write(report_data)

        if self.options.get("pdf"):
            if not HAVE_WEASYPRINT:
                raise CuckooReportError(
                    "The weasyprint library hasn't been installed on your "
                    "Operating System and as such we can't generate a PDF "
                    "report for you. You can install 'weasyprint' manually "
                    "by running 'pip install weasyprint' or by compiling and "
                    "installing package yourself.")

            report_path = os.path.join(self.reports_path, "report.pdf")
            try:
                f = weasyprint.HTML(io.BytesIO(report.encode("utf8")))
            except:
                encoded_report = report.encode("utf-8")
                f = weasyprint.HTML(io.BytesIO(encoded_report))
            f.write_pdf(report_path)
Beispiel #7
0
    def run(self, results):
        try:
            dnspacket = getDNSData(self.analysis_path)
            goodIPs = getMicrosoftDomains(self.analysis_path)
            synConn = getSYNInfo(self.analysis_path, goodIPs)
            synackconn = getSYNACKInfo(self.analysis_path, goodIPs)
            ackConn = getACKInfo(self.analysis_path, goodIPs)
            resolvedIPsArray = resolvedIPs(self.analysis_path, goodIPs)
            fullHTTPArray = getFullHTTP(self.analysis_path, dnspacket)
            udpconn = getUDPData(self.analysis_path, goodIPs)
            icmpPacket = getICMPData(self.analysis_path)
            ftpconn = getFTPConn(self.analysis_path)
            sshconn = getSSHConn(self.analysis_path)
            foundIPs = findStaticIPs(results["strings"])
            if synConn!=[] or synackconn!=[] or ackConn!=[] or resolvedIPsArray!=[] or fullHTTPArray!=[] or udpconn!=[] or dnspacket!=[] or icmpPacket!=[] or ftpconn!=[] or sshconn!=[] or foundIPs!=[]:
                gatherIOCs(self.analysis_path, synConn, synackconn, ackConn,
                           resolvedIPsArray, results, fullHTTPArray, udpconn,
                           dnspacket, icmpPacket, ftpconn, sshconn, foundIPs)
            else:
                print "No IOCs to create"

        except (UnicodeError, TypeError, IOError) as e:
            print "Error", e
            raise CuckooReportError("Failed to make STIX IOCs :(")
        return True
class VisualizeJsonReport(Report):
    """Visualize data in json report file."""
    # Make file run last, after analysis has completed

    order = 3

    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        try:
			# Get home directory path
			home_path = expanduser("~")
			# Full path to json report file
        	report_path = os.path.join(self.reports_path, "report.json")
        	# Full path to application visualize_json_report
            script_path = os.path.join(home_path, ".cuckoo/visualize_json_report/run.py")
            # Full path to location to store html file created, same directory as report json
            new_file_path = os.path.join(self.reports_path, "report.html")
            
      		# Get choice from config file
        	choice = self.options['report_type']
        	print("The visualisation option is set to  {}".format(choice))

        	parameters = list()

        	"""
        	Option 1: Visualize processes only
        	Option 2: Visualize processes and network
        	Option 3: Visualize processes and files
        	Option 4: Visualize processes and registry
        	Option 5: Visualize all data 
        	Default : Visualize processes only
        	"""
        		
			if choice == int(1):
				print("Visualize processes only")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, "-fa", "-ra", "-na", report_path] 
			elif choice == int(2):
				print("Visualize processes and network data")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, "-fa", "-ra", report_path]
			elif choice == int(3):
				print("Visualize processes and file data")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, "-na", "-ra", report_path]
			elif choice == int(4):
				print("Visualize processes and registry data")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, "-fa", "-na", report_path]
			elif choice == int(5):
				print("Visualize all data")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, report_path]
			else:
				print("Visualize processes only, this is the default mode")
				parameters = ["/usr/bin/python3", script_path, "-f", new_file_path, "-fa", "-ra", "-na", report_path]

			subprocess.call(parameters)

		except (UnicodeError, TypeError, IOError) as e:
			raise CuckooReportError("Failed to generate visualisation graph: %s" % e)
Beispiel #9
0
    def run(self, results):
        try:
            report = codecs.open(os.path.join(self.reports_path, "result.yar"), "w", "utf-8")

            rule = "import \"cuckoo\"\n\n"
            rule += self.httpRequest(results)
            rule += self.dnsLookup(results)

            report.write(rule)
            report.close()
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate Yara rule: %s" % e)
Beispiel #10
0
    def run(self, results):
        post = {
            "identifier":
            self.options.get("identifier"),
            "data":
            json.dumps(results.get("info"), default=default, sort_keys=False)
        }

        try:
            requests.post(self.options.get("url"), data=post)
        except Exception as e:
            raise CuckooReportError(
                "Failed posting message via Notification: %s" % e)
    def do_index(self, obj):
        base_document = self.get_base_document()

        # Append the base document to the object to index.
        base_document.update(obj)

        try:
            elastic.client.index(index=self.dated_index,
                                 doc_type=self.report_type,
                                 body=base_document)
        except Exception as e:
            raise CuckooReportError(
                "Failed to save results in ElasticSearch for "
                "task #%d: %s" % (self.task["id"], e))
Beispiel #12
0
    def set_path(self, analysis_path):
        """Set analysis folder path.
        @param analysis_path: analysis folder path.
        """
        self.analysis_path = analysis_path
        self.file_path = os.path.realpath(self._get_analysis_path("binary"))
        self.reports_path = self._get_analysis_path("reports")
        self.shots_path = self._get_analysis_path("shots")
        self.pcap_path = self._get_analysis_path("dump.pcap")

        try:
            Folders.create(self.reports_path)
        except CuckooOperationalError as e:
            raise CuckooReportError(e)
Beispiel #13
0
    def run(self, results):
        post = {
            "task_id": self.task["id"],
            "identifier": self.options.get("identifier"),
            "data": json.dumps(
                results.get("info"), default=default, sort_keys=False
            )
        }

        try:
            urls = self.options.get("url").split(',')
	        for url in urls:
                requests.post(url.strip(), data=post)
        except Exception as e:
            raise CuckooReportError(
                "Failed posting message via Notification: %s" % e
            )
Beispiel #14
0
    def init_once(cls):
        """Connect to Elasticsearch.
        @raise CuckooReportError: if unable to connect.
        """
        # Do not change these types without changing the elasticsearch
        # template as well.
        cls.report_type = "cuckoo"
        cls.call_type = "call"

        if not elastic.init():
            return

        cls.template_name = "%s_template" % elastic.index

        try:
            elastic.connect()
        except CuckooOperationalError as e:
            raise CuckooReportError(
                "Error running ElasticSearch reporting module: %s" % e)
    def apply_template(cls):
        template_path = cwd("elasticsearch", "template.json")
        if not os.path.exists(template_path):
            return False

        try:
            template = json.loads(open(template_path, "rb").read())
        except ValueError:
            raise CuckooReportError(
                "Unable to read valid JSON from the ElasticSearch "
                "template JSON file located at: %s" % template_path)

        # Create an index wildcard based off of the index name specified
        # in the config file, this overwrites the settings in
        # template.json.
        template["template"] = elastic.index + "-*"

        # if the template does not already exist then create it
        if not elastic.client.indices.exists_template(cls.template_name):
            elastic.client.indices.put_template(name=cls.template_name,
                                                body=json.dumps(template))
        return True
    def run(self, results):
        """
        Sends Cuckoo report as a DXL event on a DXL Fabric.

        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to send Cuckoo report as a DXL event.
        """

        try:
            # Diction of data to send out as the report on DXL
            report_dict = {}

            if self.options.get("send_compressed_event", False):
                # Convert results to JSON string
                report_json_string = json.dumps(
                    results,
                    default=serialize_datetime_objects,
                    indent=self.options.indent,
                    encoding="UTF-8")

                # Compress the Cuckoo results
                zlib_obj = zlib.compressobj(-1, zlib.DEFLATED, 31)
                compressed_report_data = zlib_obj.compress(
                    report_json_string) + zlib_obj.flush()

                # Create the DXL Event for zipped data
                zipped_event = Event(CUCKOO_ZIP_EVENT_TOPIC)

                # Set the payload to be the compressed Cuckoo report analysis
                zipped_event.payload = compressed_report_data

                # Publish the full zipped reported if the payload size is smaller than the maximum configured size.
                if sys.getsizeof(zipped_event.payload) <= self.options.get(
                        "compressed_event_max_size", 512000):
                    log.info(
                        "Publishing full zipped report to DXL on topic %s",
                        CUCKOO_ZIP_EVENT_TOPIC)
                    cuckoo_dxl_client.client.send_event(zipped_event)
                else:
                    log.info(
                        "Report too large. Not publishing zipped report to DXL."
                    )

            # Add the info and target entries from the Cuckoo results
            report_dict[INFO_REPORT_KEY] = results.get(INFO_REPORT_KEY, {})
            report_dict[TARGET_REPORT_KEY] = results.get(TARGET_REPORT_KEY, {})

            # Add items listed from the "items_to_include_in_report" setting in the report.conf to the report
            items_to_include_in_report = self.options.get(
                "items_to_include_in_report")
            if items_to_include_in_report is not None:
                # Get rid of any white space characters in the items_to_include_in_report string
                items_to_include_in_report = re.sub(
                    r"\s+", "", items_to_include_in_report)

                # Loop over list of items to include
                for report_include_item in items_to_include_in_report.split(
                        ","):
                    if not report_include_item:
                        log.warn(
                            "items_to_include_in_report includes an emtpy item."
                        )
                        continue

                    # Separate report_include_item in to sub items
                    sub_sections_list = report_include_item.split(".")
                    # Find the value in the Cuckoo results dictionary
                    sub_section_value = reduce(sub_level_getter,
                                               sub_sections_list, results)

                    if sub_section_value is NOT_FOUND_OBJ:
                        log.warn(report_include_item +
                                 " is not found in the Cuckoo report.")
                        continue

                    # Create all of the sub item levels in the results reports dictionary
                    result_sub_section = reduce(create_and_get_sub_level,
                                                sub_sections_list[0:-1],
                                                report_dict)
                    # Add the value found in the Cuckoo results
                    result_sub_section.update(
                        {sub_sections_list[-1]: sub_section_value})

            # Create the DXL Event
            report_event = Event(CUCKOO_REPORT_EVENT_TOPIC)

            # Set event payload to be the JSON of the results report dictionary
            report_event.payload = json.dumps(
                report_dict,
                default=serialize_datetime_objects).encode("UTF-8")

            # Publish the Event to the DXL Fabric
            log.info("Publishing Cuckoo report to DXL on topic %s",
                     CUCKOO_REPORT_EVENT_TOPIC)
            cuckoo_dxl_client.client.send_event(report_event)

        except Exception as ex:
            log.exception("Error sending Cuckoo report out as a DXL event.")
            raise CuckooReportError(
                "Failed to send Cuckoo report as a DXL event: %s" % ex)
Beispiel #17
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        try:
            currentMD5 = results["target"]["file"]["md5"]
            currentSHA1 = results["target"]["file"]["sha1"]
            currentSHA256 = results["target"]["file"]["sha256"]
            currentFilename = results["target"]["file"]["name"]
            currentTrustLevel = results["info"]["score"]

            print currentMD5
            print currentSHA1
            print currentSHA256
            print currentFilename
            print currentTrustLevel

            if float(currentTrustLevel) < 4.0:
                print "Trust Level is " + str(
                    currentTrustLevel) + ". No update required."
                return

            print "Opening DXL connection"
            with DxlClient(config) as client:

                #Connect to DXL fabric
                print "Connecting to DXL fabric."
                client.connect()

                #Create TIE Client
                print "Connecting to TIE."
                tie_client = TieClient(client)

                print "Trust Level is " + str(
                    currentTrustLevel) + ". Updating TIE."

                reputations_dict = \
                tie_client.get_file_reputation({
                    HashType.MD5: currentMD5,
                    HashType.SHA1: currentSHA1,
                    HashType.SHA256: currentSHA256
                    })

                print reputations_dict

                #Check if there is an enterprise (custom set) reputation
                if (reputations_dict[FileProvider.ENTERPRISE]["trustLevel"]==TrustLevel.NOT_SET or \
                    reputations_dict[FileProvider.ENTERPRISE]["trustLevel"]==TrustLevel.UNKNOWN or \
                    reputations_dict[FileProvider.ENTERPRISE]["trustLevel"]==TrustLevel.MIGHT_BE_TRUSTED or \
                    reputations_dict[FileProvider.ENTERPRISE]["trustLevel"]==TrustLevel.MOST_LIKELY_TRUSTED):

                    print "Current Trust Level is" + str(reputations_dict[
                        FileProvider.ENTERPRISE]["trustLevel"])

                    #also, let's make sure GTI trustLevels are either not being queried, or set to Unknown
                    #we are nesting for clarity
                    if (FileProvider.GTI not in reputations_dict.keys()
                            or reputations_dict[FileProvider.GTI]
                            == TrustLevel.UNKNOWN):

                        print "GTI either does not exist or set to UNKNOWN"

                        # If not set, go ahead and set it
                        tie_client.set_file_reputation(
                            TrustLevel.MOST_LIKELY_MALICIOUS, {
                                HashType.MD5: currentMD5,
                                HashType.SHA1: currentSHA1,
                                HashType.SHA256: currentSHA256
                            },
                            filename=currentFilename,
                            comment=
                            "Reputation set via OpenDXL Cuckoo Integration. Cuckoo scored this sample a "
                            + str(currentTrustLevel) + " out of 10.")

                        print "Reputation set for: " + str(
                            currentFilename) + ": " + currentMD5

        except (TypeError, IOError) as e:
            raise CuckooReportError("Failed to update TIE with results: %s" %
                                    e)