Ejemplo n.º 1
0
 def make_result(self, scan_id, result=None, md5=None):
     try:
         result = self.virustotal_analysis.get_report(
             scan_id) if not result else result
     except Exception as e:
         raise AnalysisTemporaryError(message="API error: %s" % str(e),
                                      retry_in=120)
     else:
         total = int(result.get("total", 1))
         positives = int(result.get("positives", 0))
         score = int(float(positives) / float(total) * 100)
         if score == 0:
             return AnalysisResult(message="Benign",
                                   extended_message="",
                                   link=result['permalink'],
                                   score=score)
         else:
             scans = result.get("scans", {})
             detected_by = filter(
                 lambda (k, v): v.get('detected', False) is True,
                 scans.iteritems())
             detected_by = map(
                 lambda (k, v): (k, v.get("result", "potential_malware")),
                 detected_by)
             log.info("detected by = %s " % detected_by)
             report_string = "VirusTotal Report:\n" + "\n".join(
                 [k + " :\t" + v for (k, v) in detected_by])
             malware_result = "[%d / %d] VirusTotal report for %s" % (
                 positives, total, md5)
             return AnalysisResult(message=malware_result,
                                   extended_message=report_string,
                                   link=result['permalink'],
                                   score=score)
Ejemplo n.º 2
0
    def analyze_binary(self, md5sum, binary_file_stream):
        log.debug("%s: in analyze_binary" % md5sum)
        d = binary_file_stream.read()

        try:
            start_analyze_time = time.time()
            matches = self.yara_rules.match(data=d, timeout=60)
            end_analyze_time = time.time()
            log.debug("%s: Took %0.3f seconds to analyze the file" %
                      (md5sum, end_analyze_time - start_analyze_time))
        except yara.TimeoutError:
            raise AnalysisPermanentError(
                message="Analysis timed out after 60 seconds")
        except yara.Error:
            raise AnalysisTemporaryError(message="Yara exception", retry_in=10)
        else:
            if matches:
                score = self.getHighScore(matches)
                return AnalysisResult(
                    message="Matched yara rules: %s" %
                    ', '.join([match.rule for match in matches]),
                    extended_message="%s" %
                    ', '.join([match.rule for match in matches]),
                    analysis_version=1,
                    score=score)
            else:
                return AnalysisResult(score=0)
Ejemplo n.º 3
0
    def generate_malware_result(self, md5, score):
        status_code, content = self._call_wildfire_api("POST", "/publicapi/get/report",
                                                       {'hash': md5.lower(), "format": "pdf"})

        if status_code == 200:
            open(os.path.join(self.work_directory, md5.upper()) + ".pdf", 'wb').write(content)
            return AnalysisResult(score=score, link="/reports/%s.pdf" % md5.upper())
        else:
            return AnalysisResult(score=score)
Ejemplo n.º 4
0
    def make_result(self, result=None, md5=None):
        log.info("making result for md5 {0}".format(md5 if md5 else "None"))
        try:
            result = self.fortisandbox_analysis.get_report(
                resource_hash=md5).json() if not result else result
        except Exception as e:
            raise AnalysisTemporaryError(message="API error: %s" % str(e),
                                         retry_in=120)
        else:
            result = result.get('result', {})
            data = result.get('data', {})
            score = int(data.get('score'))
            """RISK_UNKNOWN = 0
            RISK_CLEAN = 1
            RISK_MALICIOUS = 2
            RISK_LOW = 4
            RISK_MEDIUM = 8
            RISK_HIGH = 16"""
            RISK_MATRIX = {0: 0, 1: 0, 4: 25, 8: 50, 16: 75, 2: 100}
            score = RISK_MATRIX[score] if score in RISK_MATRIX else score
            untrusted = int(data.get('untrusted', "0"))
            if score == 0:
                if (self.fortisandbox_trust_untrusted
                        and untrusted == 1) or untrusted == 0:
                    return AnalysisResult(message="Benign",
                                          extended_message="",
                                          link=str(data['rating']),
                                          score=score)
                else:
                    raise AnalysisTemporaryError(
                        message=
                        "Configured to not trust untrusted scans, retrying in 120 seconds",
                        retry_in=120)

            else:
                ratings = data.get("rating", [])
                vids = data.get("vid", ['N/A'])
                jids = data.get("jid", ['N/A'])
                malware_names = data.get("malware_name", [])
                report_string = "Fortisandbox Report for {0}:\n".format(md5)
                link = "{0}/job-detail/?jid={1}".format(
                    self.host, str(jids[0]))
                report_string += "Score: {0}\n".format(score)
                report_string += "Malware Names: {0}\n".format(
                    ",".join(malware_names))
                report_string += "Malware Ratings: {0}\n".format(
                    ",".join(ratings))
                report_string += "Virus Ids: {0}\n".format(",".join(
                    [str(vid) for vid in vids]))
                malware_result = "[{0}] FortiSandbox report for {1}".format(
                    score, md5)
                return AnalysisResult(message=malware_result,
                                      extended_message=report_string,
                                      link=link,
                                      score=score)
Ejemplo n.º 5
0
    def create_result(self, sample_id, submission_id=None):
        """Create Carbon Black result for the given sample"""

        LOGGER.debug(
            "Creating result for sample with ID %u (submission_id=%s)",
            sample_id, submission_id)
        try:
            # get sample
            sample = self.rest_api.call("GET", "/rest/sample/%u" % (sample_id))

            # get analyses
            analyses = self.rest_api.call(
                "GET", "/rest/analysis/sample/%u" % (sample_id))
        except BaseException as exc:
            LOGGER.debug(
                "Error getting sample and analyses info for sample ID %u",
                sample_id,
                exc_info=True)
            raise AnalysisTemporaryError(message="API error: %s" % (str(exc)))

        if submission_id is not None:
            # filter by submission ID
            analyses = [
                analysis for analysis in analyses
                if analysis["analysis_submission_id"] == submission_id
            ]

        # check if any error occurred
        for analysis in analyses:
            if analysis["analysis_result_code"] != 1:
                LOGGER.warning(
                    "Analysis with ID %u of sample with ID %u failed with error code 0x%x: %s",
                    analysis["analysis_id"], sample_id,
                    analysis["analysis_result_code"],
                    analysis["analysis_result_str"])

        # check sample VTI score
        if (sample["sample_vti_score"] is None) or (
                sample["sample_vti_score"] < self.vti_score_threshold):
            message = "Benign"
        else:
            message = "Potential malware"

        # Check for None in the score
        if not sample["sample_vti_score"] and message == 'Benign':
            sample["sample_vti_score"] = 0

        if not sample["sample_vti_score"] and message == 'Potential malware':
            sample["sample_vti_score"] = 100

        LOGGER.debug(
            "Analysis result of sample with ID %u created successfully (message=%s link=%s score=%u)",
            sample_id, message, sample["sample_webif_url"],
            sample["sample_vti_score"])
        return AnalysisResult(
            message=message,
            extended_message="",
            link=sample["sample_webif_url"],
            score=sample["sample_vti_score"],
        )
    def make_result(self, md5sum=None, result=None):

        try:
            result = self.rl_analysis.get_report(
                md5sum) if not result else result
        except Exception as err:
            raise AnalysisTemporaryError(message="API error: %s" % str(err),
                                         retry_in=360)

        if result.get('code'):
            raise AnalysisTemporaryError(
                message=
                'No results on A1000. Allow submit_full_binaries to get results on A1000',
                retry_in=15 * 60)

        log.info("Result for md5: %s" % md5sum)
        result_link = urljoin(self.base_url, md5sum)
        threat_score = int(result.get("threat_level"))
        trust_factor = int(result.get("trust_factor"))
        threat_name = result.get("treat_name")

        score = SEVERITY[threat_score]
        status = result.get("threat_status").upper()

        if 'UNKNOWN' in status:
            malware_result = """ReversingLabs report for md5: %s
                                Status: %s""" % (md5sum, status)

            report_string = """Report string (test string)"""
            return AnalysisResult(message=malware_result,
                                  extended_message=report_string,
                                  link=result_link,
                                  score=0)

        malware_result = """"ReversingLabs report for md5: %s.
        Status: %s
        Threat name: %s
        Threat score: %s
        Trust factor: %s""" % (md5sum, status, threat_name, threat_score,
                               trust_factor)

        report_string = """Report string (test string)"""
        return AnalysisResult(message=malware_result,
                              extended_message=report_string,
                              link=result_link,
                              score=score)
    def make_result(self, md5sum, uploaded=False):
        if not uploaded:
            raise AnalysisTemporaryError(
                message="Hash is not yet uploaded to TitaniumScale",
                retry_in=30 * 60)

        malware_result = "File {} uploaded to TitaniumScale, date: {}".format(
            md5sum, datetime.utcnow())
        return AnalysisResult(message=malware_result,
                              extended_message=malware_result,
                              link="Result should be stored in Splunk",
                              score=20)
Ejemplo n.º 8
0
    def make_result(self, md5=None, result=None):

        try:
            result = self.rl_analysis.get_report(md5) if not result else result
        except Exception as err:
            log.info(traceback.format_exc())
            raise AnalysisTemporaryError(message="API error: %s" % str(err),
                                         retry_in=5 * 60)

        log.info("Result for md5: %s" % md5)
        result_link = "%s/uploads/?q=hash%%3A%s" % (
            self.report_visualisation_url.rstrip("/"), md5)
        log.info("Result link: %s" % result_link)

        malware_presence = result['rl']['malware_presence']
        status = malware_presence.get("status").upper()
        threat_name = malware_presence.get("threat_name")
        if threat_name is None:
            threat_name = ""

        threat_level = int(malware_presence.get("threat_level"))
        trust_factor = int(malware_presence.get("trust_factor"))

        score = SEVERITY[threat_level]

        if "scanner_count" in malware_presence and "scanner_match" in malware_presence:
            total_scanners = int(malware_presence.get("scanner_count"))
            scanner_match = int(malware_presence.get("scanner_match"))
            malware_result = """ReversingLabs report for md5: %s; 
                                RL Status: %s %s; 
                                RL Trust Factor: %s; 
                                Threat Level: %s; 
                                AV detection number: %s/%s;
                                """ % \
                             (md5, status, threat_name, trust_factor, threat_level, scanner_match, total_scanners)
        else:
            malware_result = """ReversingLabs report for md5: %s; 
                                RL Status: %s %s; 
                                RL Trust factor: %s; 
                                Threat level: %s;
                                """ % \
                             (md5, status, threat_name, trust_factor, threat_level)

        report_string = """Report string (test string)"""

        return AnalysisResult(message=malware_result,
                              title=malware_result,
                              description=report_string,
                              link=result_link,
                              score=score)
Ejemplo n.º 9
0
    def make_result(self, task_uuid):
        try:
            result = self.lastline_analysis.get_result(task_uuid)
            result = result.get('data', {})
        except Exception as e:
            raise AnalysisTemporaryError(message="API error: %s" % str(e), retry_in=120)
        else:
            if 'error' in result:
                raise AnalysisTemporaryError(message=result['error'], retry_in=120)
            score = int(result.get('score', 0))
            if score == 0:
                malware_result = "Benign"
            else:
                reasons = "; ".join(result.get('malicious_activity', []))
                malware_result = "Potential malware: %s" % reasons

            return AnalysisResult(message=malware_result, extended_message="",
                                  link=re.sub("(?<!:)/{2,}", "/", "%s/%s" % (self.feed_link_prefix, task_uuid)),
                                  score=score)
Ejemplo n.º 10
0
    def query_wildfire(self, md5sum):
        """
        query the wildfire api to get a report on an md5
        """
        log.info("Querying wildfire for md5sum %s" % md5sum)

        status_code, content = self._call_wildfire_api("POST", "/publicapi/get/verdict",
                                                       {'hash': md5sum.lower()})

        if status_code == 404:
            return None                       # can't find the binary
        elif status_code != 200:
            log.info("Received unknown HTTP status code %d from WildFire" % status_code)
            log.info("-> response content: %s" % content)
            raise AnalysisTemporaryError("Received unknown HTTP status code %d from WildFire" % status_code,
                                         retry_in=120)

        response = etree.fromstring(content)

        # Return 0 Benign verdict
        # 1 Malware verdict
        # 2 Grayware verdict
        # -100 Verdict is pending
        # -101 Indicates a file error
        # -102 The file could not be found
        # -103 The hash submitted is invalid
        if md5sum.lower() == response.findtext("./get-verdict-info/md5").lower():
            verdict = response.findtext("./get-verdict-info/verdict").strip()
            if verdict == "-100":
                return None                # waiting for WildFire verdict
            elif verdict == "-102":
                return None                # file not in WildFire yet
            elif verdict.startswith("-"):
                raise AnalysisPermanentError("WildFire could not process file: error %s" % verdict)
            elif verdict == "1":
                return self.generate_malware_result(md5sum, 100)
            elif verdict == "2":
                return self.generate_malware_result(md5sum, 50)
            else:
                return AnalysisResult(score=0)
Ejemplo n.º 11
0
    def create_result(self, sample_id, submission_id=None):
        """Create Carbon Black result for the given sample"""

        try:
            sample = self.rest_api.call("GET", "/rest/sample/%u" % (sample_id))
            if submission_id is not None:
                LOGGER.debug(
                    "Creating result for sample with ID %u (submission_id=%s)",
                    sample_id, submission_id)
                submission = self.rest_api.call(
                    "GET", "/rest/submission/%u" % (submission_id))
                if "submission_finished" in submission:
                    # new way
                    if submission["submission_finished"]:
                        analyses = self.rest_api.call(
                            "GET",
                            "/rest/analysis/submission/%u" % (submission_id))
                    else:
                        raise AnalysisTemporaryError(
                            message=
                            "API error: Submission ID %u not finished yet" %
                            (submission_id),
                            retry_in=self.retry_wait_time)

                else:
                    # deprecated old way
                    # get analyses
                    analyses = self.rest_api.call(
                        "GET", "/rest/analysis/sample/%u" % (sample_id))
                    # filter by submission_id
                    analyses = [
                        analysis for analysis in analyses
                        if analysis["analysis_submission_id"] == submission_id
                    ]
            else:
                LOGGER.debug("Creating result for sample with ID %u",
                             sample_id)
                # get all analyses
                analyses = self.rest_api.call(
                    "GET", "/rest/analysis/sample/%u" % (sample_id))
        except BaseException as exc:
            LOGGER.debug(
                "Error getting sample and analyses info for sample ID %s",
                sample_id,
                exc_info=True)
            raise AnalysisTemporaryError(message="API error: %s" % (str(exc)))

        # check if any error occurred
        for analysis in analyses:
            if analysis["analysis_result_code"] != 1:
                LOGGER.warning(
                    "Analysis with ID %u of sample with ID %u failed with error code 0x%x: %s",
                    analysis["analysis_id"], sample_id,
                    analysis["analysis_result_code"],
                    analysis["analysis_result_str"])

        # check sample VTI score
        if (sample["sample_vti_score"] is None) or (
                sample["sample_vti_score"] < self.vti_score_threshold):
            message = "Benign"
        else:
            message = "Potential malware"

        # Check for None in the score
        if not sample["sample_vti_score"] and message == 'Benign':
            sample["sample_vti_score"] = 0

        if not sample["sample_vti_score"] and message == 'Potential malware':
            sample["sample_vti_score"] = 100

        #
        # Override if sample_severity is blacklisted or malicious
        #
        if sample['sample_severity'].lower() == "blacklisted":
            sample["sample_vti_score"] = 100
            message = "blacklisted"

        elif sample['sample_severity'].lower() == "malicious":
            sample["sample_vti_score"] = 100
            message = "malicious"

        LOGGER.debug(
            "Analysis result of sample with ID %u created successfully (message=%s link=%s score=%u)",
            sample_id, message, sample["sample_webif_url"],
            sample["sample_vti_score"])
        return AnalysisResult(
            message=message,
            extended_message="",
            link=sample["sample_webif_url"],
            score=sample["sample_vti_score"],
        )
Ejemplo n.º 12
0
    def query_checkpoint(self, md5sum):
        """
        query the checkpoint api to get a report on an md5
        """
        headers = {
            "Content-Type": "application/json",
            "Authorization": self.api_key,
        }

        payload = json.dumps({
            "request": [{
                "md5": md5sum,
                "features": ["te", "av", "extraction"]
            }]
        })

        log.info("Querying checkpoint for md5sum %s" % md5sum)

        try:
            status_code, content = self._call_checkpoint_api(
                method="POST",
                path="/tecloud/api/v1/file/query",
                headers=headers,
                payload=payload,
                files=None)

            if status_code != 200:
                log.info(
                    "Received unknown HTTP status code %d from checkpoint" %
                    status_code)
                log.info("-> response content: %s" % content)
                raise AnalysisTemporaryError(
                    "Received unknown HTTP status code %d from checkpoint" %
                    status_code,
                    retry_in=120)
        except Exception as e:
            log.info(str(e))
            raise AnalysisTemporaryError(
                "There was an error connecting to Checkpoint %s" % str(e),
                retry_in=120)

        dict_response = json.loads(content)
        try:
            checkpoint_status_code = dict_response.get("response", [])[0].get(
                "te", {}).get("status", {}).get("code", -1)
        except Exception as e:
            checkpoint_status_code = -1
            log.error("Failed to parse checkpoint response JSON")
            log.error(traceback.format_exc())

        log.info("md5: {0} returned status_code: {1}".format(
            md5sum, checkpoint_status_code))

        if checkpoint_status_code == 1001:

            severity = dict_response.get("response", [])[0].get("te", {}).get(
                "combined_verdict", None)

            if severity.lower() == "malicious":
                score = 100
            elif severity.lower() == "unknown":
                return None
            elif severity.lower() == "benign":
                score = 0
            else:
                return None

            log.info("{0} has score of {1}".format(md5sum, score))
            return AnalysisResult(score=score)

        elif checkpoint_status_code == 1003:
            #
            # Pending
            #
            return None
        elif checkpoint_status_code == 1004:
            #
            # 1004 NOT_Found
            # File is not in checkpoint yet
            #
            return None
        elif checkpoint_status_code == 1005:
            #
            # Out of Quota
            #
            return AnalysisTemporaryError("Out of Quota")
        elif checkpoint_status_code == 1006:
            #
            # Partially found
            #
            return None
        elif checkpoint_status_code == 1007:
            #
            # FILE_TYPE_NOT_SUPPORTED
            #
            return AnalysisPermanentError("Filetype is not supported")
        elif checkpoint_status_code == 1009:
            #
            # Internal Error
            #
            return AnalysisTemporaryError("Internal Error from Checkpoint")
        elif checkpoint_status_code == 1011:
            #
            # Insufficient resources
            #
            return AnalysisTemporaryError(
                "Checkpoint reports insufficient resources")
        else:
            return None