Exemple #1
0
    def run(self, results):
        if not os.path.isfile(os.path.join(self.reports_path, "summary-report.html")):
            raise CuckooReportError(
                "Unable to open summary HTML report to convert to PDF: Ensure reporthtmlsummary is enabled in reporting.conf"
            )

        if os.path.exists("/usr/bin/xvfb-run") and os.path.exists("/usr/bin/wkhtmltopdf"):
            call(
                [
                    "/usr/bin/xvfb-run",
                    "--auto-servernum",
                    "--server-num",
                    "1",
                    "/usr/bin/wkhtmltopdf",
                    "-q",
                    os.path.join(self.reports_path, "summary-report.html"),
                    os.path.join(self.reports_path, "report.pdf"),
                ]
            )
            return True

        if not HAVE_WEASYPRINT:
            raise CuckooReportError(
                "Failed to generate PDF report: Neither wkhtmltopdf nor Weasyprint Python library are installed"
            )

        logger = logging.getLogger("weasyprint")
        logger.handlers = []
        logger.setLevel(logging.ERROR)

        HTML(os.path.join(self.reports_path, "summary-report.html")).write_pdf(os.path.join(self.reports_path, "report.pdf"))

        return True
Exemple #2
0
    def run(self, results):
        if not HAVE_REQUESTS:
            raise CuckooOperationalError(
                "The Mattermost processing module requires the requests "
                "library (install with `pip install requests`)")

        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 run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        if not HAVE_JINJA2:
            raise CuckooReportError("Failed to generate summary HTML report: "
                                    "Jinja2 Python library is not installed")

        shots_path = os.path.join(self.analysis_path, "shots")
        if os.path.exists(shots_path):
            shots = []
            counter = 1
            for shot_name in os.listdir(shots_path):
                if not shot_name.endswith(".jpg"):
                    continue

                shot_path = os.path.join(shots_path, shot_name)

                if os.path.getsize(shot_path) == 0:
                    continue

                shot = {}
                shot["id"] = os.path.splitext(File(shot_path).get_name())[0]
                shot["data"] = base64.b64encode(open(shot_path, "rb").read())
                shots.append(shot)

                counter += 1

            shots.sort(key=lambda shot: shot["id"])
            results["screenshots"] = shots
        else:
            results["screenshots"] = []

        env = Environment(autoescape=True)
        env.loader = FileSystemLoader(os.path.join(CUCKOO_ROOT, "data",
                                                   "html"))

        try:
            tpl = env.get_template("report.html")
            html = tpl.render({"results": results, "summary_report": True})
        except Exception as e:
            raise CuckooReportError(
                "Failed to generate summary HTML report: %s" % e)

        try:
            with codecs.open(os.path.join(self.reports_path,
                                          "summary-report.html"),
                             "w",
                             encoding="utf-8") as report:
                report.write(html)
        except (TypeError, IOError) as e:
            raise CuckooReportError("Failed to write summary HTML report: %s" %
                                    e)

        return True
Exemple #4
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        if not HAVE_MAKO:
            raise CuckooReportError(
                "Failed to generate HTML report: python Mako library is not installed"
            )

        shots_path = os.path.join(self.analysis_path, "shots")
        if os.path.exists(shots_path):
            shots = []
            counter = 1
            for shot_name in os.listdir(shots_path):
                if not shot_name.endswith(".png"):
                    continue

                shot_path = os.path.join(shots_path, shot_name)

                if os.path.getsize(shot_path) == 0:
                    continue

                shot = {}
                shot["id"] = os.path.splitext(File(shot_path).get_name())[0]
                shot["data"] = base64.b64encode(open(shot_path, "rb").read())
                #shot["cum"] = "Seppia is gay"
                shots.append(shot)

                counter += 1

            shots.sort(key=lambda shot: shot["id"])
            results["screenshots"] = shots
        else:
            results["screenshots"] = []

        lookup = TemplateLookup(
            directories=[os.path.join(CUCKOO_ROOT, "data", "html")],
            output_encoding='utf-8',
            encoding_errors='replace')

        template = lookup.get_template("report.html")

        try:
            html = template.render(**results)
        except Exception as e:
            raise CuckooReportError("Failed to generate HTML report: %s" % e)

        try:
            report = open(os.path.join(self.reports_path, "report.html"), "w")
            report.write(html)
            report.close()
        except (TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate HTML report: %s" % e)

        return True
    def create_incident(self):
        """Create an incident to represent the analysis in ThreatConnect.

        @raise CuckooReportError: if fails to write report.
        """

        # Instantiate an incidents object
        incidents = self.tc.incidents()

        # Get todays date and the filename of the analysis target
        date_today = datetime.date.today().strftime('%Y%m%d')
        if self.results.get('target').get('file').get('name'):
            filename = self.results['target']['file']['name']

        # Build a title for the incident
        title = 'Cuckoo Analysis {}: {}'.format(date_today, filename)

        # Add the title to the object
        incident = incidents.add(title, self.target_source)

        # Get the full timestamp for the current time and set the event date
        date_today_iso = datetime.datetime.now().isoformat()
        incident.set_event_date(date_today_iso)

        # Add the analysis ID to an attribute
        if self.results.get('info').get('id'):
            analysis_id = self.results.get('info').get('id')
        incident.add_attribute('Analysis ID', analysis_id)

        # Build a report link and record it in the Source attribute
        report_link = self.report_link_template.format(analysis_id)
        incident.add_attribute('Source', report_link)

        # Commit the changes to ThreatConnect
        try:
            incident.commit()
        except RuntimeError as e:
            raise CuckooReportError('Failed to commit incident: {}'.format(e))
        else:
            # Load the attributes into the incident object
            incident.load_attributes()

            # Mark all Cuckoo attributes with DO NOT SHARE security label
            for attribute in incident.attributes:
                if attribute.type == 'Analysis ID' or attribute.type == 'Source':
                    attribute.add_security_label('DO NOT SHARE')

            # Commit the changes to ThreatConnect
            try:
                incident.commit()
            except RuntimeError as e:
                raise CuckooReportError(
                    'Failed to commit incident: {}'.format(e))
            else:
                return incident.id
Exemple #6
0
 def connect(self):
     """Connects to Elasticsearch database, loads options and set connectors.
     @raise CuckooReportError: if unable to connect.
     """
     try:
         self.es = elastic_handler
     except TypeError:
         raise CuckooReportError(
             "Elasticsearch connection port must be integer")
     except ConnectionError:
         raise CuckooReportError("Cannot connect to ElasticsearchDB")
Exemple #7
0
    def run(self, results):
        """ Sends report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        # Get server options from reporting.conf
        server = self.options.get("host", None)
        port = self.options.get("port", None)
        proto = self.options.get("protocol", None).lower()
        # A few validations...
        if not server:
                raise CuckooReportError("Syslog Server IP not defined")
        if not port:
                raise CuckooReportError("Syslog Server port not defined")
        if not proto:
                raise CuckooReportError("Syslog Protocol not defined")
        if proto != "tcp" and proto != "udp":
                raise CuckooReportError("Syslog Protocol configuration error, "
                                           "protocol must be TCP or UDP.")
        # Generate the syslog string
        try:
            result = self.createLog(results)
        except:
            raise CuckooReportError("Error creating syslog formatted log.")
			
        # Check if the user wants it stored in the reports directory as well
        do_log = self.options.get("logfile", None)
        if do_log:
            logfile = self.options.get("logname", "syslog.txt")
            # Log syslog results to the reports directory
            try:
                syslogfile = open(str(os.path.join(self.reports_path, logfile)), "w")
                syslogfile.write(result)
            except:
                raise CuckooReportError("Error writing the syslog output file.")
            finally:
                syslogfile.close()
        # Attempt to connect to the syslog server
        try:
            server_address = (server, port)
            if proto == "tcp":
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.connect(server_address)
                # Attempt to send the syslog string to the syslog server
                try:
                    sock.sendall(result)
                except:
                    raise CuckooReportError("Failed to send data to syslog server")
                finally:
                    sock.close()
            elif proto == "udp":
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                try:
                    sock.sendto(result, server_address)
                except:
                    raise CuckooReportError("Failed to send data to syslog server")
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to send syslog data: %s" % e)
Exemple #8
0
    def run(self, results):
        zipmemdump = self.options.get("zipmemdump", False)
        zipprocdump = self.options.get("zipprocdump", False)
        zipmemstrings = self.options.get("zipmemstrings", False)
        zipprocstrings = self.options.get("zipprocstrings", False)

        for proc in results.get("procmemory", []) or []:
            dmp_path = proc.get("file", None)
            strings_path = proc.get("strings_path", None)

            for option in (zipprocdump, zipprocstrings):
                if option and dmp_path and dmp_path.endswith(
                    (".dmp", ".strings")) and os.path.exists(dmp_path):
                    try:
                        f = zipfile.ZipFile("%s.zip" % (dmp_path), "w")
                        f.write(dmp_path, os.path.basename(dmp_path),
                                zipfile.ZIP_DEFLATED)
                        f.close()
                        os.remove(dmp_path)
                        proc["file"] = "%s.zip" % (dmp_path)
                    except Exception as e:
                        raise CuckooReportError(
                            "Error creating Process Memory Zip File %s" % e)

        if zipmemdump and self.memory_path and os.path.exists(
                self.memory_path):
            try:
                f = zipfile.ZipFile("%s.zip" % (self.memory_path),
                                    "w",
                                    allowZip64=True)
                f.write(self.memory_path, os.path.basename(self.memory_path),
                        zipfile.ZIP_DEFLATED)
                f.close()
                os.remove(self.memory_path)
            except Exception as e:
                raise CuckooReportError(
                    "Error creating Full Memory Zip File %s" % e)

        if zipmemstrings and self.memory_path and os.path.exists(
                self.memory_path + ".strings"):
            strings_path = self.memory_path + ".strings"
            try:
                f = zipfile.ZipFile("%s.zip" % (strings_path),
                                    "w",
                                    allowZip64=True)
                f.write(strings_path, os.path.basename(strings_path),
                        zipfile.ZIP_DEFLATED)
                f.close()
                os.remove(strings_path)
                strings_path = "%s.zip" % (strings_path)
            except Exception as e:
                raise CuckooReportError(
                    "Error creating Full Memory Strings Zip File %s" % e)
Exemple #9
0
    def connect(self):
        """Connects to Mongo database, loads options and set connectors.
        @raise CuckooReportError: if unable to connect.
        """
        host = self.options.get("host", "127.0.0.1")
        port = self.options.get("port", 27017)
        db = self.options.get("db", "cuckoo")

        try:
            self.conn = MongoClient(host, port)
            self.db = self.conn[db]
        except TypeError:
            raise CuckooReportError("Mongo connection port must be integer")
        except ConnectionFailure:
            raise CuckooReportError("Cannot connect to MongoDB")
Exemple #10
0
    def addBundle(self):
        """Generates MAEC bundle structure."""
        if self.results["target"]["category"] == "file":
            self.idMap[
                "prefix"] = "maec:%s" % self.results["target"]["file"]["md5"]
        elif self.results["target"]["category"] == "url":
            self.idMap["urlmd5"] = hashlib.md5(
                self.results["target"]["url"]).hexdigest()
            self.idMap["prefix"] = "maec:%s" % self.idMap["urlmd5"]
        else:
            raise CuckooReportError("Unknown target type")

        # Generate bundle
        self.m = maec.BundleType(id="%s:bnd:1" % self.idMap["prefix"],
                                 schema_version="1.1")
        # Analyses
        self.analyses = maec.AnalysesType()
        self.m.set_Analyses(self.analyses)
        # Actions
        self.actions = maec.ActionsType()
        self.m.set_Actions(self.actions)
        # Behaviors
        self.behaviors = maec.BehaviorsType()
        self.m.set_Behaviors(self.behaviors)
        # Pools
        self.pools = maec.PoolsType()
        self.m.set_Pools(self.pools)
Exemple #11
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """

        encoding = self.options.get("encoding", "utf-8")

        keys_to_copy = repconf.litereport.keys_to_copy.split(" ")

        # lite report report only has the specific keys
        lite_report = {k: results[k] for k in results.keys() & keys_to_copy}

        # add specific keys from behavior
        behavior_keys_to_copy = repconf.litereport.behavior_keys_to_copy.split(" ")
        behavior = {k: results["behavior"][k] for k in results["behavior"].keys() & behavior_keys_to_copy}
        lite_report["behavior"] = behavior

        path = os.path.join(self.reports_path, "lite.json")
        try:
            if HAVE_ORJSON:
                with open(path, "wb") as report:
                    report.write(orjson.dumps(lite_report, option=orjson.OPT_INDENT_2, default=self.default)) # orjson.OPT_SORT_KEYS |
            else:
                with open(path, "w") as report:
                    json.dump(lite_report, report, sort_keys=False, separators=(',', ':'), ensure_ascii=False)
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate JSON report: %s" % e)
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        indent = self.options.get("indent", 4)
        encoding = self.options.get("encoding", "utf-8")

        try:
            
            del results['behavior']
            del results['procmemory']
            for tag in results['dropped']:
                del tag['sha1']
                del tag['crc32']
                del tag['sha256']
                del tag['path']
                del tag['ssdeep']
                del tag['sha512']
                del tag['md5']
                del tag['size']
                
            
                    
            path = os.path.join(self.reports_path, "report.json")
            with codecs.open(path, "w", "utf-8") as report:
                json.dump(results, report, sort_keys=False,
                          indent=int(indent), encoding=encoding)
                       
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate JSON report: %s" % e)
Exemple #13
0
    def apply_template(self):
        template_path = os.path.join(
            CUCKOO_ROOT, "data", "elasticsearch", "template.json"
        )
        if not os.path.exists(template_path):
            return False

        with open(template_path, "rw") as f:
            try:
                cuckoo_template = json.loads(f.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.
            cuckoo_template["template"] = self.index + "-*"

        self.es.indices.put_template(
            name="cuckoo_template", body=json.dumps(cuckoo_template)
        )
        return True
Exemple #14
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        indent = self.options.get("indent", 4)
        encoding = self.options.get("encoding", "utf-8")
        ram_boost = self.options.get("ram_boost", True)

        try:
            path = os.path.join(self.reports_path, "report.json")
            with codecs.open(path, "w", "utf-8") as report:
                if ram_boost:
                    buf = json.dumps(results,
                                     sort_keys=False,
                                     indent=int(indent),
                                     encoding=encoding,
                                     ensure_ascii=False)
                    report.write(buf)

                    #Add method (send_report)
                    send_report(path, self.analysis_path)
                else:
                    json.dump(results,
                              report,
                              sort_keys=False,
                              indent=int(indent),
                              encoding=encoding,
                              ensure_ascii=False)

                    #Add method (send_report)
                    send_report(path, self.analysis_path)
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate JSON report: %s" % e)
Exemple #15
0
    def run(self, results):
        """Publishes to google pubsub results topic
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails.
        """

        try:
            processed_msg_id = results["info"]["options"].get(
                "pubsub_msg_id", None)
            if (processed_msg_id != None):
                pubsub_client = pubsub.Client()

                sample_sha256 = results["target"]["file"]["sha256"]
                analysis_path = self.analysis_path
                os.system(
                    "python utils/networkIOCFromCuckooReport.py " +
                    analysis_path +
                    "/reports/report.json | grep -vf utils/networkWhiteList.txt | sed -e \"s/\./\.\./g\" > "
                    + self.analysis_path + "/networkIOC.txt")

                if "function" in results["info"]["options"]:
                    results_folder = "gs://a1s-zoombox/zOOmed/" + sample_sha256[
                        0:2] + "/" + sample_sha256[
                            2:
                            4] + "/" + sample_sha256 + "/" + processed_msg_id + "/" + results[
                                "info"]["package"] + "/" + results["info"][
                                    "options"]["function"] + "/"
                    os.system(
                        "gsutil -m cp -r " + analysis_path + "/* gs://" +
                        quote("a1s-zoombox/zOOmed/" + sample_sha256[0:2] +
                              "/" + sample_sha256[2:4] + "/" + sample_sha256 +
                              "/" + processed_msg_id + "/" +
                              results["info"]["package"] + "/" +
                              results["info"]["options"]["function"] + "/"))
                else:
                    os.system("gsutil -m cp -r " + analysis_path + "/* gs://" +
                              quote("a1s-zoombox/zOOmed/" +
                                    sample_sha256[0:2] + "/" +
                                    sample_sha256[2:4] + "/" + sample_sha256 +
                                    "/" + processed_msg_id + "/" +
                                    results["info"]["package"] + "/"))
                    results_folder = "gs://a1s-zoombox/zOOmed/" + sample_sha256[
                        0:2] + "/" + sample_sha256[
                            2:
                            4] + "/" + sample_sha256 + "/" + processed_msg_id + "/" + results[
                                "info"]["package"] + "/"

                #publish completion message to topic
                topic = pubsub_client.topic(self.options['pubsub_topic'])
                message_id = topic.publish(
                    u'Detonation complete. Results uploaded.',
                    upload_folder=results_folder,
                    processed_msg_id=processed_msg_id,
                    sha256=sample_sha256)

                log.info(
                    u"Message published to pubsub with message_id %s at: %s" %
                    (message_id, results_folder))
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to publish results: %s" % e)
Exemple #16
0
    def run(self, results):
        """Runs Malheur processing
        @return: Nothing.  Results of this processing are obtained at an arbitrary future time.
        """
        basedir = os.path.join(CUCKOO_ROOT, "storage", "malheur")
        reportsdir = os.path.join(basedir, "reports")
        task_id = str(results["info"]["id"])
        outputfile = os.path.join(basedir, "malheur.txt." + hashlib.md5(str(random.random())).hexdigest())
        try:
            os.makedirs(reportsdir)
        except:
            pass

        mist = mist_convert(results)
        if mist:
            with open(os.path.join(reportsdir, task_id + ".txt"), "w") as outfile:
                outfile.write(mist)

        # might need to prevent concurrent modifications to internal state of malheur by only allowing
        # one analysis to be running malheur at a time

        path, dirs, files = os.walk(reportsdir).next()
        try:
            subprocess.call(["malheur", "--input.format", "mist", "--input.mist_level", "2", "--cluster.reject_num", "2", "-o", outputfile, "cluster", reportsdir])

            # replace previous classification state with new results atomically
            os.rename(outputfile, outputfile[:-33])
        except Exception as e:
            raise CuckooReportError("Failed to perform Malheur classification: %s" % e)
Exemple #17
0
	def run(self, results):		
		try:
			#print "Start of IOC_STIX reporting module\n"+results
			#pcapFile = dpkt.pcap.Reader(file(self.analysis_path+"/cut-byprocessingmodule.pcap"))
			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)
			udpconn = getUDPData(self.analysis_path, goodIPs)
			dnspacket = getDNSData(self.analysis_path)
			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
 def do_bulk_index(self, bulk_reqs):
     try:
         helpers.bulk(self.es, bulk_reqs)
     except Exception as e:
         raise CuckooReportError(
             "Failed to save results in ElasticSearch for "
             "task #%d: %s" % (self.task["id"], e))
Exemple #19
0
    def _run_report(self, plugin, data):
        """Run a single report plugin.
        @param plugin: report plugin.
        @param data: results data from analysis.
        """
        current = plugin()
        current.set_path(self.analysis_path)
        current.cfg = Config(current.conf_path)
        module = inspect.getmodule(current)

        if "." in module.__name__:
            module_name = module.__name__.rsplit(".", 1)[1]
        else:
            module_name = module.__name__

        try:
            current.set_options(self.cfg.get(module_name))
        except CuckooOperationalError:
            raise CuckooReportError(
                "Reporting module %s not found in configuration file" %
                module_name)

        try:
            # Run report, for each report a brand new copy of results is
            # created, to prevent a reporting module to edit global
            # result set and affect other reporting modules.
            current.run(copy.deepcopy(data))
            log.debug("Executed reporting module \"%s\"" %
                      current.__class__.__name__)
        except NotImplementedError:
            return
        except CuckooReportError as e:
            log.warning("Failed to execute reporting module \"%s\": %s" %
                        (current.__class__.__name__, e))
Exemple #20
0
    def run(self, results):
        """Writes report.
        @param results: Cuckoo results dict.
        @raise CuckooReportError: if fails to write report.
        """
        indent = self.options.get("indent", 4)
        encoding = self.options.get("encoding", "utf-8")

        # 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:
            path = os.path.join(self.reports_path, "report.json")

            with codecs.open(path, "w", "utf-8") as report:
                json.dump(results,
                          report,
                          default=default,
                          sort_keys=False,
                          indent=int(indent),
                          encoding=encoding)
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate JSON report: %s" % e)
        finally:
            self.restore_calls(results)
Exemple #21
0
    def addMetadata(self):
        """Generates header for MAEC xml and root components."""
        if self.results["target"]["category"] == "file":
            id = "cuckoo:%s" % self.results["target"]["file"]["md5"]
        elif self.results["target"]["category"] == "url":
            id = "cuckoo:%s" % hashlib.md5(
                self.results["target"]["url"]).hexdigest()
        else:
            raise CuckooReportError("Unknown target type")

        self.m = maec.malwareMetaData(
            version="1.1",
            id=id,
            author="Cuckoo Sandbox %s" % self.results["info"]["version"],
            comment=
            "Report created with Cuckoo Sandbox %s automated and open source malware sandbox: http://www.cuckoosandbox.org"
            % self.results["info"]["version"],
            timestamp=datetime_to_iso(self.results["info"]["started"]))
        # Objects
        self.objects = maec.objectsType()
        self.m.set_objects(self.objects)
        # Object Properties
        self.properties = maec.objectPropertiesType()
        self.m.set_objectProperties(self.properties)
        # Relationships
        self.relationships = maec.relationshipsType()
        self.m.set_relationships(self.relationships)
Exemple #22
0
    def do_mongo(self, report_mongo, report, t, node):
        """This fucntion will store behavior and webgui report without reprocess"""
        if HAVE_MONGO:
            try:
                conn = MongoClient(reporting_conf.mongodb.host,
                                   reporting_conf.mongodb.port)
                mongo_db = conn[reporting_conf.mongodb.db]
            except ConnectionFailure:
                raise CuckooReportError("Cannot connect to MongoDB")
                return

        if "processes" in report.get("behavior", {}):
            new_processes = []

            for process in report.get("behavior", {}).get("processes", []):
                new_process = dict(process)

                chunk = []
                chunks_ids = []
                # Loop on each process call.
                for index, call in enumerate(process["calls"]):
                    # If the chunk size is 100 or if the loop is completed then
                    # store the chunk in MongoDB.
                    if len(chunk) == 100:
                        to_insert = {
                            "pid": process["process_id"],
                            "calls": chunk
                        }
                        chunk_id = mongo_db.calls.insert(to_insert)
                        chunks_ids.append(chunk_id)
                        # Reset the chunk.
                        chunk = []

                    # Append call to the chunk.
                    chunk.append(call)

                # Store leftovers.
                if chunk:
                    to_insert = {"pid": process["process_id"], "calls": chunk}
                    chunk_id = mongo_db.calls.insert(to_insert)
                    chunks_ids.append(chunk_id)

                # Add list of chunks.
                new_process["calls"] = chunks_ids
                new_processes.append(new_process)

            # Store the results in the report.
            report_mongo["behavior"]["processes"] = new_processes

        #patch info.id to have the same id as in main db
        report_mongo["info"]["id"] = t.main_task_id
        mongo_db.analysis.save(report_mongo)

        # set complated_on time
        main_db.set_status(t.main_task_id, TASK_COMPLETED)
        # set reported time
        main_db.set_status(t.main_task_id, TASK_REPORTED)

        conn.close()
    def connect(self):
        """Connect to Elasticsearch.
        @raise CuckooReportError: if unable to connect.
        """
        hosts = []
        for host in self.options.get("hosts", "127.0.0.1:9200").split(","):
            if host.strip():
                hosts.append(host.strip())

        self.index = self.options.get("index", "cuckoo")

        # Do not change these types without changing the elasticsearch
        # template as well.
        self.report_type = "cuckoo"
        self.call_type = "call"

        # Get the index time option and set the dated index accordingly
        index_type = self.options.get("index_time_pattern", "yearly")
        if index_type.lower() == "yearly":
            strf_time = "%Y"
        elif index_type.lower() == "monthly":
            strf_time = "%Y-%m"
        elif index_type.lower() == "daily":
            strf_time = "%Y-%m-%d"

        date_index = datetime.datetime.utcnow().strftime(strf_time)
        self.dated_index = "%s-%s" % (self.index, date_index)

        # Gets the time which will be used for indexing the document into ES
        # ES needs epoch time in seconds per the mapping
        self.report_time = int(time.time())

        self.template_name = self.index + "_template"

        try:
            self.es = Elasticsearch(hosts)
        except TypeError:
            raise CuckooReportError(
                "Elasticsearch connection hosts must be host:port or host")
        except (ConnectionError, ConnectionTimeout) as e:
            raise CuckooReportError("Cannot connect to Elasticsearch: %s" % e)

        # check to see if the template exists apply it if it does not
        if not self.es.indices.exists_template(self.template_name):
            if not self.apply_template():
                raise CuckooReportError("Cannot apply Elasticsearch template")
Exemple #24
0
 def connect(self):
     """Connects to Mongo database, loads options and set connectors.
     @raise CuckooReportError: if unable to connect.
     """
     try:
         self.conn = MongoClient(
             self.options.get("host", "127.0.0.1"),
             port=self.options.get("port", 27017),
             username=self.options.get("username", None),
             password=self.options.get("password", None),
             authSource=self.options.get("authsource", "cuckoo"),
         )
         self.db = self.conn[self.options.get("db", "cuckoo")]
     except TypeError:
         raise CuckooReportError("Mongo connection port must be integer")
     except ConnectionFailure:
         raise CuckooReportError("Cannot connect to MongoDB")
Exemple #25
0
    def run(self, results):
        if not HAVE_REQUESTS:
            raise CuckooOperationalError(
                "The Mattermost processing module requires the requests "
                "library (install with `pip install requests`)"
            )

        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")
        )

        filename = results.get("target", {}).get("file", {}).get("name", "")
        if self.options.get("hash-filename"):
            filename = hashlib.sha256(filename).hexdigest()

        post += "File : {0} ::: Score : **{1}** ::: ".format(
            filename, 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,
        }

        headers = {"Content-Type": "application/json"}

        try:
            requests.post(
                self.options.get("url"),
                headers=headers,
                data=json.dumps(data)
            )
        except Exception as e:
            raise CuckooReportError(
                "Failed posting message to Mattermost: %s" % e
            )
Exemple #26
0
    def connect(self):
        """Connects to Mongo database, loads options and set connectors.
        @raise CuckooReportError: if unable to connect.
        """
        host = self.options.get("host", "127.0.0.1")
        port = self.options.get("port", 27017)
        user = self.options.get("user", "cuckoo")
        pwd = self.options.get("passwd", "cuckoo")
        dbname = self.options.get("database", "cuckoo")

        try:
            self.conn = MongoClient("mongodb://%s:%s@%s:%d/%s" %
                                    (user, pwd, host, port, dbname))
            self.db = self.conn[dbname]
            self.fs = GridFS(self.db)
        except TypeError:
            raise CuckooReportError("Mongo connection port must be integer")
        except ConnectionFailure:
            raise CuckooReportError("Cannot connect to MongoDB")
Exemple #27
0
    def connect(self):
        """Connect to Elasticsearch.
        @raise CuckooReportError: if unable to connect.
        """
        hosts = []
        for host in self.options.get("hosts", "127.0.0.1:9200").split(","):
            if host.strip():
                hosts.append(host.strip())

        self.index = self.options.get("index", "cuckoo")
        self.type_ = self.options.get("type", "cuckoo")

        try:
            self.es = Elasticsearch(hosts)
        except TypeError:
            raise CuckooReportError(
                "Elasticsearch connection hosts must be host:port or host")
        except (ConnectionError, ConnectionTimeout) as e:
            raise CuckooReportError("Cannot connect to Elasticsearch: %s" % e)
Exemple #28
0
 def run(self, results):
     """Writes report.
     @param results: Cuckoo results dict.
     @raise CuckooReportError: if fails to write report.
     """
     try:
         report = open(os.path.join(self.reports_path, "report.json"), "w")
         report.write(json.dumps(results, sort_keys=False, indent=4))
         report.close()
     except (TypeError, IOError) as e:
         raise CuckooReportError("Failed to generate JSON report: %s" % e)
Exemple #29
0
    def do_index(self, obj):
        index = "%s-%d" % (self.index, self.task["id"])

        try:
            self.es.create(index=index, doc_type=self.type_, body=obj)
        except Exception as e:
            raise CuckooReportError(
                "Failed to save results in ElasticSearch for "
                "task #%d: %s" % (self.task["id"], e))

        self.idx += 1
Exemple #30
0
    def run(self, results):
        """Invokes IOCAware OpenIOC script.
		@param results: Cuckoo results dict
		@raise CuckooReportError: if fails to write report
		"""

        try:
            # Make call to create ioc from cuckoo results
            doCuckoo(results)
        except (UnicodeError, TypeError, IOError) as e:
            raise CuckooReportError("Failed to generate IOC results: %s" % e)