예제 #1
0
    def run(self):
        """Run extract of printable strings.
        @return: list of printable strings.
        """
        self.key = "strings"
        strings = []

        if self.task["category"] == "file":
            if not os.path.exists(self.file_path):
                raise CuckooProcessingError(
                    "Sample file doesn't exist: \"%s\"" % self.file_path)

            try:
                data = open(self.file_path, "rb").read(self.MAX_FILESIZE)
            except (IOError, OSError) as e:
                raise CuckooProcessingError("Error opening file %s" % e)

            strings = []
            for s in re.findall(b"[\x1f-\x7e]{6,}", data):
                strings.append(s.decode("utf-8"))
            for s in re.findall(b"(?:[\x1f-\x7e][\x00]){6,}", data):
                strings.append(s.decode("utf-16le"))

        # Now limit the amount & length of the strings.
        strings = strings[:self.MAX_STRINGCNT]
        for idx, s in enumerate(strings):
            strings[idx] = s[:self.MAX_STRINGLEN]

        return strings
예제 #2
0
    def process_pcap_binary(self):
        """Process a PCAP file with Suricata by running Suricata.

        Using the socket mode is preferred as the plain binary mode requires
        Suricata to load all its rules for every PCAP file and thus takes a
        couple of performance heavy seconds to set itself up.
        """
        if not os.path.isfile(self.suricata):
            raise CuckooProcessingError("Unable to locate Suricata binary")

        if not os.path.isfile(self.config_path):
            raise CuckooProcessingError(
                "Unable to locate Suricata configuration")

        args = [
            self.suricata,
            "-c",
            self.config_path,
            "-k",
            "none",
            "-l",
            self.suricata_path,
            "-r",
            self.pcap_path,
        ]

        try:
            subprocess.check_call(args)
        except subprocess.CalledProcessError as e:
            raise CuckooProcessingError(
                "Suricata returned an error processing this pcap: %s" % e)
예제 #3
0
    def run(self):
        """Run VirusTotal processing
        @return: full VirusTotal report.
        """
        self.key = "virustotal"

        if not config("processing:virustotal:key"):
            raise CuckooProcessingError(
                "VirusTotal API key not configured, skipping the VirusTotal "
                "processing module.")

        self.vt = VirusTotalAPI()

        # Scan the original sample or URL.
        if self.task["category"] == "file":
            results = self.scan_file(self.file_path)
        elif self.task["category"] == "url":
            results = self.scan_url(self.task["target"])
        elif self.task["category"] == "baseline":
            return
        elif self.task["category"] == "service":
            return
        else:
            raise CuckooProcessingError("Unsupported task category: %s" %
                                        self.task["category"])

        # Scan any dropped files that have an interesting filetype.
        for row in self.results.get("dropped", []):
            if not self.should_scan_file(row["type"]):
                continue

            row["virustotal"] = self.scan_file(row["path"], summary=True)

        return results
예제 #4
0
    def run(self):
        """Run androguard to extract static android information
                @return: list of static features
        """
        self.key = "apkinfo"
        apkinfo = {}

        if "file" not in self.task["category"]:
            return

        f = File(self.task["target"])
        if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type():
            if not os.path.exists(self.file_path):
                raise CuckooProcessingError(
                    "Sample file doesn't exist: \"%s\"" % self.file_path)

            try:
                a = APK(self.file_path)
                if a.is_valid_APK():
                    manifest = {}
                    apkinfo["files"] = self._apk_files(a)
                    manifest["package"] = a.get_package()
                    # manifest["permissions"]=a.get_details_permissions_new()
                    manifest["main_activity"] = a.get_main_activity()
                    manifest["activities"] = a.get_activities()
                    manifest["services"] = a.get_services()
                    manifest["receivers"] = a.get_receivers()
                    # manifest["receivers_actions"]=a.get__extended_receivers()
                    manifest["providers"] = a.get_providers()
                    manifest["libraries"] = a.get_libraries()
                    apkinfo["manifest"] = manifest
                    # apkinfo["certificate"] = a.get_certificate()
                    static_calls = {}
                    if self.check_size(apkinfo["files"]):
                        vm = DalvikVMFormat(a.get_dex())
                        vmx = uVMAnalysis(vm)

                        static_calls["all_methods"] = self.get_methods(vmx)
                        static_calls[
                            "is_native_code"] = analysis.is_native_code(vmx)
                        static_calls["is_dynamic_code"] = analysis.is_dyn_code(
                            vmx)
                        static_calls[
                            "is_reflection_code"] = analysis.is_reflection_code(
                                vmx)

                        # static_calls["dynamic_method_calls"]= analysis.get_show_DynCode(vmx)
                        # static_calls["reflection_method_calls"]= analysis.get_show_ReflectionCode(vmx)
                        # static_calls["permissions_method_calls"]= analysis.get_show_Permissions(vmx)
                        # static_calls["crypto_method_calls"]= analysis.get_show_CryptoCode(vmx)
                        # static_calls["native_method_calls"]= analysis.get_show_NativeMethods(vmx)
                    else:
                        log.warning("Dex size bigger than: %s",
                                    self.options.decompilation_threshold)
                    apkinfo["static_method_calls"] = static_calls
            except (IOError, OSError, zipfile.BadZipfile) as e:
                raise CuckooProcessingError("Error opening file %s" % e)

        return apkinfo
예제 #5
0
    def run(self):
        """Run Google play unofficial python api the get the google play information
        @return: list of google play features
        """
        self.key = "googleplay"
        googleplay = {}

        if not HAVE_GOOGLEPLAY:
            log.error("Unable to import the GooglePlay library, has it been "
                      "installed properly?")
            return

        if "file" not in self.task["category"]:
            return

        f = File(self.task["target"])
        if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type():
            if not os.path.exists(self.file_path):
                raise CuckooProcessingError("Sample file doesn't exist: \"%s\"" % self.file_path)

            android_id = self.options.get("android_id")
            google_login = self.options.get("google_login")
            google_password = self.options.get("google_password")
            # auth_token = self.options.get("auth_token", None)

            if not android_id and not google_login and not google_password:
                raise CuckooProcessingError("Google Play Credentials not configured, skip")

            try:
                a = APK(self.file_path)
                if a.is_valid_APK():
                    package = a.get_package()
                    # Connect
                    api = GooglePlayAPI(android_id)
                    api.login(google_login, google_password, None)

                    # Get the version code and the offer type from the app details
                    app_data = api.details(package)
                    app_detail = app_data.docV2.details.appDetails

                    if not app_detail.installationSize:
                        return googleplay

                    googleplay["title"] = app_detail.title
                    googleplay["app_category"] = app_detail.appCategory._values
                    googleplay["version_code"] = app_detail.versionCode
                    googleplay["app_type"] = app_detail.appType
                    googleplay["content_rating"] = app_detail.contentRating
                    googleplay["developer_email"] = app_detail.developerEmail
                    googleplay["developer_name"] = app_detail.developerName
                    googleplay["developer_website"] = app_detail.developerWebsite
                    googleplay["installation_size"] = app_detail.installationSize
                    googleplay["num_downloads"] = app_detail.numDownloads
                    googleplay["upload_date"] = app_detail.uploadDate
                    googleplay["permissions"] = app_detail.permission._values
            except (IOError, OSError, zipfile.BadZipfile) as e:
                raise CuckooProcessingError("Error opening file %s" % e)

        return googleplay
예제 #6
0
    def run(self, results):
        self.moloch_capture = \
            self.options.get("moloch_capture", "/data/moloch/bin/moloch-capture")
        self.config_path = self.options.get("conf",
                                            "/data/moloch/etc/config.ini")
        self.instance = self.options.get("instance", "cuckoo")

        if not os.path.isfile(self.pcap_path):
            log.warning("Unable to run Moloch as no pcap is available")
            return

        if not os.path.isfile(self.moloch_capture):
            raise CuckooProcessingError("Unable to locate Moloch binary")

        if not os.path.isfile(self.config_path):
            raise CuckooProcessingError(
                "Unable to locate Moloch configuration")

        args = [
            self.moloch_capture,
            "-c",
            self.config_path,
            "-r",
            self.pcap_path,
            "-n",
            self.instance,
            "-q",
        ]

        tags = {}
        tags[self.instance] = self.task["id"]

        if self.task["category"] == "file":
            # Tag file hashes.
            f = results.get("target", {}).get("file", {})
            for field in ("md5", "sha1", "sha256", "sha512"):
                if field in f:
                    tags[field] = f[field]

            # Tag normalized VirusTotal results.
            for variant in results.get("virustotal", {}).get("normalized", []):
                tags["virustotal"] = variant

        for key, value in tags.items():
            args += [
                "-t",
                "%s:%s" % (key, value),
            ]

        try:
            subprocess.check_call(args)
        except subprocess.CalledProcessError as e:
            raise CuckooProcessingError("Error submitting PCAP to Moloch: %s" %
                                        e)
예제 #7
0
파일: sysmon.py 프로젝트: lprat/dfa
    def run(self):
        self.key = "sysmon"

        # Determine oldest sysmon log and remove the rest
        lastlog = os.listdir("%s/sysmon/" % self.analysis_path)
        lastlog.sort()
        lastlog = lastlog[-1]
        # Leave only the most recent file
        for f in os.listdir("%s/sysmon/" % self.analysis_path):
            if f != lastlog:
                try:
                    os.remove("%s/sysmon/%s" % (self.analysis_path, f))
                except:
                    log.error("Failed to remove sysmon file log %s" % f)

        os.rename(
            "%s/sysmon/%s" % (self.analysis_path, lastlog),
            "%s/sysmon/sysmon.xml" % self.analysis_path
        )

        data = None
        try:
            xml = open("%s/sysmon/sysmon.xml" % self.analysis_path).read()
            xml = xml.decode("latin1").encode("utf8")
            data = xmltodict.parse(xml)["Events"]["Event"]
        except Exception as e:
            raise CuckooProcessingError("Failed parsing sysmon.xml: %s" % e.message)

        return self.remove_noise(data)
예제 #8
0
    def run(self):
        self.key = "sysmon"

        try:
            with open('%s/sysmon/sysmon.xml' % self.analysis_path) as xmlfile:
                data = xmltodict.parse(xmlfile)
        except Exception as e:
            raise CuckooProcessingError("Failed opening sysmon log: %s"
                                        & e.message)

        clean = {}
        for event in data['root']['Event']:
            clean[event['System']['EventRecordID']] = {}
            clean[event['System']['EventRecordID']]['System'] = {}
            clean[event['System']['EventRecordID']]['EventData'] = {}
            for k, v in event['System'].items():
                clean[event['System']['EventRecordID']]['System'][k] = v
            for eventdata in event['EventData']['Data']:
                clean[event['System']['EventRecordID']]['EventData'][
                    eventdata['@Name']] = eventdata.get('#text', None)

        with open('%s/sysmon/sysmon.json' % self.analysis_path,
                  'w') as dump_file:
            json.dump(clean, dump_file)

        return clean
예제 #9
0
    def process_pcap_socket(self):
        """Process a PCAP file with Suricata in socket mode."""
        if not HAVE_SURICATASC:
            raise CuckooProcessingError(
                "Suricata has been configured to run in socket mode but "
                "suricatasc has not been installed, please re-install "
                "Suricata or SuricataSC"
            )

        if not os.path.exists(self.socket):
            raise CuckooProcessingError(
                "Suricata has been configured to run in socket mode "
                "but the socket is unavailable"
            )

        suri = suricatasc.SuricataSC(self.socket)

        try:
            suri.connect()
        except suricatasc.SuricataException as e:
            raise CuckooProcessingError(
                "Error connecting to Suricata in socket mode: %s" % e
            )

        # Submit the PCAP file.
        ret = suri.send_command("pcap-file", {
            "filename": self.pcap_path,
            "output-dir": self.suricata_path,
        })

        if not ret or ret["return"] != "OK":
            raise CuckooProcessingError(
                "Error submitting PCAP file to Suricata in socket mode, "
                "return value: %s" % ret
            )

        # TODO Should we add a timeout here? If we do so we should also add
        # timeout logic to the binary mode.
        while True:
            ret = suri.send_command("pcap-current")

            # When the pcap file has been processed the "current pcap" file
            # will be none.
            if ret and ret["message"] == "None":
                break

            time.sleep(1)
예제 #10
0
    def run(self, results):
        """Submits results to MISP.
        @param results: Cuckoo results dict.
        """
        url = self.options.get("url")
        apikey = self.options.get("apikey")
        mode = shlex.split(self.options.get("mode") or "")

        if not url or not apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP instance."
            )

        self.misp = pymisp.PyMISP(url, apikey, False, "json")

        sample_filename=os.path.basename(self.task["target"])

        distribution = self.options.get("distribution") or 0
        threat_level = self.options.get("threat_level") or 4
        analysis = self.options.get("analysis") or 0

        event = self.misp.new_event(
            distribution = distribution,
            threat_level_id = threat_level,
            analysis = analysis,
            info="Cuckoo Sandbox analysis for %s (#%d)" % (sample_filename, self.task["id"]),
        )

        if results.get("target", {}).get("category") == "file":
            self.misp.upload_sample(
                filename=sample_filename,
                filepath_or_bytes=self.task["target"],
                event_id=event["Event"]["id"],
                distribution=distribution,
                to_ids=False,
                category="External analysis",
            )

        if "hashes" in mode:
            self.sample_hashes(results, event)

        if "maldoc" in mode:
            self.maldoc_network(results, event)

        if "url" in mode:
            self.all_urls(results, event)

        if "ipaddr" in mode:
            self.domain_ipaddr(results, event)

        if "dropped" in mode:
            self.dropped_hashes(results, event)

        tag = self.options.get("tag")
	    if tag:
	        results = self.misp.add_tag(event, tag)
	        if results.has_key('message'):
	            log.warning("Cannot tag event: %s" % results['message'])
예제 #11
0
    def run(self):
        self.key = "mlmd"

        try:
            if os.path.exists(self.file_path):
                #extract PE data, send to MLMD server, set data=reply
                features = feature_extractor.get_features(self.file_path)
                res = requests.post("http://localhost:8080/ML",json=features)
                data = res.json()
        except SomethingFailed:
            raise CuckooProcessingError("Failed")

        return data
예제 #12
0
파일: network.py 프로젝트: zhaistone/cuckoo
def iplayer_from_raw(raw, linktype=1):
    """Converts a raw packet to a dpkt packet regarding of link type.
    @param raw: raw packet
    @param linktype: integer describing link type as expected by dpkt
    """
    if linktype == 1:  # ethernet
        try:
            pkt = dpkt.ethernet.Ethernet(raw)
            return pkt.data
        except dpkt.NeedData:
            pass
    elif linktype == 101:  # raw
        return dpkt.ip.IP(raw)
    else:
        raise CuckooProcessingError("unknown PCAP linktype")
예제 #13
0
파일: misp.py 프로젝트: yinjingjiu/cuckoo
    def run(self, results):
        """Submits results to MISP.
        @param results: Cuckoo results dict.
        """
        url = self.options.get("url")
        apikey = self.options.get("apikey")
        mode = shlex.split(self.options.get("mode") or "")

        if not url or not apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP instance.")

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            import pymisp

        self.misp = pymisp.PyMISP(url, apikey, False, "json")

        event = self.misp.new_event(
            distribution=pymisp.Distribution.all_communities.value,
            threat_level_id=pymisp.ThreatLevel.undefined.value,
            analysis=pymisp.Analysis.completed.value,
            info="Cuckoo Sandbox analysis #%d" % self.task["id"],
        )

        if results.get("target", {}).get("category") == "file":
            self.misp.upload_sample(
                filename=os.path.basename(self.task["target"]),
                filepath_or_bytes=self.task["target"],
                event_id=event["Event"]["id"],
                category="External analysis",
            )

        self.signature(results, event)

        if "hashes" in mode:
            self.sample_hashes(results, event)

        if "url" in mode:
            self.all_urls(results, event)

        if "ipaddr" in mode:
            self.domain_ipaddr(results, event)

        self.family(results, event)
예제 #14
0
    def run(self):
        """Run analysis.
        @return: MISP results dict.
        """
        self.url = self.options.get("url", "")
        self.apikey = self.options.get("apikey", "")
        maxioc = int(self.options.get("maxioc", 100))

        if not self.url or not self.apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP instance."
            )

        self.key = "misp"
        self.iocs = {}

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            import pymisp

        self.misp = pymisp.PyMISP(self.url, self.apikey, False, "json")
        iocs = set()

        iocs.add(self.results.get("target", {}).get("file", {}).get("md5"))

        for dropped in self.results.get("dropped", []):
            iocs.add(dropped.get("md5"))

        iocs.update(self.results.get("network", {}).get("hosts", []))

        for block in self.results.get("network", {}).get("domains", []):
            iocs.add(block.get("ip"))
            iocs.add(block.get("domain"))

        # Remove empty entries and turn the collection into a list.
        iocs = list(iocs.difference((None, "")))

        # Acquire all information related to IOCs.
        for ioc in iocs[:maxioc]:
            self.search_ioc(ioc)

        # Sort IOC information by date and return all information.
        return sorted(
            self.iocs.values(), key=self._parse_date, reverse=True
        )
예제 #15
0
    def run(self, results):
        """Submits results to MISP.
        @param results: Cuckoo results dict.
        """
        url = self.options.get("url")
        apikey = self.options.get("apikey")
        mode = shlex.split(self.options.get("mode") or "")

        if not url or not apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP instance."
            )

        self.misp = pymisp.PyMISP(url, apikey, False, "json")

        event = self.misp.new_event(
            distribution=self.misp.distributions.all_communities,
            threat_level_id=self.misp.threat_level.undefined,
            analysis=self.misp.analysis.completed,
            info="Cuckoo Sandbox analysis #%d" % self.task["id"],
        )

        if results.get("target", {}).get("category") == "file":
            self.misp.upload_sample(
                filename=os.path.basename(self.task["target"]),
                filepath=self.task["target"],
                event_id=event["Event"]["id"],
                category="External analysis",
            )

        if "hashes" in mode:
            self.sample_hashes(results, event)

        if "maldoc" in mode:
            self.maldoc_network(results, event)

        if "url" in mode:
            self.all_urls(results, event)

        if "ipaddr" in mode:
            self.domain_ipaddr(results, event)
예제 #16
0
    def run(self):
        self.key = "snort"

        results = {
            "alerts": [],
        }

        self.snort = self.options.get("snort", "/usr/local/bin/snort")
        self.config_path = self.options.get("conf", "/etc/snort/snort.conf")

        if not os.path.isfile(self.pcap_path):
            log.warning("Unable to run Snort as no pcap is available")
            return results

        if not os.path.isfile(self.snort):
            raise CuckooProcessingError("Unable to locate Snort binary")

        if not os.path.isfile(self.config_path):
            raise CuckooProcessingError("Unable to locate Snort configuration")

        args = [
            self.snort,
            "-c",
            self.config_path,
            "-A",
            "console",
            "-r",
            self.pcap_path,
            "-q",
            "-y",
        ]

        try:
            output = subprocess.check_output(args)
        except subprocess.CalledProcessError as e:
            raise CuckooProcessingError(
                "Snort returned an error processing this pcap: %s" % e)

        for line in output.split("\n"):
            if not line:
                continue

            x = self.alert_re.match(line)
            if not x:
                log.warning("Error matching Snort line: %r", line)
                continue

            timestamp = datetime.datetime.strptime(x.group("timestamp"),
                                                   "%m/%d/%y-%H:%M:%S.%f")

            if ":" in x.group("src"):
                src_ip, src_port = x.group("src").rsplit(":", 1)
            else:
                src_ip = x.group("src")
                src_port = None

            if ":" in x.group("dest"):
                dst_ip, dst_port = x.group("dest").rsplit(":", 1)
            else:
                dst_ip = x.group("dest")
                dst_port = None

            results["alerts"].append({
                "timestamp":
                timestamp,
                "sid":
                int(x.group("sid")),
                "priority":
                int(x.group("priority")),
                "revision":
                int(x.group("revision")),
                "message":
                x.group("message"),
                "src_ip":
                src_ip,
                "src_port":
                int(src_port) if src_port else None,
                "dst_ip":
                dst_ip,
                "dst_port":
                int(dst_port) if dst_port else None,
                "protocol":
                x.group("protocol"),
                "classtype":
                x.group("classtype"),
            })

        return results
예제 #17
0
    def run(self):

        self.key = "curtain"
        # Remove some event entries which are commonly found in all samples (noise reduction)
        noise = [
            "$global:?", "# Compute file-hash using the crypto object",
            "# Construct the strongly-typed crypto object",
            "HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=285758'",
            "[System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($args[0])",
            "[System.Management.ManagementDateTimeConverter]::ToDateTime($args[0])",
            "Set-Location Z:", "Set-Location Y:", "Set-Location X:",
            "Set-Location W:", "Set-Location V:", "Set-Location U:",
            "Set-Location T:", "Set-Location S:", "Set-Location R:",
            "Set-Location Q:", "Set-Location P:", "Set-Location O:",
            "Set-Location N:", "Set-Location M:", "Set-Location L:",
            "Set-Location K:", "Set-Location J:", "Set-Location I:",
            "Set-Location H:", "Set-Location G:", "Set-Location F:",
            "Set-Location E:", "Set-Location D:", "Set-Location C:",
            "Set-Location B:", "Set-Location A:", "Set-Location ..",
            "Set-Location \\",
            "$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Out-String',[System.Management.Automation.CommandTypes]::Cmdlet)",
            "$str.Substring($str.LastIndexOf('Verbs') + 5)",
            "[Parameter(ParameterSetName='nameSet', Position=0, ValueFromPipelineByPropertyName=$true)]",
            "[ValidateSet('Alias','Cmdlet','Provider','General','FAQ','Glossary','HelpFile'",
            "param([string[]]$paths)",
            "$origin = New-Object System.Management.Automation.Host.Coordinates",
            "Always resolve file paths using Resolve-Path -Relative.",
            "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1))",
            "$this.ServiceName",
            "Read-Host 'Press Enter to continue...' | Out-Null",
            "([System.Management.Automation.CommandTypes]::Script)",
            "if ($myinv -and ($myinv.MyCommand -or ($_.CategoryInfo.Category -ne 'ParserError')))",
            "CmdletsToExport=@(", "CmdletsToExport", "FormatsToProcess",
            "AliasesToExport", "FunctionsToExport", "$_.PSParentPath.Replace",
            "$ExecutionContext.SessionState.Path.Combine",
            "get-help about_Command_Precedence"
        ]

        # Determine oldest Curtain log and remove the rest
        curtLog = os.listdir("%s/curtain/" % self.analysis_path)
        curtLog.sort()
        curtLog = curtLog[-1]

        # Leave only the most recent file
        for file in os.listdir("%s/curtain/" % self.analysis_path):
            if file != curtLog:
                try:
                    os.remove("%s/curtain/%s" % (self.analysis_path, file))
                except:
                    pass

        os.rename("%s/curtain/%s" % (self.analysis_path, curtLog),
                  "%s/curtain/curtain.log" % self.analysis_path)

        try:
            tree = ET.parse("%s/curtain/curtain.log" % self.analysis_path)
            root = tree.getroot()
        except Exception as e:
            raise CuckooProcessingError("Failed opening curtain.log: %s" %
                                        e.message)

        pids = {}
        COUNTER = 0
        FILTERED = 0

        for i in range(0, len(root)):

            # Setup PID Dict
            if root[i][0][1].text == "4104":

                FILTERFLAG = 0

                PID = root[i][0][10].attrib['ProcessID']
                #TID = root[i][0][10].attrib['ThreadID']

                MESSAGE = root[i][1][2].text

                if PID not in pids:
                    pids[PID] = {"pid": PID, "events": [], "filter": []}

                # Checks for unique strings in events to filter out
                if MESSAGE != None:
                    for entry in noise:
                        if entry in MESSAGE:
                            FILTERFLAG = 1
                            FILTERED += 1
                            pids[PID]["filter"].append(
                                {str(FILTERED): MESSAGE.strip()})

                # Save the record
                if FILTERFLAG == 0 and MESSAGE != None:

                    COUNTER += 1
                    MODFLAG = 0

                    # Attempt to further decode token replacement/other common obfuscation
                    # Original and altered will be saved
                    ALTMSG = MESSAGE.strip()

                    if re.search("\x00", ALTMSG):
                        ALTMSG, MODFLAG = removeNull(ALTMSG, MODFLAG)

                    if re.search("(\\\"|\\\')", ALTMSG):
                        ALTMSG, MODFLAG = removeEscape(ALTMSG, MODFLAG)

                    if re.search("`", ALTMSG):
                        ALTMSG, MODFLAG = removeTick(ALTMSG, MODFLAG)

                    if re.search("\^", ALTMSG):
                        ALTMSG, MODFLAG = removeCaret(ALTMSG, MODFLAG)

                    while re.search("[\x20]{2,}", ALTMSG):
                        ALTMSG, MODFLAG = spaceReplace(ALTMSG, MODFLAG)

                    if re.search("\[[Cc][Hh][Aa][Rr]\][0-9]{1,3}", ALTMSG):
                        ALTMSG, MODFLAG = charReplace(ALTMSG, MODFLAG)

                    # One run pre formatReplace
                    if re.search("(\"\+\"|\'\+\')", ALTMSG):
                        ALTMSG, MODFLAG = joinStrings(ALTMSG, MODFLAG)

                    while re.search(
                            "(\"|\')(\{[0-9]{1,2}\})+(\"|\')[ -fF]+(\'.+?\'\))",
                            ALTMSG):
                        ALTMSG, MODFLAG = formatReplace(ALTMSG, MODFLAG)

                    # One run post formatReplace for new strings
                    if re.search("(\"\+\"|\'\+\')", ALTMSG):
                        ALTMSG, MODFLAG = joinStrings(ALTMSG, MODFLAG)

                    if "replace" in ALTMSG.lower():
                        try:
                            ALTMSG, MODFLAG = replaceDecoder(ALTMSG, MODFLAG)
                        except Exception as e:
                            log.error(
                                "Curtain processing error for entry - %s" % e)

                    # Remove camel case obfuscation as last step
                    ALTMSG, MODFLAG = adjustCase(ALTMSG, MODFLAG)

                    if MODFLAG == 0:
                        ALTMSG = "No alteration of event."

                    # Save the output
                    pids[PID]["events"].append({
                        str(COUNTER): {
                            "original": MESSAGE.strip(),
                            "altered": ALTMSG
                        }
                    })

        remove = []

        # Find Curtain PID if it was picked up in log
        for pid in pids:
            for event in pids[pid]["events"]:
                for entry in event.values():
                    if "Process { [System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog" in entry[
                            "original"]:
                        if pid not in remove:
                            remove.append(pid)

        # Find empty PID
        for pid in pids:
            if len(pids[pid]["events"]) == 0:
                if pid not in remove:
                    remove.append(pid)

        # Remove PIDs
        for pid in remove:
            del pids[pid]

        # Reorder event counts
        for pid in pids:
            tempEvents = []
            eventCount = len(pids[pid]["events"])
            for index, entry in enumerate(pids[pid]["events"]):
                tempEvents.append(
                    {"%02d" % (eventCount - index): entry.values()[0]})
            pids[pid]["events"] = tempEvents

            tempEvents = []
            eventCount = len(pids[pid]["filter"])
            for index, entry in enumerate(pids[pid]["filter"]):
                tempEvents.append(
                    {"%02d" % (eventCount - index): entry.values()[0]})
            pids[pid]["filter"] = tempEvents

        # Identify behaviors per PID
        for pid in pids:
            behaviorTags = []
            for entry in pids[pid]["events"]:
                behaviorTags = buildBehaviors(entry, behaviorTags)
                pids[pid]["behaviors"] = behaviorTags

        return pids
예제 #18
0
    def run(self):
        """Runs TIE processing
        @return: TIE results
        """
        log.info("Processing TIE reputation analysis.")

        self.key = "tie"
        timeout = int(self.options.get("timeout", 60))
        scan = int(self.options.get("scan", 0))

        # Evaluate the original sample against TIE reputation
        if self.task["category"] == "file":
            # Create the client
            with DxlClient(config) as client:
                # Connect to the fabric
                client.connect()

                tie_client = TieClient(client)

                #Generate relevant hash information
                md5_hex = File(self.file_path).get_md5()
                sha1_hex = File(self.file_path).get_sha1()
                sha256_hex = File(self.file_path).get_sha256()

                #Request raw json reputation results
                reputations_dict = \
                        tie_client.get_file_reputation({
                        HashType.MD5: md5_hex,
                        HashType.SHA1: sha1_hex,
                        HashType.SHA256: sha256_hex
                        })

                #debug
                log.info("Raw TIE results: " +
                         json.dumps(reputations_dict,
                                    sort_keys=True,
                                    indent=4,
                                    separators=(',', ': ')))

                #initialize result array and tiekey counter for each result
                proc_result = {}
                tiekey = 0
                strtiekey = str(tiekey)
                # Display the Global Threat Intelligence
                if FileProvider.GTI in reputations_dict:
                    gti_rep = reputations_dict[FileProvider.GTI]
                    proc_result[strtiekey] = {}
                    proc_result[strtiekey][
                        'title'] = "Global Threat Intelligence (GTI) Test Date:"
                    proc_result[strtiekey][
                        'value'] = EpochMixin.to_localtime_string(
                            gti_rep[ReputationProp.CREATE_DATE])
                    tiekey += 1
                    strtiekey = str(tiekey)

                    #Set GTI Trust Level
                    proc_result[strtiekey] = {}
                    proc_result[strtiekey][
                        'title'] = "Global Threat Intelligence (GTI) trust level:"
                    trustValue = gti_rep[ReputationProp.TRUST_LEVEL]
                    proc_result[strtiekey]['value'] = self.trustLevel(
                        trustValue)
                    tiekey += 1
                    strtiekey = str(tiekey)

                # Display the Enterprise reputation information
                if FileProvider.ENTERPRISE in reputations_dict:
                    ent_rep = reputations_dict[FileProvider.ENTERPRISE]

                    # Retrieve the enterprise reputation attributes
                    ent_rep_attribs = ent_rep[ReputationProp.ATTRIBUTES]

                    # Display prevalence (if it exists)
                    if FileEnterpriseAttrib.PREVALENCE in ent_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey][
                            'title'] = "Enterprise prevalence:"
                        proc_result[strtiekey]['value'] = ent_rep_attribs[
                            FileEnterpriseAttrib.PREVALENCE]
                        tiekey += 1
                        strtiekey = str(tiekey)

                    # Display first contact date (if it exists)
                    if FileEnterpriseAttrib.FIRST_CONTACT in ent_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey]['title'] = "First contact: "
                        proc_result[strtiekey][
                            'value'] = FileEnterpriseAttrib.to_localtime_string(
                                ent_rep_attribs[
                                    FileEnterpriseAttrib.FIRST_CONTACT])
                        tiekey += 1
                        strtiekey = str(tiekey)

                #These are lookup conversions for the ATD trust_score
                valueDict = {}
                valueDict['-1'] = "Known Trusted"
                valueDict['0'] = "Most Likely Trusted"
                valueDict['1'] = "Might Be Trusted"
                valueDict['2'] = "Unknown"
                valueDict['3'] = "Might Be Malicious"
                valueDict['4'] = "Most Likely Malicious"
                valueDict['5'] = "Known Malicious"
                valueDict['-2'] = "Not Set"

                # Display the ATD reputation information
                if FileProvider.ATD in reputations_dict:
                    atd_rep = reputations_dict[FileProvider.ATD]

                    # Retrieve the ATD reputation attributes
                    atd_rep_attribs = atd_rep[ReputationProp.ATTRIBUTES]

                    proc_result[strtiekey] = {}
                    proc_result[strtiekey]['title'] = "ATD Test Date: "
                    proc_result[strtiekey][
                        'value'] = EpochMixin.to_localtime_string(
                            atd_rep[ReputationProp.CREATE_DATE])
                    tiekey += 1
                    strtiekey = str(tiekey)

                    # Display GAM Score (if it exists)
                    if AtdAttrib.GAM_SCORE in atd_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey][
                            'title'] = "ATD Gateway AntiMalware Score: "
                        proc_result[strtiekey]['value'] = valueDict[
                            atd_rep_attribs[AtdAttrib.GAM_SCORE]]
                        tiekey += 1
                        strtiekey = str(tiekey)

                    # Display AV Engine Score (if it exists)
                    if AtdAttrib.AV_ENGINE_SCORE in atd_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey][
                            'title'] = "ATD AV Engine Score: "
                        proc_result[strtiekey]['value'] = valueDict[
                            atd_rep_attribs[AtdAttrib.AV_ENGINE_SCORE]]
                        tiekey += 1
                        strtiekey = str(tiekey)

                    # Display Sandbox Score (if it exists)
                    if AtdAttrib.SANDBOX_SCORE in atd_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey]['title'] = "ATD Sandbox Score: "
                        proc_result[strtiekey]['value'] = valueDict[
                            atd_rep_attribs[AtdAttrib.SANDBOX_SCORE]]
                        tiekey += 1
                        strtiekey = str(tiekey)

                    # Display Verdict (if it exists)
                    if AtdAttrib.VERDICT in atd_rep_attribs:
                        proc_result[strtiekey] = {}
                        proc_result[strtiekey]['title'] = "ATD Verdict: "
                        proc_result[strtiekey]['value'] = valueDict[
                            atd_rep_attribs[AtdAttrib.VERDICT]]
                        tiekey += 1
                        strtiekey = str(tiekey)

                results = proc_result

        elif self.task["category"] == "url":
            return
        elif self.task["category"] == "baseline":
            return
        elif self.task["category"] == "service":
            return
        else:
            raise CuckooProcessingError("Unsupported task category: %s" %
                                        self.task["category"])

        log.info("Finished processing TIE reputation analysis.")
        return results
예제 #19
0
import logging
import json

from cuckoo.common.abstracts import Processing
from cuckoo.common.exceptions import CuckooProcessingError

log = logging.getLogger(__name__)

__author__ = "haam3r"
__version__ = "1.0.0"
__date__ = "2018-09-05"

try:
    import xmltodict
except ImportError:
    raise CuckooProcessingError('Unable to import required xmltodict module')


class Sysmon(Processing):
    """Parse exported Sysmon XML file to a json file"""
    def run(self):
        self.key = "sysmon"

        try:
            with open('%s/sysmon/sysmon.xml' % self.analysis_path) as xmlfile:
                data = xmltodict.parse(xmlfile)
        except Exception as e:
            raise CuckooProcessingError("Failed opening sysmon log: %s"
                                        & e.message)

        clean = {}
예제 #20
0
파일: misp.py 프로젝트: z6s469s1/cuckoo
    def run(self, results):
        """Submit results to MISP.
        @param results: Cuckoo results dict.
        """
        url = self.options.get("url")
        apikey = self.options.get("apikey")
        mode = shlex.split(self.options.get("mode") or "")
        score = results.get("info", {}).get("score", 0)
        upload_sample = self.options.get("upload_sample")

        if results.get("target", {}).get("category") == "file":
            f = results.get("target", {}).get("file", {})
            hash_safelisted = is_safelisted_misphash(f["md5"]) or \
                               is_safelisted_misphash(f["sha1"]) or \
                               is_safelisted_misphash(f["sha256"])

            if hash_safelisted:
                return

        if score < self.options.get("min_malscore", 0):
            return

        if not url or not apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP "
                "instance."
            )

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            import pymisp

        self.misp = pymisp.PyMISP(url, apikey, False, "json")

        # Get default settings for a new event
        distribution = self.options.get("distribution") or 0
        threat_level = self.options.get("threat_level") or 4
        analysis = self.options.get("analysis") or 0
        tag = self.options.get("tag") or "Cuckoo"

        event = self.misp.new_event(
            distribution=distribution,
            threat_level_id=threat_level,
            analysis=analysis,
            info="Cuckoo Sandbox analysis #%d" % self.task["id"]
        )

        # Add a specific tag to flag Cuckoo's event
        if tag:
            mispresult = self.misp.tag(event["Event"]["uuid"], tag)
            if mispresult.has_key("message"):
                log.debug("tag event: %s" % mispresult["message"])

        if upload_sample:
            target = results.get("target", {})
            if target.get("category") == "file" and target.get("file"):
                self.misp.upload_sample(
                    filename=os.path.basename(self.task["target"]),
                    filepath_or_bytes=self.task["target"],
                    event_id=event["Event"]["id"],
                    category="External analysis",
                )

        self.signature(results, event)

        if "hashes" in mode:
            self.sample_hashes(results, event)

        if "url" in mode:
            self.all_urls(results, event)

        if "ipaddr" in mode:
            self.domain_ipaddr(results, event)

        self.family(results, event)
예제 #21
0
    def run(self):
        """Run analysis.
        @return: MISP results dict.
        """

        if not HAVE_MISP:
            raise CuckooDependencyError(
                "Unable to import PyMISP (install with `pip install pymisp`)"
            )

        self.url = self.options.get("url", "")
        self.apikey = self.options.get("apikey", "")
        maxioc = int(self.options.get("maxioc", 100))

        if not self.url or not self.apikey:
            raise CuckooProcessingError(
                "Please configure the URL and API key for your MISP instance."
            )

        self.key = "misp"
        self.iocs = {}
        self.iocs_network = {}
        self.iocs_hashes = {}

        self.misp = PyMISP(self.url, self.apikey, False, "json")
        iocs = set()
        iocs_network = set()
        iocs_hashes = set()

        iocs.add(self.results.get("target", {}).get("file", {}).get("md5"))
        iocs_hashes.add(self.results.get("target", {}).get("file", {}).get("md5"))

        for dropped in self.results.get("dropped", []):
            iocs.add(dropped.get("md5"))
            iocs_hashes.add(dropped.get("md5"))

        iocs.update(self.results.get("network", {}).get("hosts", []))
        iocs_network.update(self.results.get("network", {}).get("hosts", []))

        for block in self.results.get("network", {}).get("domains", []):
            iocs.add(block.get("ip"))
            iocs_network.add(block.get("ip"))
            iocs.add(block.get("domain"))
            iocs_network.add(block.get("domain"))


        # Remove empty entries and turn the collection into a list.
        iocs = list(iocs.difference((None, "")))
        iocs_hashes = list(iocs_hashes.difference((None, "")))
        iocs_network = list(iocs_network.difference((None, "")))

        # Acquire all information related to IOCs.
        # hash blacklist not used atm
        #for ioc in iocs_hashes[:maxioc]:
            #self.search_ioc(ioc, "hash")

        for ioc in iocs_network[:maxioc]:
            print ioc
            self.search_ioc(ioc, "network")

        # Sort IOC information by date and return all information.
        return sorted(
            self.iocs.values(), key=self._parse_date, reverse=True
        )
예제 #22
0
    def run(self):
        """Run debug analysis.
        @return: debug information dict.
        """
        self.key = "debug"
        debug = {
            "log": [],
            "cuckoo": [],
            "action": [],
            "dbgview": [],
            "errors": [],
        }

        if os.path.exists(self.log_path):
            try:
                f = codecs.open(self.log_path, "rb", "utf-8")
                debug["log"] = f.readlines()
            except ValueError as e:
                raise CuckooProcessingError("Error decoding %s: %s" %
                                            (self.log_path, e))
            except (IOError, OSError) as e:
                raise CuckooProcessingError("Error opening %s: %s" %
                                            (self.log_path, e))
        else:
            log.error(
                "Error processing task #%d: it appears that the Virtual "
                "Machine (%s) hasn't been able to contact back to "
                "the Cuckoo Host. There could be a few reasons for this, "
                "please refer to our documentation on the matter: %s",
                self.task.id,
                self.machine.get("name"),
                faq("troubleshooting-vm-network-configuration"),
                extra={
                    "error_action": "vmrouting",
                    "action": "guest.communication",
                    "status": "error",
                    "task_id": self.task.id,
                })

        if os.path.exists(self.cuckoolog_path):
            debug["cuckoo"] = Logfile(self.cuckoolog_path)

        dbgview_log = os.path.join(self.analysis_path, "logs", "dbgview.log")
        if os.path.exists(dbgview_log):
            f = open(dbgview_log, "rb")
            # Ignore the first line which identifies the machine.
            f.readline()
            for line in f:
                idx, time, message = line.split("\t", 2)
                debug["dbgview"].append(message.strip())

        debug["errors"] = []
        for error in Database().view_errors(self.task["id"]):
            if error.message and error.message not in debug["errors"]:
                debug["errors"].append(error.message)

            if error.action and error.action not in debug["action"]:
                debug["action"].append(error.action)

        if os.path.exists(self.mitmerr_path):
            mitmerr = open(self.mitmerr_path, "rb").read()
            if mitmerr and mitmerr not in debug["errors"]:
                debug["errors"].append(mitmerr)

        return debug
예제 #23
0
    def run(self):
        """Run Floss on analyzed file.
        @return: Floss results dict.
        """
        self.key = "strings"
        self.floss = self.options.get("floss")
        self.MIN_STRINGLEN = int(self.options.get("min_str_len"))
        self.MAX_STRINGLEN = self.options.get("max_str_len")
        self.MAX_STRINGCNT = self.options.get("max_str_cnt")
        self.MAX_FILESIZE = 16*1024*1024
        
        STRING_TYPES = [
            "decoded",
            "stack",
            "static"
        ]
        
        strings = {}

        if self.task["category"] == "file":
            if not os.path.exists(self.file_path):
                raise CuckooProcessingError(
                    "Sample file doesn't exist: \"%s\"" % self.file_path
                )

            try:
                f = File(self.file_path)
                filename = os.path.basename(self.task["target"])
                base_name = os.path.splitext(filename)[0]
                ext = filename.split(os.path.extsep)[-1].lower()
                data = open(self.file_path, "r").read(self.MAX_FILESIZE)
            except (IOError, OSError) as e:
                raise CuckooProcessingError("Error opening file %s" % e)
            
            # Extract static strings
            static_strings = re.findall("[\x1f-\x7e]{" + str(self.MIN_STRINGLEN) + ",}", data)
            for s in re.findall("(?:[\x1f-\x7e][\x00]){" + str(self.MIN_STRINGLEN) + ",}", data):
                static_strings.append(s.decode("utf-16le"))

            if self.MAX_STRINGLEN != 0:
                for i, s in enumerate(static_strings):
                    static_strings[i] = s[:self.MAX_STRINGLEN]

            if self.MAX_STRINGCNT != 0 and len(static_strings) > self.MAX_STRINGCNT:
                static_strings = static_strings[:self.MAX_STRINGCNT]
                static_strings.append("[snip]")

            package = self.task.get("package")

            if self.floss and (package == "exe" or ext == "exe" or "PE32" in f.get_type()):
                # Disable floss verbose logging
                main.set_logging_levels()
                
                try:
                    # Prepare Floss for extracting hidden & encoded strings
                    vw = vivisect.VivWorkspace()
                    vw.loadFromFile(self.file_path)
                    vw.analyze()

                    selected_functions = main.select_functions(vw, None)
                    decoding_functions_candidates = id_man.identify_decoding_functions(
                        vw, main.get_all_plugins(), selected_functions
                    )
                except Exception as e:
                    raise CuckooProcessingError("Error analyzing file with vivisect: %s" % e)

                try:
                    # Decode & extract hidden & encoded strings
                    decoded_strings = main.decode_strings(
                        vw, decoding_functions_candidates, self.MIN_STRINGLEN
                    )
                    decoded_strs = main.filter_unique_decoded(decoded_strings)

                    stack_strings = stackstrings.extract_stackstrings(
                        vw, selected_functions, self.MIN_STRINGLEN
                    )
                    stack_strings = list(stack_strings)

                    decoded_strings = [x for x in decoded_strs if not x in static_strings]
                except Exception as e:
                    raise CuckooProcessingError("Error extracting strings with floss: %s" % e)

                if len(decoded_strings) or len(stack_strings):
                    # Create annotated scripts
                    if self.options.get("idapro_str_sct"):
                        idapro_sct_name = base_name + ".idb"
                        strings["idapro_sct_name"] = idapro_sct_name

                        main.create_ida_script(
                            self.file_path, os.path.join(self.str_script_path, idapro_sct_name), 
                            decoded_strings, stack_strings
                        )

                    if self.options.get("radare_str_sct"):
                        radare_sct_name = base_name + ".r2"
                        strings["radare_sct_name"] = radare_sct_name

                        main.create_r2_script(
                            self.file_path, os.path.join(self.str_script_path, radare_sct_name), 
                            decoded_strings, stack_strings
                        )

                    if self.options.get("x64dbg_str_sct"):
                        x64dbg_sct_name = base_name + ".json"
                        strings["x64dbg_sct_name"] = x64dbg_sct_name

                        imagebase = vw.filemeta.values()[0]['imagebase']
                        main.create_x64dbg_database(
                            self.file_path, os.path.join(self.str_script_path, base_name + ".json"), 
                            imagebase, decoded_strings
                        )

                # convert Floss strings into regular, readable strings
                for idx, s in enumerate(decoded_strings):
                    decoded_strings[idx] = main.sanitize_string_for_printing(s.s)

                for idx, s in enumerate(stack_strings):
                    stack_strings[idx] = s.s

                results = [decoded_strings, stack_strings, static_strings]

                for idx, str_type in enumerate(STRING_TYPES):
                    strings[str_type] = results[idx]

            else:
                strings["static"] = static_strings

        return strings