def analyze_binary(self, md5sum, binary_file_stream):
        if not self.submit_full_binaries:
            raise AnalysisPermanentError(
                message="NOT SUBMITTING FULL BINARIES")

        response = self.tiscale_client.upload_file(
            md5sum=md5sum, binary_file_stream=binary_file_stream)

        if response.status_code == 200:
            log.info(
                "File {} uploaded successfully. Response status_code = {}".
                format(md5sum, response.status_code))
            return self.make_result(md5sum=md5sum, uploaded=True)

        elif response.status_code == 403:
            log.info("Quota reached. Response status_code: {}".format(
                response.status_code))
            raise AnalysisTemporaryError(
                message="Quota reached, will retry in 1 hour",
                retry_in=60 * 60)

        else:
            log.info("Unable to upload file. Response status_code: {}".format(
                response.status_code))
            raise AnalysisTemporaryError(
                message="Uploading file failed, will try again in 30 min",
                retry_in=30 * 60)
示例#2
0
    def analyze_binary(self, md5sum, binary_file_stream):

        if not self.submit_full_binaries:
            raise AnalysisPermanentError(
                message="NOT SUBMITTING FULL BINARIES!")
        log.info("Submitting FULL binary %s to VT for analysis" % md5sum)
        try:
            response = self.virustotal_analysis.submit_file(
                resource_hash=md5sum, stream=binary_file_stream)
        except VTAPIQUOTAREACHED as vte:
            raise AnalysisTemporaryError(message="VTAPIQUOTAREACHED",
                                         retry_in=15 * 60)

        response_code = response.get("response_code", -1)
        verbose_msg = response.get("verbose_msg", "")
        # response_code == -2 or "scan request successfully queued" is the wait condition
        if response_code == -2 or "Scan request successfully queued" in verbose_msg:
            raise AnalysisTemporaryError(
                message="VirusTotal report not yet ready -> %s" % verbose_msg,
                retry_in=120)
        elif response_code == 1:
            scan_id = response.get("scan_id", None)
            return self.make_result(scan_id=scan_id, result=response)
        else:
            raise AnalysisTemporaryError(message="Unknown error? % s" %
                                         response,
                                         retry_in=120)
示例#3
0
    def check_result_for(self, md5sum):

        log.info("Submitting hash %s to RL for analysis" % md5sum)

        try:
            response = self.rl_analysis.get_report(resource_hash=md5sum)
        except RLAPIQUOTAREACHED as rle:
            log.info(traceback.format_exc())
            raise AnalysisTemporaryError(message="Error: {}".format(str(rle)),
                                         retry_in=15 * 60)
        except Exception as err:
            log.info(traceback.format_exc())
            raise AnalysisTemporaryError(message="Error: {}".format(str(err)),
                                         retry_in=15 * 60)

        malware_presence = response["rl"]["malware_presence"]
        status = malware_presence.get("status").upper()

        if 'UNKNOWN' in status:
            return AnalysisInProgress(retry_in=15 * 60)

        # calculate if hash needs rescan
        datetime_now = datetime.utcnow()
        log.info("current time: %s" % datetime_now)
        if self.days_rescan:
            rescan_date = datetime_now - timedelta(days=int(self.days_rescan))
        else:
            rescan_date = None
        log.info("rescan date: %s" % rescan_date)
        last_seen_date_str = malware_presence.get('last_seen')
        log.info("last seen str: %s" % last_seen_date_str)
        last_seen_date = datetime.strptime(
            last_seen_date_str,
            "%Y-%m-%dT%H:%M:%S") if last_seen_date_str else None
        log.info("last seen date: %s" % last_seen_date)
        log.info(
            "Binary %s has not been scanned since: %s - timenow: %s. Should do rescan if last seen is older than %s"
            % (md5sum, last_seen_date, datetime_now, rescan_date))

        if self.days_rescan and last_seen_date <= rescan_date:
            log.info("HIT rescan date: Binary %s" % md5sum)
            try:
                self.rl_analysis.rescan_hash(md5sum)
            except RLAPIQUOTAREACHED as rle:
                log.info(traceback.format_exc())
                raise AnalysisTemporaryError(message="Error: {}".format(
                    str(rle)),
                                             retry_in=15 * 60)
            except Exception as err:
                log.info(traceback.format_exc())
                raise AnalysisTemporaryError(
                    message="There was an error. Error: {}".format(str(err)),
                    retry_in=15 * 60)

            return AnalysisInProgress(
                message="Rescaning hash {}".format(md5sum), retry_in=60 * 60)
        else:
            return self.make_result(md5=md5sum, result=response)
示例#4
0
    def get_uuid(self, response):
        try:
            task_uuid = response.get('data', {}).get('task_uuid', None)
        except AttributeError:
            raise AnalysisTemporaryError(message="Invalid response from LastLine: %s" % response, retry_in=120)
        else:
            if not task_uuid:
                raise AnalysisTemporaryError(message="No UUID for result: %s" % response, retry_in=120)

        return task_uuid
示例#5
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)
    def submit_checkpoint(self, md5sum, file_stream):
        """
        submit a file to the checkpoint api
        returns a checkpoint submission status code
        """

        headers = {
            "Authorization": self.api_key,
        }

        payload = {
            "request": {
                "md5": md5sum,
                "file_name": "CarbonBlack_{0}".format(md5sum)
            }
        }

        json_input = StringIO(json.dumps(payload))

        files = {
            'file': ("CarbonBlack_{0}".format(md5sum), file_stream),
            'request': ('request', json_input)
        }

        log.info(
            "Submitting {0} to Checkpoint Threat Emulation".format(md5sum))

        try:
            status_code, content = self._call_checkpoint_api(
                "POST",
                "/tecloud/api/v1/file/upload",
                headers=headers,
                payload=None,
                files=files)
        except Exception as e:
            log.exception(
                "Exception while submitting MD5 %s to checkpoint: %s" %
                (md5sum, e))
            raise AnalysisTemporaryError(
                "Exception while submitting to checkpoint: %s" % e)
        else:
            if status_code == 200:
                return True
            else:
                time.sleep(5)
                raise AnalysisTemporaryError(
                    "Received HTTP error code %d while submitting to checkpoint"
                    % status_code)
示例#7
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"],
        )
示例#8
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)
示例#9
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)
示例#10
0
    def analyze_binary(self, md5sum, binary_file_stream):
        log.info("Submitting {0} to FortiSandbox for analysis".format(
            str(md5sum)))
        try:
            response = self.fortisandbox_analysis.submit_file(
                resource_hash=md5sum, stream=binary_file_stream)
        except BaseException as be:
            log.error("EXCEPTION WHEN trying to submit binary: " + str(md5sum))
            log.error(str(be))
            log.error(traceback.format_exc())
            raise AnalysisTemporaryError(message=str(be), retry_in=15 * 60)

        result = response.json().get("result", {})
        response_code = result.get("status", {}).get("message", None)
        if response_code == "OK":
            log.info("Sucessfully submitted {0} to FortiSandbox for scanning".
                     format(md5sum))
        else:
            if response_code == "INVALID_SESSION":
                self.fortisandbox_analysis.invalidate_session()
            raise AnalysisPermanentError(
                message="FortiSandbox analysis failed -> %s" % response.json())
        try:
            response = self.fortisandbox_analysis.get_report(
                resource_hash=md5sum)
            log.debug("Fortinet report: " + str(response.json()))
            result = response.json().get("result", {})
            response_code = result.get("status", {}).get("message", None)
            if response_code == "OK":
                log.info("Got analysis report from Fortisandbox for %s" %
                         md5sum)
                return self.make_result(md5=md5sum, result=response.json())
            else:
                log.info(
                    "No analysis report from Fortisandbox for %s, try again in 180 seconds"
                    % md5sum)
                raise AnalysisTemporaryError(
                    message="FortiSandbox analysis failed -> %s" %
                    response_code,
                    retry_in=180)
        except AnalysisTemporaryError as ate:
            raise ate
        except:
            log.error("Fortisandbox Analysis failed , permanent!")
            log.error(traceback.format_exc())
            raise AnalysisPermanentError(
                message="FortiSandbox Anlaysis failed -> %s" % response_code)
示例#11
0
    def submit_wildfire(self, md5sum, file_stream):
        """
        submit a file to the wildfire api
        returns a wildfire submission status code
        """

        files = {'file': ('CarbonBlack_%s' % md5sum, file_stream)}
        try:
            status_code, content = self._call_wildfire_api("POST", "/publicapi/submit/file", files=files)
        except Exception as e:
            log.exception("Exception while submitting MD5 %s to WildFire: %s" % (md5sum, e))
            raise AnalysisTemporaryError("Exception while submitting to WildFire: %s" % e)
        else:
            if status_code == 200:
                return True
            else:
                raise AnalysisTemporaryError("Received HTTP error code %d while submitting to WildFire" % status_code)
    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)
示例#13
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)
示例#14
0
    def analyze_binary(self, md5sum, binary_file_stream):
        log.info("Submitting binary %s to LastLine" % md5sum)

        try:
            response = self.lastline_analysis.submit_file(binary_file_stream)
        except AnalysisAPIError as e:
            raise AnalysisTemporaryError(message="API error: %s" % str(e), retry_in=120)

        task_uuid = self.get_uuid(response)

        retries = 10
        while retries:
            sleep(10)
            result = self.lastline_analysis.get_progress(task_uuid)
            if result.get('data', {}).get('completed', 0) == 1:
                return self.make_result(task_uuid)
            retries -= 1

        raise AnalysisTemporaryError(message="Maximum retries (10) exceeded submitting to LastLine", retry_in=120)
示例#15
0
 def check_result_for(self, md5sum):
     try:
         response = self.lastline_analysis.submit_file_hash(md5=md5sum)
     except FileNotAvailableError as e:
         # the file does not exist yet.
         return None
     except AnalysisAPIError as e:
         raise AnalysisTemporaryError(message="API error: %s" % str(e), retry_in=120)
     else:
         task_uuid = self.get_uuid(response)
         return self.make_result(task_uuid)
    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)
示例#17
0
    def analyze_binary(self, md5sum, binary_file_stream):
        self.submit_wildfire(md5sum, binary_file_stream)

        retries = 15
        while retries:
            time.sleep(60)
            result = self.check_result_for(md5sum)
            if result:
                return result
            retries -= 1

        raise AnalysisTemporaryError(message="Maximum retries (20) exceeded submitting to WildFire", retry_in=120)
示例#18
0
    def check_result_for(self, md5_hash):
        LOGGER.debug("Checking result for md5 %s", md5_hash)
        try:
            result = self.rest_api.call("GET", "/rest/sample/md5/%s" % (md5_hash.lower()))
        except BaseException as exc:
            LOGGER.debug("Error while checking for md5 %s", md5_hash, exc_info=True)
            raise AnalysisTemporaryError(message="API error: %s" % (str(exc)), retry_in=self.retry_wait_time)

        LOGGER.debug("%u sample(s) found with md5 %s", len(result), md5_hash)
        if len(result) == 0:
            return None
        else:
            return self.create_result(result[0]["sample_id"])
    def analyze_binary(self, md5sum, binary_file_stream):

        if not self.submit_full_binaries:
            raise AnalysisPermanentError(
                message="NOT SUBMITTING FULL BINARIES")

        log.info("Submitting FULL binary %s to ReversingLabs for analysis" %
                 md5sum)

        try:
            response = self.rl_analysis.submit_file(resource_hash=md5sum,
                                                    stream=binary_file_stream)
        except RLAPIQUOTAREACHED:
            raise AnalysisTemporaryError(message="RLAPIQUOTAREACHED",
                                         retry_in=15 * 60)

        if response.status_code == 200 or response.status_code == 201:
            return self.check_result_for(md5sum=md5sum)
        else:
            raise AnalysisTemporaryError(message="Unknown error: %s" %
                                         str(response),
                                         retry_in=15 * 60)
    def analyze_binary(self, md5sum, binary_file_stream):
        self.submit_checkpoint(md5sum, binary_file_stream)

        retries = 30
        while retries:
            time.sleep(10)
            result = self.query_checkpoint(md5sum)
            if result:
                return result
            retries -= 1

        raise AnalysisTemporaryError(
            message="Maximum retries (20) exceeded submitting to checkpoint",
            retry_in=120)
示例#21
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)
    def check_result_for(self, md5sum):

        log.info("Submitting hash %s to RL for analysis" % md5sum)
        try:
            response = self.rl_analysis.get_report(resource_hash=md5sum)
        except RLAPIQUOTAREACHED as rle:
            log.info(rle)
            raise AnalysisTemporaryError(
                message="Quota reached. Will retry in 30 min",
                retry_in=30 * 60)
        except Exception as err:
            log.info(err)
            raise AnalysisTemporaryError(
                message="There was an error. Error: {}".format(str(err)),
                retry_in=60 * 60)

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

        return self.make_result(md5sum=md5sum, result=response)
示例#23
0
    def analyze_binary(self, md5sum, binary_file_stream):
        if not self.submit_full_binaries:
            raise AnalysisPermanentError(
                "Submitting full binaries is not enabled")

        log.info("Submitting binary {}".format(md5sum))

        successfull_upload = self.rl_analysis.submit_file(
            md5sum=md5sum, stream=binary_file_stream)

        if successfull_upload:
            return self.make_result(md5=md5sum)
        else:
            raise AnalysisTemporaryError(
                "Unable to upload file. md5sum: {}".format(md5sum),
                retry_in=30 * 60)
示例#24
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)
示例#25
0
    def analyze_binary(self, md5_hash, binary_file_stream):
        LOGGER.info("Submitting binary with md5 %s to VMRay" % (md5_hash))

        # submit file to VMRay
        try:
            result = self.rest_api.call("POST",
                                        "/rest/sample/submit",
                                        params={
                                            "archive_action":
                                            "ignore",
                                            "sample_file":
                                            binary_file_stream,
                                            "sample_filename_b64enc":
                                            base64.encodestring(md5_hash)
                                        })
        except VMRayRESTAPIError as exc:
            LOGGER.debug("Error submitting sample with md5 %s",
                         md5_hash,
                         exc_info=True)
            raise AnalysisTemporaryError(message="API error: %s" % str(exc),
                                         retry_in=self.retry_wait_time)

        sample_id = result["samples"][0]["sample_id"]
        submission_id = result["submissions"][0]["submission_id"]

        LOGGER.debug("Waiting for submission with ID %u to finish all jobs",
                     submission_id)

        # wait until all analyses have finished
        open_jobs = list(result["jobs"])
        wait_start = time.time()
        while len(open_jobs) > 0:
            # check for timeout
            if (time.time() - wait_start) > self.max_analysis_wait_time:
                LOGGER.debug(
                    "Timed out waiting for result of submission with ID %u",
                    submission_id)
                raise AnalysisTemporaryError(
                    message=
                    "Timed out waiting for analysis jobs to finish for submission %u"
                    % (submission_id),
                    retry_in=self.retry_wait_time)

            check_jobs = list(open_jobs)
            open_jobs = []
            for job in check_jobs:
                try:
                    self.rest_api.call("GET", "/rest/job/%u" % (job["job_id"]))
                except VMRayRESTAPIError as exc:
                    if exc.status_code == 404:
                        # job has finished
                        continue

                # job is still there or server is unreachable
                open_jobs.append(job)

            if len(open_jobs) == 0:
                break

            time.sleep(self.loop_wait_time)

        LOGGER.debug("All jobs for submission with ID %u have finished",
                     submission_id)
        return self.create_result(sample_id, submission_id=submission_id)
示例#26
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"],
        )
    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