Beispiel #1
0
    def report(self, item_id, report_format="json"):
        """Retrieves the specified report for the analyzed item, referenced by item_id.

        Available formats include: json.

        :type  item_id:       str
        :param item_id:       File ID number
        :type  report_format: str
        :param report_format: Return format

        :rtype:  dict
        :return: Dictionary representing the JSON parsed data or raw, for other
                 formats / JSON parsing failure.
        """
        if report_format == "html":
            return "Report Unavailable"

        # grab an analysis id from the submission id.
        response = self._request(
            "/analysis/sample/{sample_id}".format(sample_id=item_id),
            headers=self.headers)

        try:
            # the highest score is probably the most interesting.
            # vmray uses this internally with sample_highest_vti_score so this seems like a safe assumption.
            analysis_id = 0
            top_score = -1
            for analysis in response.json()['data']:
                if analysis['analysis_vti_score'] > top_score:
                    top_score = analysis['analysis_vti_score']
                    analysis_id = analysis['analysis_id']

        except (ValueError, KeyError) as e:
            raise sandboxapi.SandboxError(e)

        # assume report format json.
        response = self._request(
            "/analysis/{analysis_id}/archive/logs/summary.json".format(
                analysis_id=analysis_id),
            headers=self.headers)

        # if response is JSON, return it as an object.
        try:
            return response.json()
        except ValueError:
            pass

        # otherwise, return the raw content.
        return response.content
Beispiel #2
0
    def analyze(self, handle, filename):
        """Submit a file for analysis.

        :type  handle:   File handle
        :param handle:   Handle to file to upload for analysis.
        :type  filename: str
        :param filename: File name.

        :rtype:  str
        :return: File ID as a string
        """
        # multipart post files.
        files = {"file": (filename, handle)}

        # ensure the handle is at offset 0.
        handle.seek(0)

        # add submission options
        data = {
            #FIXME: These may need to change, see docs page 36
            'options': '{"application":"0","timeout":"500","priority":"0","profiles":["%s"],"analysistype":"0","force":"true","prefetch":"1"}' % self.profile,
        }

        response = self._request("/submissions", method='POST', params=data, files=files)

        try:
            if response.status_code == 200:
                # good response
                try:
                    return response.json()['ID']
                except TypeError:
                    return response.json()[0]['ID']
            else:
                raise sandboxapi.SandboxError("api error in analyze ({u}): {r}".format(u=response.url, r=response.content))
        except (ValueError, KeyError) as e:
            raise sandboxapi.SandboxError("error in analyze: {e}".format(e=e))
Beispiel #3
0
    def check(self, item_id):
        """Check if an analysis is complete.

        :type  item_id: str
        :param item_id: Analysis ID to check.

        :rtype:  bool
        :return: Boolean indicating if a report is done or not.
        """

        data = self.request("/samples/{:s}/status".format(item_id))

        if "status" in data.keys():
            return data["status"] == "reported"
        else:
            raise sandboxapi.SandboxError("Triage didn't return a status")
Beispiel #4
0
    def _request(self, uri, method='GET', params=None, files=None, headers=None, auth=None):
        """Override the parent _request method.

        We have to do this here because FireEye requires some extra
        authentication steps. On each request we pass the auth headers, and
        if the session has expired, we automatically reauthenticate.
        """
        if headers:
            headers['Accept'] = 'application/json'
        else:
            headers = {
                'Accept': 'application/json',
            }

        if not self.api_token:
            # need to log in
            response = sandboxapi.SandboxAPI._request(self, '/auth/login', 'POST', headers=headers,
                                                      auth=HTTPBasicAuth(self.username, self.password))
            if response.status_code != 200:
                raise sandboxapi.SandboxError("Can't log in, HTTP Error {e}".format(e=response.status_code))
            # we are now logged in, save the token
            self.api_token = response.headers.get('X-FeApi-Token')

        headers['X-FeApi-Token'] = self.api_token

        response = sandboxapi.SandboxAPI._request(self, uri, method, params, files, headers)

        # handle session timeout
        unauthorized = False
        try:
            if json.loads(response.content.decode('utf-8'))['fireeyeapis']['httpStatus'] == 401:
                unauthorized = True
        except (ValueError, KeyError, TypeError):
            # non-JSON response, or no such keys.
            pass

        if response.status_code == 401 or unauthorized:
            self.api_token = None
            try:
                headers.pop('X-FeApi-Token')
            except KeyError:
                pass

            # recurse
            return self._request(uri, method, params, files, headers)

        return response
Beispiel #5
0
    def report(self, item_id, report_format='json'):
        """Retrieves the specified report for the analyzed item, referenced by item_id.

        :param str item_id: The hash of the file.
        :param str report_format: Return format.
        :rtype: dic
        :return: Dictionary representing the JSON parsed data.
        """
        data = {
            'apikey': self._api_key,
            'hash': item_id,
            'format': 'xml',
        }
        response = self._request('/get/report', method='POST', params=data)
        if not response.ok:
            raise sandboxapi.SandboxError("{}: {}".format(
                response.status_code, response.content))
        return self.decode(response)
Beispiel #6
0
    def analyze(self, handle, filename):
        """Submit a file for analysis.

        :type  handle:   File handle
        :param handle:   Handle to file to upload for analysis.
        :type  filename: str
        :param filename: File name.

        :rtype:  str
        :return: Task ID as a string
        """
        # ensure the handle is at offset 0.
        handle.seek(0)

        try:
            return self.jbx.submit_sample(handle)['webids'][0]
        except (jbxapi.JoeException, KeyError, IndexError) as e:
            raise sandboxapi.SandboxError("error in analyze: {e}".format(e=e))
Beispiel #7
0
    def report(self, item_id, report_format="json"):
        """Retrieves the specified report for the analyzed item,
        referenced by item_id. Note that the summary is returned and more
        detailed information is available.

        :param str item_id: The id of the submitted file.
        :param str report_format:   In here for compatibility though Triage
                                    only supports the JSON format

        :rtype: dic
        :return: Dictionary representing the JSON parsed data.
        """

        if report_format != "json":
            raise sandboxapi.SandboxError(
                "Triage api only supports the json report format")

        data = self.request("/samples/{:s}/summary".format(item_id))

        return data
    def full_report(self, item_id, report_format="json"):
        """Retrieves a more detailed report"""
        report_format = report_format.lower()

        response = self._request(
            "/report/{job_id}/file/{report_format}".format(
                job_id=item_id, report_format=report_format))

        if response.status_code == 429:
            raise sandboxapi.SandboxError(
                'API rate limit exceeded while fetching report')

        # if response is JSON, return it as an object
        if report_format == "json":
            try:
                return json.loads(response.content.decode('utf-8'))
            except ValueError:
                pass

        # otherwise, return the raw content.
        return response.content.decode('utf-8')
Beispiel #9
0
    def report(self, item_id, report_format="json"):
        """Retrieves the specified report for the analyzed item, referenced by item_id.

        For available report formats, see online Joe Sandbox documentation.

        :type  item_id:       str
        :param item_id:       File ID number
        :type  report_format: str
        :param report_format: Return format

        :rtype:  dict
        :return: Dictionary representing the JSON parsed data or raw, for other
                 formats / JSON parsing failure.
        """
        if report_format == "json":
            report_format = "jsonfixed"

        try:
            return json.loads(
                self.jbx.download(item_id, report_format)[1].decode('utf-8'))
        except (jbxapi.JoeException, ValueError, IndexError) as e:
            raise sandboxapi.SandboxError(
                "error in report fetch: {e}".format(e=e))
Beispiel #10
0
    def check(self, item_id):
        """Check if an analysis is complete.

        :type  item_id: str
        :param item_id: File ID to check.

        :rtype:  bool
        :return: Boolean indicating if a report is done or not.
        """
        response = self._request("/submissions/status/{file_id}".format(file_id=item_id))

        if response.status_code == 404:
            # unknown id
            return False

        try:
            status = response.json()['submissionStatus']
            if status == 'Done':
                return True

        except ValueError as e:
            raise sandboxapi.SandboxError(e)

        return False
Beispiel #11
0
    def check(self, item_id):
        """Check if an analysis is complete.

        :param str item_id: The hash of the file to check.
        :rtype: bool
        :return: True if the report is ready, otherwise False.
        """
        data = {
            'apikey': self._api_key,
            'hash': item_id,
        }
        response = self._request('/get/verdict', method='POST', params=data)

        if not response.ok:
            raise sandboxapi.SandboxError("{}: {}".format(
                response.status_code, response.content))

        output = self.decode(response)
        try:
            status = int(output['wildfire']['get-verdict-info']['verdict'])
            if status >= 0:
                self._score = status
                return True
            elif status == -100:
                return False
            elif status == -101:
                raise sandboxapi.SandboxError(
                    'An error occurred while processing the sample.')
            elif status == -102:
                raise sandboxapi.SandboxError(
                    'Unknown sample in the Wildfire database.')
            elif status == -103:
                raise sandboxapi.SandboxError('Invalid hash value.')
            else:
                raise sandboxapi.SandboxError('Unknown status.')
        except (ValueError, IndexError) as e:
            raise sandboxapi.SandboxError(e)