def _add_vault_hashes_to_dictionary(self, cef_artifact, vault_id):

        success, message, vault_info = phantom_rules.vault_info(
            vault_id=vault_id)

        if not vault_info:
            return phantom.APP_ERROR, "Vault ID not found"

        # The return value is a list, each item represents an item in the vault
        # matching the vault id, the info that we are looking for (the hashes)
        # will be the same for every entry, so just access the first one
        try:
            metadata = vault_info[0].get('metadata')
        except Exception:
            return phantom.APP_ERROR, PROC_EMAIL_FAILED_VAULT_CONT_DATA

        try:
            cef_artifact['fileHashSha256'] = metadata['sha256']
        except Exception:
            pass

        try:
            cef_artifact['fileHashMd5'] = metadata['md5']
        except Exception:
            pass

        try:
            cef_artifact['fileHashSha1'] = metadata['sha1']
        except Exception:
            pass

        return phantom.APP_SUCCESS, PROC_EMAIL_MAPPED_HASH_VAL
def playbook_local_soc_fork_customer_request_1(action=None,
                                               success=None,
                                               container=None,
                                               results=None,
                                               handle=None,
                                               filtered_artifacts=None,
                                               filtered_results=None):
    phantom.debug('playbook_local_soc_fork_customer_request_1() called')

    # ----- start of added code -----
    import csv
    # get container id
    container_id = container.get('id', None)

    # use the container id to get information about any files in the vault
    vault_info = phantom.vault_info(container_id=container_id)

    # filter info returned to find the path where the file is stored in the vault
    file_path = vault_info[2][0]["path"]
    phantom.debug('vault file path: {}'.format(file_path))

    # read the .csv file, file and add artifacts with the label "customer_request" to container
    raw_data = {}
    reader = None
    try:
        with open(file_path, 'r') as f:
            reader = csv.DictReader(f)
            for cef_data in reader:
                cef_data_keys = cef_data.keys()
                if 'action' in cef_data_keys and (
                        'sourceAddress' in cef_data_keys
                        or 'destinationAddress' in cef_data_keys):
                    phantom.debug('adding artifact: {}'.format(cef_data))
                    success, message, artifact_id = phantom.add_artifact(
                        container=container,
                        raw_data=raw_data,
                        cef_data=cef_data,
                        label='customer_request',
                        name='Parsed CSV Artifact',
                        severity='high',
                        identifier=None,
                        artifact_type='network')
                    if not success:
                        phantom.error(
                            "Adding Artifact failed: {}".format(message))
    except Exception as e:
        phantom.error("Exception Occurred: {}".format(e.args[1]))
        return
    # ----- end of added code -----

    # call playbook "local/soc_fork_customer_request", returns the playbook_run_id
    playbook_run_id = phantom.playbook("local/soc_fork_customer_request",
                                       container)

    return
    def _add_attachment(self, param):

        # Create action result
        action_result = self.add_action_result(ActionResult(param))

        # Create RT object
        if phantom.is_fail(self._create_rt_session(action_result)):
            return action_result.get_status()

        # Get params
        ticket_id = param[RT_JSON_ID]
        vault_id = param[RT_JSON_VAULT]
        comment = param.get('comment')

        # Set default comment
        if not comment:
            comment = 'File uploaded from Phantom'

        # Check for vault file
        _, _, file_info = vault_info(vault_id=vault_id,
                                     container_id=self.get_container_id())

        if not file_info:
            return action_result.set_status(
                phantom.APP_ERROR, "Vault ID is invalid. Vault file not found")

        file_info = file_info[0]

        if not file_info['name']:
            file_info['name'] = vault_id

        # Create payload for request
        content = {
            'content':
            'Action: comment\nText: {0}\nAttachment: {1}'.format(
                comment, file_info['name'])
        }
        upfile = {'attachment_1': open(file_info['path'], 'rb')}

        ret_val, resp_text = self._make_rest_call(
            "ticket/{0}/comment".format(ticket_id),
            action_result,
            data=content,
            files=upfile,
            method='post')

        if phantom.is_fail(ret_val):
            return ret_val

        return action_result.set_status(phantom.APP_SUCCESS)
    def _query_file(self, param):
        vault_id = param['vault_id']

        if param.get('force_analysis') is False:
            task_id = self._check_existing(vault_id)
            if task_id:
                return self._get_detonation_results(task_id)

        filename = param.get('file_name')
        if not filename:
            filename = vault_id

        try:
            _, _, file_info = phantom_rules.vault_info(vault_id=vault_id)
            if not file_info:
                self.threatgrid_action_result.set_status(
                    phantom.APP_ERROR, THREATGRID_FILE_NOT_FOUND_ERROR.format(vault_id))
                return
            file_path = list(file_info)[0].get('path')
            payload = open(file_path, 'rb')
        except:
            self.threatgrid_action_result.set_status(
                phantom.APP_ERROR, THREATGRID_FILE_NOT_FOUND_ERROR.format(vault_id))
            return

        files = {
            'sample': (filename, payload),
        }
        data = {
            'api_key': self.threatgrid_api_key,
            'filename': filename,
            'tags': [],
            'os': '',
            'osver': '',
            'source': '',
            'vm': param.get('vm', ''),
            'playbook': param.get('playbook', 'default')
        }
        if param.get('private'):
            data['private'] = True

        self._queue_analysis(data, files, filename)
    def _handle_create_observable(self, param):
        self.save_progress("In action handler for: {0}".format(self.get_action_identifier()))
        action_result = self.add_action_result(ActionResult(dict(param)))
        data = dict()
        case_id = param['id']
        data_type = param['data_type']
        message = param['description']
        tlp = param.get('tlp', 'Amber')
        try:
            int_tlp = THEHIVE_TLP_DICT[tlp]
        except KeyError:
            return action_result.set_status(phantom.APP_ERROR, THEHIVE_ERR_INVALID_TLP)
        tags = param.get('tags', '')
        try:
            tags = [x.strip() for x in tags.split(',')]
            tags = list(filter(None, tags))
            if not tags:
                return action_result.set_status(phantom.APP_ERROR, "Tags format invalid. Please supply one or more tags separated by a comma")
        except:
            return action_result.set_status(phantom.APP_ERROR, "Tags format invalid. Please supply one or more tags separated by a comma")

        ioc = param.get('ioc', False)
        data = param.get('data', '')

        # if a file is to be supplied, the vault_id parameter will be used to grab a file from the Vault
        if data_type == 'file':
            vault_id = param.get('vault_id')

            if not vault_id:
                return action_result.set_status(phantom.APP_ERROR, "Parameter Vault ID is mandatory if 'data_type' is file")

            try:
                _, _, vault_file_info = ph_rules.vault_info(container_id=self.get_container_id(), vault_id=vault_id)
                vault_file_info = list(vault_file_info)
            except Exception as e:
                error_msg = self._get_error_message_from_exception(e)
                self.debug_print(error_msg)
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Unable to find specified Vault file. Please check Vault ID and try again. {}".format(error_msg)
                )

            if len(vault_file_info) != 1:
                return action_result.set_status(phantom.APP_ERROR, "Unable to find specified Vault file. Please check Vault ID and try again.")

            vault_file_info = vault_file_info[0]
            file_path = vault_file_info.get('path')
            file_name = vault_file_info.get('name')

            # file name is being ignored by Hive. It uses the file_path.
            file_data = {'attachment': (file_name, open(file_path, 'rb'), magic.Magic(mime=True).from_file(file_path))}

        endpoint = "api/case/{0}/artifact".format(case_id)
        authToken = "Bearer {}".format(self._api_key)
        headers = {'Authorization': authToken}
        mesg = {
            "dataType": data_type,
            "message": message,
            "tlp": int_tlp,
            "tags": tags,
            "ioc": ioc
        }

        if data_type == 'file':
            data = {"_json": json.dumps(mesg)}

            ret_val, response = self._make_rest_call(endpoint, action_result, params=None, headers=headers, data=data, method="post", files=file_data)
        else:
            mesg['data'] = data
            headers['Content-Type'] = 'application/json'
            ret_val, response = self._make_rest_call(endpoint, action_result, params=None, headers=headers, data=mesg, method="post")

        if phantom.is_fail(ret_val):
            return action_result.get_status()

        # need to flatten hashes if file was uploaded
        if response.get('attachment'):
            hashes = response.get('attachment').get('hashes', [])
            response['attachment']['sha256'] = hashes[0]
            response['attachment']['sha1'] = hashes[1]
            response['attachment']['md5'] = hashes[2]

            del response['attachment']['hashes']

        action_result.add_data(response)

        return action_result.set_status(phantom.APP_SUCCESS, "Successfully created observable")
示例#6
0
    def _upload_vault_file(self, action_result, vault_id):
        """Uploads a file from vault to Redmine and returns a dictionary suitable for attaching the uploaded file to an existing ticket"""

        try:
            self.debug_print("Rules.vault_info start")
            success, message, vault_info = Rules.vault_info(vault_id=vault_id)
            vault_info = list(vault_info)
            self.debug_print(
                "Rules.vault_info results: success: {}, message: {}, info: {}".format(
                    success, message, vault_info
                )
            )
            if not vault_info:
                return action_result.set_status(phantom.APP_ERROR, REDMINE_ERR_GETTING_VAULT_INFO)
        except requests.exceptions.HTTPError:
            return action_result.set_status(phantom.APP_ERROR, REDMINE_ERR_INVALID_VAULT_ID.format(vault_id=vault_id))
        except Exception as e:
            error_msg = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR, REDMINE_ERR_OPENING_FILE.format(error=error_msg)
            )

        try:
            file_info = vault_info[0]
        except Exception as e:
            error_msg = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                REDMINE_ERR_GETTING_FILE_INFO.format(error=error_msg),
            )

        try:
            file_path = file_info["path"]
        except Exception:
            return action_result.set_status(phantom.APP_ERROR, REDMINE_ERR_GETTING_FILE_PATH)

        with open(file_path, "rb") as f:
            file_contents = f.read()

        ret_val, response = self._make_rest_call(
            "/uploads.json",
            action_result,
            params=None,
            method="post",
            headers={"Content-Type": "application/octet-stream"},
            data=file_contents,
        )

        if phantom.is_fail(ret_val):
            return action_result.set_status(
                phantom.APP_ERROR, REDMINE_ERR_UPLOAD_ATTACHMENT
            )

        try:
            upload = {
                "token": response["upload"]["token"],
                "filename": file_info["name"],
                "content_type": file_info["mime_type"],
            }
        except Exception as e:
            self.debug_print(self._get_error_message_from_exception(e))
            return action_result.set_status(
                phantom.APP_ERROR, REDMINE_ERR_PROCESSING_UPLOAD_DICT
            )

        return upload
示例#7
0
def mark_evidence(container=None,
                  input_object=None,
                  content_type=None,
                  **kwargs):
    """
    Mark an object as Evidence in a container
    
    Args:
        container (CEF type: phantom container id): Container ID or Container Object
        input_object (CEF type: *): The object to mark as evidence. This could be a vault_id, artifact_id, note_id, container_id, or action_run_id. If the previous playbook block is an action then "keyword_argument:results" can be used for the action_run_id with the content_type "action_run_id". Vault_id can be an ID or a vault hash.
        content_type (CEF type: *): The content type of the object to add as evidence which must be one of the following:
                        
                        vault_id
                        artifact_id
                        container_id
                        note_id
                        action_run_id
    
    Returns a JSON-serializable object that implements the configured data paths:
        *.id (CEF type: *): ID of the evidence item
    """
    ############################ Custom Code Goes Below This Line #################################
    import json
    import phantom.rules as phantom

    outputs = []
    container_id = None
    data = []
    valid_types = [
        'vault_id', 'artifact_id', 'container_id', 'note_id', 'action_run_id'
    ]

    # Ensure valid content_type:
    if content_type.lower() not in valid_types:
        raise TypeError(
            f"The content_type '{content_type}' is not a valid content_type")

    # Ensure valid container input
    if isinstance(container, dict) and container.get('id'):
        container_id = container['id']
    elif isinstance(container, int) or (isinstance(container, str)
                                        and container.isdigit()):
        container_id = container
    else:
        raise TypeError(
            "The input 'container' is neither a container dictionary nor an int, so it cannot be used"
        )

    # If content added is type 'action_run_id',
    # then iterate through an input object that is a results object,
    # and append the action_run_id's to data
    if isinstance(input_object,
                  list) and content_type.lower() == 'action_run_id':
        for action_result in input_object:
            if action_result.get('action_run_id'):
                data.append({
                    "container_id": container_id,
                    "object_id": action_result['action_run_id'],
                    "content_type": 'actionrun',
                })
        # If data is still an empty list after for loop,
        # it indicates that the input_object was not a valid results object
        if not data:
            raise TypeError(
                "The input for 'input_object' is not a valid integer or supported object."
            )

    # If 'input_object' is already an action_run_id, no need to translate it.
    elif (isinstance(input_object, int) or
          (isinstance(input_object, str) and input_object.isdigit())
          ) and content_type.lower() == 'action_run_id':
        data = [{
            "container_id": container_id,
            "object_id": input_object,
            "content_type": 'actionrun',
        }]

    # If vault_id was entered, check to see if user already entered a vault integer
    # else if user entered a hash vault_id, attempt to translate to a vault integer
    elif input_object and content_type.lower() == 'vault_id':
        if isinstance(input_object, int) or (isinstance(input_object, str)
                                             and input_object.isdigit()):
            content_type = "containerattachment"
        else:
            success, message, info = phantom.vault_info(vault_id=input_object)
            if success == False:
                raise RuntimeError(f"Invalid vault_id: {message}")
            else:
                input_object = info[0]['id']
                content_type = "containerattachment"
        data = [{
            "container_id": container_id,
            "object_id": input_object,
            "content_type": content_type,
        }]

    # If 'container_id' was entered, the content_type needs to be set to 'container'.
    # Phantom does not allow a literal input of 'container' so thus 'container_id is used.
    elif (isinstance(input_object, int) or
          (isinstance(input_object, str) and
           input_object.isdigit())) and content_type.lower() == 'container_id':
        data = [{
            "container_id": container_id,
            "object_id": input_object,
            "content_type": 'container',
        }]

    # If 'artifact_id' was entered, the content_type needs to be set to 'artifact'
    elif (isinstance(input_object, int) or
          (isinstance(input_object, str) and
           input_object.isdigit())) and content_type.lower() == 'artifact_id':
        data = [{
            "container_id": container_id,
            "object_id": input_object,
            "content_type": 'artifact',
        }]
    # If 'note_id' was entered, the content_type needs to be set to 'note'
    elif (isinstance(input_object, int) or
          (isinstance(input_object, str)
           and input_object.isdigit())) and content_type.lower() == 'note_id':
        data = [{
            "container_id": container_id,
            "object_id": input_object,
            "content_type": 'note',
        }]
    else:
        raise TypeError(
            f"The input_object is not a valid integer or supported object. Type '{type(input_object)}'"
        )

    # Build url for evidence endpoint
    url = phantom.build_phantom_rest_url('evidence')

    # Post data to evidence endpoint
    for item in data:
        response = phantom.requests.post(uri=url, json=item,
                                         verify=False).json()

        # If successful add evidence id to outputs
        # elif evidence already exists print to debug
        # else error out
        if response.get('success'):
            outputs.append({'id': response['id']})
        elif response.get('failed') and response.get(
                'message') == 'Already added to Evidence.':
            phantom.debug(
                f"{content_type} \'{container_id}\' {response['message']}")
        else:
            raise RuntimeError(f"Unable to add evidence: {response}")

    # Return a JSON-serializable object
    assert json.dumps(
        outputs
    )  # Will raise an exception if the :outputs: object is not JSON-serializable
    return outputs
    def _provide_attachment_details(self, attachment_list, action_result):
        """ Helper function that is used to get attachment from the vault, and provide attachment details which can be
        used to add attachment to an incident.

        :param attachment_list: list of vault IDs
        :param action_result: object of ActionResult class
        :return: status (success/failure) and (add_attachment_params_dict dictionary having attachment related
                            information and attachment_data dictionary containing attachment) / None
        """

        file_obj = []
        filename = []
        attachment_data = dict()
        add_attachment_params_dict = dict()

        attachment_list = [
            value.strip() for value in attachment_list.split(',')
            if value.strip()
        ]
        if not attachment_list:
            self.debug_print(
                consts.BMCREMEDY_ERR_INVALID_FIELDS.format(field='vault_id'))
            return action_result.set_status(
                phantom.APP_ERROR,
                consts.BMCREMEDY_ERR_INVALID_FIELDS.format(
                    field='vault_id')), None, None

        # At most, three attachments should be provided
        if len(attachment_list) > 3:
            self.debug_print(consts.BMCREMEDY_ATTACHMENT_LIMIT_EXCEED)
            return action_result.set_status(
                phantom.APP_ERROR,
                consts.BMCREMEDY_ATTACHMENT_LIMIT_EXCEED), None, None

        try:
            # Searching for file with vault id in current container
            _, _, files_array = (ph_rules.vault_info(
                container_id=self.get_container_id()))
            files_array = list(files_array)
            for vault_id in attachment_list:
                file_found = False
                for file_data in files_array:
                    if file_data[consts.BMCREMEDY_JSON_VAULT_ID] == vault_id:
                        # Getting filename to use
                        filename.append(file_data['name'])
                        # Reading binary data of file
                        with open(file_data.get('path'), 'rb') as f:
                            file_obj.append(f.read())
                        file_found = True
                        break
                if not file_found:
                    self.debug_print("{}: {}".format(
                        consts.BMCREMEDY_UNKNOWN_VAULT_ID, vault_id))
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "{}: {}".format(consts.BMCREMEDY_UNKNOWN_VAULT_ID,
                                        vault_id)), None, None
        except Exception as e:
            err_msg = self._get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR,
                                            err_msg), None, None

        for index, value in enumerate(file_obj):
            add_attachment_params_dict['z2AF Work Log0{}'.format(
                index + 1)] = filename[index]
            attachment_data['attach-z2AF Work Log0{}'.format(index + 1)] = (
                filename[index], value)

        return phantom.APP_SUCCESS, add_attachment_params_dict, attachment_data
    def _handle_create_object(self, param):
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))
        action_result = self.add_action_result(ActionResult(dict(param)))

        if not self._create_storage_client(action_result):
            self.save_progress("Could not create API client")
            return action_result.get_status()

        # Required values can be accessed directly
        path = param.get('path')
        bucket = param['bucket']
        vault_id = param['vault_id']

        try:
            self.debug_print('Rules.vault_info start')
            success, message, vault_info = Rules.vault_info(vault_id=vault_id)
            self.debug_print(
                'Rules.vault_info results: success: {}, message: {}, info: {}'.
                format(success, message, vault_info))
        except requests.exceptions.HTTPError:
            error_message = "Invalid Vault ID: %s" % (vault_id)
            return action_result.set_status(phantom.APP_ERROR, error_message)
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR, "Error opening file. {}".format(err))

        try:
            vault_info = list(vault_info)
            file_info = vault_info[0]
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while getting 'File Info'. {}".format(err))

        file_path = file_info['path']
        mime = magic.Magic(mime=True)

        file_mime_type = mime.from_file(file_path)

        file = MediaFileUpload(file_path, mimetype=file_mime_type)

        if not file_path:
            return action_result.set_status(
                phantom.APP_ERROR, "Could not find given vault ID in vault")

        if path:
            target_path = os.path.join(path, file_info["name"])
        else:
            target_path = file_info["name"]
        request = self._client.objects().insert(bucket=bucket,
                                                name=target_path,
                                                media_body=file)
        ret_val, response = self._send_request(request, action_result)

        if phantom.is_fail(ret_val):
            return ret_val

        action_result.add_data(response)
        return action_result.set_status(phantom.APP_SUCCESS,
                                        "Successfully created object")
示例#10
0
    def _handle_send_htmlemail(self, param):  # noqa: C901

        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))
        action_result = self.add_action_result(ActionResult(param))

        config = self.get_config()

        # Derive 'from' email address
        sender_address = config.get('sender_address',
                                    config.get(phantom.APP_JSON_USERNAME))
        email_from = param.get(SMTP_JSON_FROM, sender_address)

        email_to = self._handle_py_ver_compat_for_input_str(param['to'])
        email_cc = self._handle_py_ver_compat_for_input_str(param.get('cc'))
        email_bcc = self._handle_py_ver_compat_for_input_str(param.get('bcc'))
        # Filter method returns a Filter object on Python v3 and a List on Python v2
        # So, to maintain the uniformity the Filter object has been explicitly type casted to List
        email_to = [x.strip() for x in email_to.split(",")]
        email_to = list(filter(None, email_to))

        if email_cc:
            email_cc = [x.strip() for x in email_cc.split(",")]
            email_cc = list(filter(None, email_cc))

        if email_bcc:
            email_bcc = [x.strip() for x in email_bcc.split(",")]
            email_bcc = list(filter(None, email_bcc))

        email_subject = param.get('subject')
        email_headers = param.get('headers')
        email_html = param['html_body']
        email_text = param.get('text_body')
        attachment_json = param.get('attachment_json')

        encoding = config.get(SMTP_ENCODING, False)
        smtputf8 = config.get(SMTP_ALLOW_SMTPUTF8, False)

        if encoding:
            message_encoding = 'utf-8'
        else:
            message_encoding = 'ascii'

        # Validation for the 'from' email address
        if not email_from:
            return action_result.set_status(
                phantom.APP_ERROR, "Error: failed to get email sender")

        if not len(email_to):
            return action_result.set_status(
                phantom.APP_ERROR, "Error: failed to get email recipents")

        if email_headers:
            try:
                email_headers = json.loads(email_headers)
            except:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: custom email headers field is not valid json")

            if not isinstance(email_headers, dict):
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: custom email headers field is not a dictionary")

        else:
            email_headers = {}

        if attachment_json:
            try:
                attachment_json = json.loads(attachment_json)
            except:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: attachment json field is not valid json")

            if not isinstance(attachment_json, list):
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: attachment json field is not a list")

            has_dictionary = False
            for x in attachment_json:
                if isinstance(x, dict) and x.get('vault_id'):
                    has_dictionary = True
                    break

            if not has_dictionary:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: attachment json field does not contain any dictionaries with the \"vault_id\" key"
                )

            for attachment in attachment_json:
                for key, value in list(attachment.items()):
                    attachment.pop(key)
                    attachment[self._handle_py_ver_compat_for_input_str(
                        key)] = self._handle_py_ver_compat_for_input_str(value)

        else:
            attachment_json = []

        for i in range(1, 6):
            attachment_json += [{
                'vault_id':
                self._handle_py_ver_compat_for_input_str(
                    param.get('attachment{}'.format(i))),
                'content_id':
                self._handle_py_ver_compat_for_input_str(
                    param.get('content_id{}'.format(i)))
            }]

        attachment_json = list(
            filter(lambda x: isinstance(x, dict) and x.get('vault_id'),
                   attachment_json))

        root = MIMEMultipart('related')

        root['from'] = email_from
        root['to'] = ",".join(email_to)

        if email_cc:
            root['cc'] = ", ".join(email_cc)
            email_to.extend(email_cc)

        if email_bcc:
            email_to.extend(email_bcc)

        if email_subject:
            root['subject'] = self._handle_py_ver_compat_for_input_str(
                email_subject)

        for k, v in list(email_headers.items()):
            k = self._handle_py_ver_compat_for_input_str(k)
            root[k] = self._handle_py_ver_compat_for_input_str(v)

        if not email_text:
            email_text = self.html_to_text(email_html)

        msg = MIMEMultipart('alternative')

        try:
            if message_encoding == 'utf-8':
                msg.attach(
                    MIMEText(
                        self._handle_py_ver_compat_for_input_str(email_text),
                        'plain', 'utf-8'))
                msg.attach(
                    MIMEText(
                        self._handle_py_ver_compat_for_input_str(email_html),
                        'html', 'utf-8'))
            else:
                msg.attach(MIMEText(email_text, 'plain', 'ascii'))
                msg.attach(MIMEText(email_html, 'html', 'ascii'))
        except Exception as e:
            return action_result.set_status(
                phantom.APP_ERROR, "{0} Error message: {1}".format(
                    SMTP_UNICODE_ERROR_MSG,
                    self._get_error_message_from_exception(e)))
        root.attach(msg)

        for x in attachment_json:
            vault_id = x['vault_id']
            content_id = x.get('content_id')
            try:
                _, _, data = ph_rules.vault_info(
                    container_id=self.get_container_id(), vault_id=vault_id)
                if not data:
                    _, _, data = ph_rules.vault_info(vault_id=vault_id)
                data = list(data)
            except:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: failed to find vault ID: {}".format(vault_id))

            if data and len(data) > 0 and isinstance(
                    data[0], dict) and data[0].get('path'):
                path = data[0].get('path')

                attachment_path = data[0].get('name')
                filename = os.path.basename(attachment_path)
                filename = self._handle_py_ver_compat_for_input_str(filename)
                ctype, encoding = mimetypes.guess_type(attachment_path)
                if ctype is None:
                    ctype = 'application/octet-stream'
                maintype, subtype = ctype.split('/', 1)

                try:
                    if maintype == 'text':
                        with open(path, "r") as fp:
                            attachment = MIMEText(fp.read(), _subtype=subtype)

                    elif maintype == 'message':
                        with open(path, "r") as fp:
                            base_msg = message_from_file(fp)
                            attachment = MIMEMessage(base_msg,
                                                     _subtype=subtype)

                    elif maintype == 'image':
                        # Python 2to3 change
                        with open(path, "rb") as fp:
                            attachment = MIMEImage(fp.read(), _subtype=subtype)

                    else:
                        with open(path, "rb") as rfp:
                            attachment = MIMEBase(maintype, subtype)
                            attachment.set_payload(rfp.read())
                            encoders.encode_base64(attachment)

                except:
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "Error: failed to read the file for the vault ID: {}".
                        format(vault_id))

                attachment.add_header('Content-Disposition',
                                      'attachment',
                                      filename=filename)
                if content_id:
                    attachment.add_header(
                        'Content-ID', "<{}>".format(content_id.strip().lstrip(
                            '<').rstrip('>').strip()))

                root.attach(attachment)

            else:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error: failed to find vault id: {}".format(vault_id))

        try:
            # Provided mail_options=["SMTPUTF8"], to allow Unicode characters for py3 in to_list parameter
            # This will ensure that the to_list gets encoded with 'utf-8' and not the default encoding which is 'ascii'
            mail_options = list()
            if smtputf8:
                mail_options.append("SMTPUTF8")
            self._smtp_conn.sendmail(email_from,
                                     email_to,
                                     root.as_string(),
                                     mail_options=mail_options)

        except UnicodeEncodeError:
            return action_result.set_status(
                phantom.APP_ERROR, "{} {}".format(SMTP_ERR_SMTP_SEND_EMAIL,
                                                  SMTP_ERR_SMTPUTF8_CONFIG))
        except Exception as e:
            return action_result.set_status(
                phantom.APP_ERROR,
                "{} {}".format(SMTP_ERR_SMTP_SEND_EMAIL,
                               self._get_error_message_from_exception(e)))

        return action_result.set_status(phantom.APP_SUCCESS,
                                        SMTP_SUCC_SMTP_EMAIL_SENT)
示例#11
0
    def _add_attachments(self, outer, attachments, action_result,
                         message_encoding):

        if (not attachments):
            return phantom.APP_SUCCESS

        for attachment_vault_id in attachments:

            if self.get_container_id() == '0':

                if '.pdf' not in attachment_vault_id:
                    return action_result.set_status(phantom.APP_ERROR,
                                                    SMTP_ERR_SMTP_SEND_EMAIL)

                if hasattr(Vault, "get_phantom_home"):
                    report_dir_pre_4_0 = '{0}/www/reports'.format(
                        self.get_phantom_home())
                    report_dir_post_4_0 = '{0}/vault/reports'.format(
                        self.get_phantom_home())
                else:
                    report_dir_pre_4_0 = '/opt/phantom/www/reports'
                    report_dir_post_4_0 = '/opt/phantom/vault/reports'

                filename = ''
                for report_dir in (report_dir_post_4_0, report_dir_pre_4_0):
                    test_filename = os.path.join(report_dir,
                                                 attachment_vault_id)
                    test_filename = os.path.abspath(test_filename)

                    if os.path.isfile(test_filename):
                        filename = test_filename
                        break

                is_valid_path = filename.startswith(
                    report_dir_pre_4_0) or filename.startswith(
                        report_dir_post_4_0)

                if not filename or not is_valid_path:
                    return action_result.set_status(phantom.APP_ERROR,
                                                    SMTP_ERR_SMTP_SEND_EMAIL)

                with open(filename, 'rb') as fp:
                    msg = MIMEBase('application', 'pdf')
                    msg.set_payload(fp.read())

                filename = os.path.basename(filename)
                # handling ugly file names that are of the format "report_type__id-X__ts-<timestamp>.pdf", where 'X' is any number
                if '__' in filename:
                    pieces = filename.split('__')
                    if len(pieces) == 3:
                        filename = '{}_{}'.format(
                            pieces[0], pieces[2])  # get rid of __id_x__

                # Encode the payload using Base64
                encoders.encode_base64(msg)
            else:

                try:
                    _, _, vault_meta_info = ph_rules.vault_info(
                        container_id=self.get_container_id(),
                        vault_id=attachment_vault_id)
                    if not vault_meta_info:
                        _, _, vault_meta_info = ph_rules.vault_info(
                            vault_id=attachment_vault_id)
                        if not vault_meta_info:
                            self.invalid_vault_ids.append(attachment_vault_id)
                            continue
                    vault_meta_info = list(vault_meta_info)
                except:
                    self.invalid_vault_ids.append(attachment_vault_id)
                    continue

                # Check if we have any results
                if (len(vault_meta_info) == 0):
                    continue

                # pick up the first one, they all point to the same file
                vault_meta_info = vault_meta_info[0]

                attachment_path = vault_meta_info['name']
                file_path = vault_meta_info['path']

                # Guess the content type based on the file's extension.  Encoding
                # will be ignored, although we should check for simple things like
                # gzip'd or compressed files.
                filename = os.path.basename(attachment_path)
                ctype, encoding = mimetypes.guess_type(attachment_path)
                if ctype is None or encoding is not None:
                    # No guess could be made, or the file is encoded (compressed), so
                    # use a generic bag-of-bits type.
                    ctype = 'application/octet-stream'
                maintype, subtype = ctype.split('/', 1)
                try:
                    if maintype == 'text':
                        fp = open(file_path)
                        # Note: we should handle calculating the charset
                        msg = MIMEText(fp.read(), _subtype=subtype)
                        fp.close()
                    elif maintype == 'message':
                        fp = open(file_path)
                        base_msg = message_from_file(fp)
                        msg = MIMEMessage(base_msg, _subtype=subtype)
                        fp.close()
                    elif maintype == 'image':
                        fp = open(file_path, 'rb')
                        msg = MIMEImage(fp.read(), _subtype=subtype)
                        fp.close()
                    else:
                        fp = open(file_path, 'rb')
                        msg = MIMEBase(maintype, subtype)
                        msg.set_payload(fp.read())
                        fp.close()
                        # Encode the payload using Base64
                        encoders.encode_base64(msg)
                except Exception as e:
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        self._get_error_message_from_exception(e))

            # if using utf-8 encode the filename of the attachment as well
            if message_encoding == 'utf-8':
                filename = self._handle_py_ver_compat_for_input_str(filename)

            # Set the filename parameter
            msg.add_header('Content-Disposition',
                           'attachment',
                           filename=filename)
            outer.attach(msg)

        return phantom.APP_SUCCESS
示例#12
0
    def _handle_detonate_file(self, param):
        action_result = self.add_action_result(ActionResult(dict(param)))
        ret_val = self._check_version(action_result)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        vault_id = param['vault_id']
        file_name = param.get('file_name')
        dozip = param.get("zip_and_encrypt", False)
        zip_password = param.get("zip_password") or "infected"

        try:
            self.debug_print('Rules.vault_info start')
            success, message, vault_info = Rules.vault_info(vault_id=vault_id)
            self.debug_print(
                'Rules.vault_info results: success: {}, message: {}, info: {}'.
                format(success, message, vault_info))
        except requests.exceptions.HTTPError:
            error_message = "Invalid Vault ID: %s" % (vault_id)
            return action_result.set_status(phantom.APP_ERROR, error_message)
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR, "Error opening file. {}".format(err))

        if not vault_info:
            return action_result.set_status(phantom.APP_ERROR,
                                            "Invalid Vault ID")

        try:
            vault_info = list(vault_info)
            file_info = vault_info[0]
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while getting 'File Info'. {}".format(err))

        try:
            file_path = file_info['path']
        except KeyError:
            return action_result.set_status(
                phantom.APP_ERROR, "Error occurred while getting 'File Path'")

        if not file_name:
            try:
                file_name = file_info['name']
            except KeyError:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Error occurred while getting 'File Name'")

        try:
            payload = open(file_path, 'rb')
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR, "Error opening file. {}".format(err))

        if dozip:
            try:
                import zip_and_encrypt as z
                zae = z.zip_and_encrypt("/tmp/phcuckoo_app_", zip_password)
                zae.add(file_path)
                payload = zae.archive_fp

            except Exception as e:
                err = self._get_error_message_from_exception(e)
                return action_result.set_status(phantom.APP_ERROR, err)

        files = {'file': (file_name, payload)}

        ret_val, task_id = self._queue_analysis(action_result,
                                                "file",
                                                files=files)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        return self._poll_for_task(action_result, task_id, key=file_name)
示例#13
0
    def _upload_file(self, param):

        action_result = self.add_action_result(
            phantom.ActionResult(dict(param)))

        caption = param.get('caption', '')

        if caption:
            caption += ' -- '

        caption += 'Uploaded from Phantom'

        kwargs = {}
        params = {'channels': param['destination'], 'initial_comment': caption}

        if 'filetype' in param:
            params['filetype'] = param.get('filetype')

        if 'filename' in param:
            params['filename'] = param.get('filename')

        if 'parent_message_ts' in param:
            # Support for replying in thread
            params['thread_ts'] = param.get('parent_message_ts')

        if 'file' in param:
            vault_id = param.get('file')

            # check the vault for a file with the supplied ID
            try:
                success, message, vault_meta_info = ph_rules.vault_info(
                    vault_id=vault_id)
                vault_meta_info = list(vault_meta_info)
                if not success or not vault_meta_info:
                    error_msg = " Error Details: {}".format(
                        unquote(message)) if message else ''
                    return action_result.set_status(
                        phantom.APP_ERROR, "{}.{}".format(
                            SLACK_ERR_UNABLE_TO_FETCH_FILE.format(key="info"),
                            error_msg))
            except Exception as e:
                err = self._get_error_message_from_exception(e)
                return action_result.set_status(
                    phantom.APP_ERROR, "{}. {}".format(
                        SLACK_ERR_UNABLE_TO_FETCH_FILE.format(key="info"),
                        err))

            # phantom vault file path
            file_path = vault_meta_info[0].get('path')
            if not file_path:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    SLACK_ERR_UNABLE_TO_FETCH_FILE.format(key="path"))

            # phantom vault file name
            file_name = vault_meta_info[0].get('name')
            if not file_name:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    SLACK_ERR_UNABLE_TO_FETCH_FILE.format(key="name"))

            upfile = open(file_path, 'rb')
            params['filename'] = file_name
            kwargs['files'] = {'file': upfile}
        elif 'content' in param:
            params['content'] = self._handle_py_ver_compat_for_input_str(
                param.get('content'))
        else:
            return action_result.set_status(
                phantom.APP_ERROR, SLACK_ERR_FILE_OR_CONTENT_NOT_PROVIDED)

        ret_val, resp_json = self._make_slack_rest_call(
            action_result, SLACK_UPLOAD_FILE, params, **kwargs)
        if 'files' in kwargs:
            upfile.close()

        if not ret_val:
            message = action_result.get_message()
            if message:
                error_message = "{}: {}".format(SLACK_ERR_UPLOADING_FILE,
                                                message)
            else:
                error_message = SLACK_ERR_UPLOADING_FILE
            return action_result.set_status(phantom.APP_ERROR, error_message)

        file_json = resp_json.get('file', {})

        thumbnail_dict = {}
        pop_list = []

        for key, value in list(file_json.items()):

            if key.startswith('thumb'):

                pop_list.append(key)

                name_arr = key.split('_')

                thumb_name = "{0}_{1}".format(name_arr[0], name_arr[1])

                if thumb_name not in thumbnail_dict:
                    thumbnail_dict[thumb_name] = {}

                thumb_dict = thumbnail_dict[thumb_name]

                if len(name_arr) == 2:
                    thumb_dict['img_url'] = value

                elif name_arr[2] == 'w':
                    thumb_dict['width'] = value

                elif name_arr[2] == 'h':
                    thumb_dict['height'] = value

            elif key == 'initial_comment':
                resp_json['caption'] = value
                pop_list.append(key)

            elif key in ['channels', 'ims', 'groups']:

                if 'destinations' not in resp_json:
                    resp_json['destinations'] = []

                resp_json['destinations'] += value

                pop_list.append(key)

            elif key == 'username':
                pop_list.append(key)

            elif key == 'user':
                resp_json['sender'] = value
                pop_list.append(key)

        for poppee in pop_list:
            file_json.pop(poppee)

        resp_json['thumbnails'] = thumbnail_dict

        action_result.add_data(resp_json)

        return action_result.set_status(phantom.APP_SUCCESS,
                                        SLACK_SUCC_FILE_UPLOAD)
示例#14
0
    def _handle_detonate_file(self, param: Dict[str, Any]):
        action_result = self.add_action_result(ActionResult(dict(param)))
        status, api = self._get_api(action_result)
        if api is None:
            return status

        vault_id = param["vault_id"]
        try:
            _, _, vault_info = phantom_rules.vault_info(vault_id=vault_id)
        except Exception:  # pylint: disable=broad-except
            return action_result.set_status(
                phantom.APP_ERROR,
                f"Error while getting vault info for vault_id {vault_id}",
            )

        if len(vault_info) > 1:
            return action_result.set_status(
                phantom.APP_ERROR,
                f"Found multiple files for vault_id {vault_id}")

        if len(vault_info) == 0:
            return action_result.set_status(
                phantom.APP_ERROR, f"No sample found for vault_id {vault_id}")

        vault_info = vault_info[0]

        file_path = vault_info.get("path")
        if not file_path:
            return action_result.set_status(
                phantom.APP_ERROR,
                f"Cannot find a path for vault id {vault_id}")

        self.save_progress("Submitting file %s" % vault_id)

        params = {"reanalyze": True}
        if param.get("comment"):
            params["comment"] = param.get("comment")
        if param.get("tags"):
            params["tags"] = param.get("tags")
        if param.get("type"):
            params["sample_type"] = param.get("type")
        if param.get("config"):
            params["user_config"] = param.get("config")
        if param.get("jobrules"):
            params["jobrule_entries"] = param.get("jobrules")

        if param.get("file_name"):
            params["sample_filename_b64enc"] = base64.b64encode(
                param.get("file_name").encode()).decode()
        elif vault_info.get("name"):
            params["sample_filename_b64enc"] = base64.b64encode(
                vault_info["name"].encode()).decode()

        try:
            res = api.submit_file(file_path, params=params)
        except Exception as exc:  # pylint: disable=broad-except
            err = self._get_error_message_from_exception(exc)
            return action_result.set_status(
                phantom.APP_ERROR, f"{VMRAY_ERR_SUBMIT_FILE}. Details: {err}")

        try:
            if res["errors"]:
                errors = [
                    err.get("error_msg", "NO_ERROR_MSG_GIVEN")
                    for err in res["errors"]
                ]
                return action_result.set_status(phantom.APP_ERROR,
                                                ";".join(errors))

            submission_id = res["submissions"][0]["submission_id"]
            submission_url = res["submissions"][0]["submission_webif_url"]
        except Exception as exc:  # pylint: disable=broad-except
            err = self._get_error_message_from_exception(exc)
            return action_result.set_status(phantom.APP_ERROR,
                                            VMRAY_ERR_SERVER_RES.format(err))

        submission_finished = True

        iocs_only = param.get("ioc_only", True)
        status, report = self._get_report(action_result, submission_id,
                                          DEFAULT_TIMEOUT, iocs_only)
        if phantom.is_fail(status):
            if report:
                error_msg, _exc = report
                if error_msg == VMRAY_ERR_SUBMISSION_NOT_FINISHED:
                    submission_finished = False
                else:
                    return action_result.set_status(phantom.APP_ERROR,
                                                    f"{error_msg}, {_exc}")
                report = None
            else:
                return action_result.get_status()
        try:
            if report:
                for analysis in report["analyses"]:
                    action_result.add_data({"analysis": analysis})
                if report["reputation_lookup"]:
                    action_result.add_data(
                        {"reputation_lookup": report["reputation_lookup"][0]})
                action_result.update_summary({
                    "billing_type":
                    report["billing_type"],
                    "recursive_submission_ids":
                    report["recursive_submission_ids"],
                    "verdict":
                    report["verdict"],
                })
        except Exception as exc:  # pylint: disable=broad-except
            err = self._get_error_message_from_exception(exc)
            return action_result.set_status(phantom.APP_ERROR,
                                            VMRAY_ERR_SERVER_RES.format(err))

        action_result.update_summary({
            "submission_id":
            submission_id,
            "url":
            submission_url,
            "submission_finished":
            submission_finished,
        })

        return action_result.set_status(phantom.APP_SUCCESS)
    def _handle_request_cert(self, param):
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))

        action_result = self.add_action_result(ActionResult(dict(param)))

        container_id = self.get_container_id()

        # required params
        csr = param["csr"]  # vault_id or filename
        server_platform_id = consts.PLATFORM_MAP[param["server_platform"]]
        order_validity_years = int(param["order_validity"])

        # optional params
        cn = param.get("common_name")
        signature_hash = param.get("signature_hash")

        success, msg, vault_info = ph_rules.vault_info(
            container_id=container_id)

        if not success:
            return action_result.set_status(phantom.APP_ERROR, msg)

        filename = ""
        for vault_item in vault_info:
            if csr == vault_item["vault_id"] or csr == vault_item["name"]:
                filename = vault_item["path"]
                break
        else:
            # 'else' on a for loop is called if it IS NOT broken (i.e. break is never called)
            # in this case that means we did not find a vault item in the list, so return an error
            return action_result.set_status(
                phantom.APP_ERROR, "Could not find the csr in the file vault")

        with open(filename, "r") as fp:
            csr_data = fp.read()

        # try to parse the csr
        try:
            csr_req = x509.load_pem_x509_csr(bytes(csr_data, "utf-8"))
            parsed_signature_hash = csr_req.signature_hash_algorithm.name
            # https://cryptography.io/en/latest/x509/reference/#cryptography.x509.Name.get_attributes_for_oid
            parsed_cn = csr_req.subject.get_attributes_for_oid(
                x509.oid.NameOID.COMMON_NAME)[0].value
            self.save_progress(
                "Parsed csr values: siganture_hash={0} CN={1}".format(
                    parsed_signature_hash, parsed_cn))
        except Exception:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Failed to parse the csr, make sure it is in PEM format")

        payload = {
            "certificate": {
                "common_name": cn or parsed_cn,
                "csr": csr_data,
                "signature_hash": signature_hash or parsed_signature_hash,
                "sever_platform": {
                    "id": server_platform_id,
                },
            },
            "organization": {
                "id": int(self._org_id)
            },
            "order_validity": {
                "years": order_validity_years
            }
        }

        # submit the request
        ret_val, response = self._make_rest_call("/order/certificate/ssl",
                                                 action_result,
                                                 method="post",
                                                 json=payload)

        if phantom.is_fail(ret_val):
            # the call to the 3rd party device or service failed, action result should contain all the error details
            return action_result.get_status()

        # Add the response into the data section
        action_result.add_data(response)

        # Add a dictionary that is made up of the most important values from data into the summary
        action_result.update_summary({
            "order_id":
            response["id"],
            "request_id":
            response["requests"][0]["id"],
            "request_status":
            response["requests"][0]["status"],
            "common_name":
            payload["certificate"]["common_name"],
            "signature_hash":
            payload["certificate"]["signature_hash"]
        })

        return action_result.set_status(phantom.APP_SUCCESS)
    def _get_attachment(self, param):

        # Create action result
        action_result = self.add_action_result(ActionResult(param))

        # Create RT object
        if phantom.is_fail(self._create_rt_session(action_result)):
            return action_result.get_status()

        # Get parameters
        ticket_id = param[RT_JSON_ID]
        attachment_id = param[RT_JSON_ATTACHMENT]

        # Set up the result data
        data = action_result.add_data(dict())
        data['id'] = ticket_id
        data['attachment_id'] = attachment_id

        # Request the attachment meta data
        ret_val, resp_text = self._make_rest_call(
            "ticket/{0}/attachments/{1}".format(ticket_id, attachment_id),
            action_result)

        if phantom.is_fail(ret_val):
            return ret_val

        if '# Invalid attachment id' in resp_text:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Attachment with ID {0} not found on ticket {1}".format(
                    attachment_id, ticket_id))

        if re.findall('# Ticket .+ does not exist.', resp_text):
            return action_result.set_status(
                phantom.APP_ERROR,
                "Ticket {0} does not exist.".format(ticket_id))

        # Look for the filename in the meta data
        filename_index = resp_text.find('filename')

        if filename_index == -1:
            file_name = "noname"
            self.debug_print("Filename not found in header, setting to noname")
        else:
            start_filename = resp_text.find('=', filename_index) + 2
            end_filename = resp_text.find('\n', filename_index) - 1
            file_name = resp_text[start_filename:end_filename]

        if not file_name:
            file_name = "noname"
            self.save_progress(
                "Filename not found in header, setting to noname")

        # Look for the file length in the meta data
        length_index = resp_text.find('Content-Length')

        if length_index == -1:
            return action_result.set_status(
                phantom.APP_ERROR, "Cannot find Content-Length of attachment")

        start_length = resp_text.find(':', length_index) + 2
        end_length = resp_text.find('\n', length_index)

        length = int(resp_text[start_length:end_length])

        if length == 0:
            return action_result.set_status(
                phantom.APP_SUCCESS, "File is empty, nothing to do here")

        # Request the attachment content
        ret_val, response = self._make_rest_call(
            "ticket/{0}/attachments/{1}/content".format(
                ticket_id, attachment_id), action_result)

        # Convert to bytes and strip away headers and trailers.
        content = response.content

        if phantom.is_fail(ret_val):
            return ret_val

        # find first newline
        skip = content.find(b'\n')
        if skip == -1:
            return action_result.set_status(
                phantom.APP_ERROR, "Cannot find first line of file content")
        # skip first and second newline
        skip += 2

        # Let the actiond handle i/o exceptions and return the errors.
        ret_val = Vault.create_attachment(content[skip:length + skip],
                                          self.get_container_id(),
                                          file_name=file_name)

        if ret_val['succeeded'] is not True:
            return action_result.set_status(
                phantom.APP_ERROR, "Error saving file to vault: {0}".format(
                    ret_val.get('error', 'Unknwon error')))

        vault_id = ret_val['vault_id']
        _, _, file_info = vault_info(vault_id=vault_id,
                                     container_id=self.get_container_id())

        if len(file_info) == 0:
            return action_result.set_status(
                phantom.APP_ERROR, "File not found in vault after adding")

        file_info = file_info[0]

        data['vault_id'] = vault_id
        data['name'] = file_info['name']
        data['size'] = file_info['size']
        data['sha1'] = file_info['metadata']['sha1']
        data['sha256'] = file_info['metadata']['sha256']
        data['md5'] = file_info['metadata']['md5']
        data['path'] = file_info['path']

        return action_result.set_status(phantom.APP_SUCCESS)
    def _handle_detonate_file(self, param):
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))
        action_result = self.add_action_result(ActionResult(dict(param)))

        vault_id = param['vault_id']

        try:
            success, message, vault_meta_info = ph_rules.vault_info(
                vault_id=vault_id)
            vault_meta_info = list(vault_meta_info)
            if not success or not vault_meta_info:
                error_msg = " Error Details: {}".format(
                    unquote(message)) if message else ''
                return action_result.set_status(
                    phantom.APP_ERROR, "{}. {}".format(
                        ANYRUN_ERR_UNABLE_TO_FETCH_FILE.format(
                            key="vault meta info"), error_msg))
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR, "{}. {}".format(
                    ANYRUN_ERR_UNABLE_TO_FETCH_FILE.format(
                        key="vault meta info"), err))

        try:
            # phantom vault file path
            file_path = vault_meta_info[0].get('path')
            if not file_path:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    ANYRUN_ERR_UNABLE_TO_FETCH_FILE.format(key="path"))
        except:
            return action_result.set_status(
                phantom.APP_ERROR,
                ANYRUN_ERR_UNABLE_TO_FETCH_FILE.format(key="path"))

        self.save_progress("Detonating file {}".format(file_path))
        files = [('file', open(file_path, 'rb'))]

        # make rest call
        ret_val, response = self._make_rest_call(ANYRUN_DETONATE_FILE_ENDPOINT,
                                                 action_result,
                                                 method="post",
                                                 files=files,
                                                 headers=self._headers)

        if phantom.is_fail(ret_val):
            # the call to the 3rd party device or service failed, action result should contain all the error details
            return action_result.get_status()

        self.save_progress("Successfully detonated file")
        try:
            action_result.add_data(response['data'])
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while processing response from server. {}".
                format(err))

        return action_result.set_status(phantom.APP_SUCCESS,
                                        "Successfully detonated file")
示例#18
0
def zip_extract(container=None, vault_id=None, password=None, **kwargs):
    """
    Extract all files recursively from a .zip archive. Add the extracted files to the vault and return the vault IDs of the extracted files. Provide a password if needed to decrypt.
    
    Args:
        container (CEF type: phantom container id): The container that extracted files will be added to. Should be a container ID or a container dictionary.
        vault_id: The vault ID of the zip archive to be unzipped.
        password: The password to use for decryption of the zip archive if necessary.
    
    Returns a JSON-serializable object that implements the configured data paths:
        zip_file_info.name: File name of the zip file in the vault
        zip_file_info.user: User who added the zip file to the vault
        output_files.*.file_name: The names of the files extracted from the zip archive.
        output_files.*.file_path: The file paths of the files extracted from the zip archive.
        output_files.*.vault_id: The vault IDs of the files extracted from the zip archive.
    """
    ############################ Custom Code Goes Below This Line #################################
    import json
    import phantom.rules as phantom

    import os
    from pathlib import Path
    import zipfile

    outputs = {'output_files': []}

    # Ensure valid container input
    if isinstance(container, dict) and container.get('id'):
        container_id = container['id']
    elif isinstance(container, int):
        container_id = container
    else:
        raise TypeError(
            "The input 'container' is neither a container dictionary nor an int, so it cannot be used"
        )

    # check the vault_id input
    success, message, info = phantom.vault_info(vault_id=vault_id,
                                                container_id=container_id)
    if not success:
        raise ValueError("Could not find file in vault")
    outputs['zip_file_info'] = info[0]

    if password and not isinstance(password, str):
        raise TypeError("password must be a string")

    # create a directory to store the extracted files before adding to the vault
    extract_path = Path("/opt/phantom/vault/tmp/") / vault_id
    extract_path.mkdir(parents=True, exist_ok=True)

    # extract the files with ZipFile
    with zipfile.ZipFile(info[0]["path"]) as f_zip:
        if password:
            f_zip.extractall(str(extract_path), pwd=password.encode())
        else:
            f_zip.extractall(str(extract_path))

    # add each extracted file to the vault and the output
    for p in extract_path.rglob("*"):
        if p.is_file():
            success, message, vault_id = phantom.vault_add(
                container=container_id, file_location=str(p), file_name=p.name)
            if not success:
                raise RuntimeError(
                    'failed to add file to vault with path {}'.format(str(p)))
            outputs['output_files'].append({
                'file_path': str(p),
                'file_name': p.name,
                'vault_id': vault_id
            })

    # Return a JSON-serializable object
    assert json.dumps(
        outputs
    )  # Will raise an exception if the :outputs: object is not JSON-serializable
    return outputs
    def _handle_detonate_file(self, param):
        # Implement the handler here
        # use self.save_progress(...) to send progress messages back to the platform
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))

        # Add an action result object to self (BaseConnector) to represent the action for this param
        action_result = self.add_action_result(ActionResult(dict(param)))

        # Access action parameters passed in the 'param' dictionary
        vault_id = self._handle_py_ver_compat_for_input_str(
            param.get('vault_id'))

        # Get vault info from the vauld_id parameter
        try:
            success, msg, vault_info = phantom_rules.vault_info(
                vault_id=vault_id)
        except:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while fetching the vault information of the specified Vault ID"
            )

        if not vault_info:
            try:
                error_msg = "Error occurred while fetching the vault information of the Vault ID: {}".format(
                    vault_id)
            except:
                error_msg = "Error occurred while fetching the vault information of the specified Vault ID"

            return action_result.set_status(phantom.APP_ERROR, error_msg)

        # Loop through the Vault infomation
        for item in vault_info:
            vault_path = item.get('path')
            if vault_path is None:
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Could not find a path associated with the provided Vault ID"
                )
            try:
                # Open the file
                vault_file = open(vault_path, 'rb')
                # Create the files data to send to the console
                files = {'file': (item['name'], vault_file)}
            except Exception as e:
                error_msg = self._get_error_message_from_exception(e)
                return action_result.set_status(
                    phantom.APP_ERROR,
                    "Unable to open vault file: {}".format(error_msg))

        # Process parameters
        profile = param.get("profile")
        try:
            profile = [x.strip() for x in profile.split(',')]
        except Exception:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while processing the {}".format(
                    PROFILE_ACTION_PARAM))
        profile = list(filter(None, profile))
        if not profile:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Please provide a valid value for the {}".format(
                    PROFILE_ACTION_PARAM))

        # Get the other parameters and information
        priority = 0 if param['priority'].lower() == 'normal' else 1
        analysis_type = 1 if param['analysis_type'].lower() == 'live' else 2

        timeout = param.get('timeout')
        # Validate 'timeout' action parameter
        ret_val, timeout = self._validate_integer(action_result, timeout,
                                                  TIMEOUT_ACTION_PARAM)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        force = "true" if param.get('force', True) else "false"

        # When analysis type = 2 (Sandbox), prefetch must equal 1
        if analysis_type == 2:
            prefetch = 1
        else:
            prefetch = 1 if param.get('prefetch', False) else 0

        enable_vnc = "true" if param.get('enable_vnc', False) else "false"

        data = {}

        # Get the application code to use for the detonation
        application = self.get_application_code(param.get('application'))

        # Create the data based on the parameters
        options = {
            "priority": priority,
            "analysistype": analysis_type,
            "force": force,
            "prefetch": prefetch,
            "profiles": profile,
            "application": application,
            "timeout": timeout,
            "enable_vnc": enable_vnc
        }

        # Need to stringify the options parameter
        data = {'options': json.dumps(options)}

        endpoint = FIREEYEAX_DETONATE_FILE_ENDPOINT

        # make rest call
        ret_val, response = self._make_rest_call(endpoint,
                                                 action_result,
                                                 method="post",
                                                 files=files,
                                                 data=data)

        if phantom.is_fail(ret_val):
            return action_result.get_status()

        # Now post process the data, uncomment code as you deem fit
        try:
            resp_data = response[0]
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while fetching data from API response. {}".
                format(err))

        try:
            resp_data['submission_details'] = json.loads(
                resp_data['submission_details'])
        except Exception as e:
            err = self._get_error_message_from_exception(e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while processing API response. {}".format(err))

        # Add the response into the data section
        if isinstance(resp_data, list):
            for alert in resp_data:
                action_result.add_data(alert)
        else:
            action_result.add_data(resp_data)

        return action_result.set_status(phantom.APP_SUCCESS)
示例#20
0
    def _handle_detonate_file(self, param):

        # Implement the handler here
        # use self.save_progress(...) to send progress messages back to the platform
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))

        # Add an action result object to self (BaseConnector) to represent the action for this param
        action_result = self.add_action_result(ActionResult(dict(param)))

        # Place vault id in in its own variable.
        vault_id_str = param['vault_id']

        try:
            success, message, info = rules.vault_info(vault_id=vault_id_str)
            info = json.loads(json.dumps(info[0]))
            filepath = info['path']
        except:
            return action_result.set_status(
                phantom.APP_ERROR,
                'File not found in vault: {}'.format(vault_id_str))

        # Issue request to Intezer Analyze
        endpoint = 'analyze'

        # Perform file check
        file_check = self.check_file(str(filepath), action_result)

        # Check file type is correct
        if not file_check:
            return

        str_vault_dict = str(filepath)

        file = {'file': open(str_vault_dict, 'rb')}
        self.save_progress(
            "File has been found location is: {}".format(str_vault_dict))

        # Make connection to the Intezer Analyze endpoint
        ret_val, response = self._make_rest_call(endpoint,
                                                 action_result,
                                                 method="post",
                                                 params=file)

        if (phantom.is_fail(ret_val)):
            # so just return from here
            # the call to the 3rd party device or service failed, action result should contain all the error details
            message = "Failed request to detonate file endpoint. Message: {}, Response: {}".format(
                response, ret_val)
            return action_result.set_status(phantom.APP_ERROR,
                                            status_message=message)

        if response['result_url']:
            self.save_progress(
                "File has been posted to Intezer Analyze successfully")

            # Get result URL
            result_url = response['result_url'][1:]

            # Make connection to the Intezer Report Endpoint
            ret_val, response = self._make_rest_call(result_url, action_result)

            # If the response is a failure
            if (phantom.is_fail(ret_val)):
                message = "Failed retrieving analysis id from output. Message: {}".format(
                    response)
                return action_result.set_status(phantom.APP_ERROR,
                                                status_message=message)
            # Report is Queued or In Progress
            i = 0
            # While the result is not succeeded or 50 seconds has not elapsed
            while i < 10 and response['status'] != 'succeeded':
                self.save_progress(
                    "Sleeping 60 seconds while report is being fetched")
                # Sleep 60 seconds
                time.sleep(60)
                # Make connection to the Intezer Report Endpoint
                ret_val, response = self._make_rest_call(
                    result_url, action_result)
                # Increment the timeout counter
                i += 1
                # If we reach 10 minutes and the analysis has not returned
                if i == 10:
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        status_message=
                        "Timed out whilst waiting for report to build")
                # If the response is a failure
                if (phantom.is_fail(ret_val)):
                    message = "Failed retrieving report for Intezer Analyze. Message: {}".format(
                        response)
                    return action_result.set_status(phantom.APP_ERROR,
                                                    status_message=message)

            # Create new python dictionary to store output
            data_output = response

            # Add the response into the data section
            action_result.add_data(data_output)

            # Add a dictionary that is made up of the most important values from data into the summary
            summary = action_result.update_summary({})
            summary['sha256'] = data_output['result']['sha256']
            summary['verdict'] = data_output['result']['verdict']
            summary['analysis_url'] = data_output['result']['analysis_url']

            # Return success, no need to set the message, only the status
            # BaseConnector will create a textual message based off of the summary dictionary
            return action_result.set_status(phantom.APP_SUCCESS)
示例#21
0
    def _handle_upload_file(self, param):

        # Implement the handler here
        # use self.save_progress(...) to send progress messages back to the platform
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))

        # Add an action result object to self (BaseConnector) to represent the action for this param
        action_result = self.add_action_result(ActionResult(dict(param)))

        # Access action parameters passed in the 'param' dictionary

        # Required values can be accessed directly
        config = self.get_config()

        endpoint = config['endpoint']
        username = config['username']
        password = config['password']

        vault_id = param['vault_id']

        # Find vault path  and info for given vault ID
        try:
            success, message, vault_info = phrules.vault_info(
                vault_id=vault_id)
            vault_info = list(vault_info)[0]
        except IndexError:
            return action_result.set_status(phantom.APP_ERROR,
                                            VAULT_ERR_FILE_NOT_FOUND), None
        except Exception:
            return action_result.set_status(phantom.APP_ERROR,
                                            VAULT_ERR_VAULT_ID_NOT_VALID), None

        if not vault_info:
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error while fetching the vault information of the vault id: '{}'"
                .format(vault_id))

        file_name = vault_info.get('path')
        if file_name is None:
            return action_result.set_status(phantom.APP_ERROR,
                                            VAULT_ERR_PATH_NOT_FOUND)

        # Optional values should use the .get() function
        node_name = param.get('node_name', 'wlWhiteListIPv4')
        file_type = param.get('file_type', 'IPv4')
        dry_run = param.get('dry_run', False)
        is_remove = param.get('is_remove', False)
        is_update = param.get('is_update', False)

        self.save_progress("[-] Path: {}".format(os.getcwd()))
        self.save_progress(
            "vault id: {} - target node_name: {}  file_type: {}    dry_run: {}"
            .format(vault_id, node_name, file_type, dry_run))

        # Command Constructor
        dir_path = os.path.dirname(os.path.realpath(__file__))
        script_abs_name = "{}/minemeld-sync.py".format(
            dir_path)  # /opt/phantom/bin/phenv python2.7 ..

        dry_run_arg = "--dry-run"
        remove_arg = "--delete"
        update_arg = "--update"
        base_cmd = ("/opt/phantom/bin/phenv python2.7 {script_abs_name}"
                    " -k -m {endpoint} -u {username} -p {password}"
                    " -t {file_type} {node_name} {input_file}".format(
                        script_abs_name=script_abs_name,
                        endpoint=endpoint,
                        username=username,
                        password=password,
                        file_type=file_type,
                        node_name=node_name,
                        input_file=file_name))

        final_cmd = base_cmd

        if dry_run:
            final_cmd = "{} {}".format(final_cmd, dry_run_arg)
        if is_remove:
            final_cmd = "{} {}".format(final_cmd, remove_arg)
        if is_update:
            final_cmd = "{} {}".format(final_cmd, update_arg)

        out = subprocess.Popen(final_cmd.split(" "),
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT)
        stdout, stderr = out.communicate()

        self.save_progress("stdout: {} - stderr: {} ".format(stdout, stderr))

        # Now post process the data,  uncomment code as you deem fit

        # Add the response into the data section
        action_result.add_data(stdout)
        action_result.add_data(stderr)

        # Add a dictionary that is made up of the most important values from data into the summary
        # summary = action_result.update_summary({})
        # summary['num_data'] = len(action_result['data'])

        # Return success, no need to set the message, only the status
        # BaseConnector will create a textual message based off of the summary dictionary

        # For now return Error with a message, in case of success we don't set the message, but use the summary
        # return action_result.set_status(phantom.APP_ERROR, "Action not yet implemented")
        return action_result.set_status(phantom.APP_SUCCESS)
示例#22
0
    def _handle_post_url(self, param):

        action_result = ActionResult(dict(param))
        self.add_action_result(action_result)

        params = dict()
        params['url'] = param["url"]
        params['filename'] = param.get('filename')
        params['key'] = self._api_key

        # Check if we have a size
        sizes = {"tiny": "T", "small": "S", "normal": "N", "medium": "M", "large": "L", "full page": "F"}
        test = param.get("size")
        if not test:
            self.save_progress("Size was blank, using the default \"full page\" size")
            test = "full page"
        if not sizes.get(test.lower()):
            self.save_progress("Given size not found, using the default \"full page\" size")
            params['size'] = "F"
        else:
            params['size'] = sizes[test.lower()]

        # Check if we have a Secret Phrase
        if self._api_phrase is None:
            params['hash'] = ""
        else:
            params['hash'] = str(hashlib.md5((params['url'] + self._api_phrase).encode('utf-8')).hexdigest())

        params['cacheLimit'] = '0'
        params['format'] = 'JPG'
        params['timeout'] = '200'

        ret_val, image = self._make_rest_call('', action_result, params, method='post', stream=True)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        permalink = None
        # only create a permalink if the hash is used
        if params['hash']:
            permalink = self._get_sspermalink('', params=params, method='post')

        if params['filename']:
            file_name = "{}.jpg".format(params['filename'])
        else:
            file_name = "{0}{1}".format(param["url"], "_screenshot.jpg")

        is_download = False
        if hasattr(Vault, "create_attachment"):
            vault_ret = Vault.create_attachment(image, self.get_container_id(), file_name=file_name)

            if vault_ret.get('succeeded'):
                action_result.set_status(phantom.APP_SUCCESS, "Downloaded screenshot")
                _, _, vault_meta_info = ph_rules.vault_info(container_id=self.get_container_id(), vault_id=vault_ret[phantom.APP_JSON_HASH])
                if not vault_meta_info:
                    self.debug_print("Error while fetching meta information for vault ID: {}".format(vault_ret[phantom.APP_JSON_HASH]))
                    return action_result.set_status(phantom.APP_ERROR, "Could not find meta information of the downloaded screenshot's Vault")

                vault_path = list(vault_meta_info)[0]['path']
                summary = {
                        phantom.APP_JSON_VAULT_ID: vault_ret[phantom.APP_JSON_HASH],
                        phantom.APP_JSON_NAME: file_name,
                        'vault_file_path': vault_path,
                        phantom.APP_JSON_SIZE: vault_ret.get(phantom.APP_JSON_SIZE)}
                if permalink:
                    summary['permalink'] = permalink
                action_result.update_summary(summary)
                is_download = True
            else:
                is_download = False
        if not is_download:
            if hasattr(Vault, 'get_vault_tmp_dir'):
                temp_dir = Vault.get_vault_tmp_dir()
            else:
                temp_dir = '/opt/phantom/vault/tmp'
            temp_dir = "{0}{1}".format(temp_dir, '/{}'.format(uuid.uuid4()))
            os.makedirs(temp_dir)
            file_path = os.path.join(temp_dir, 'tempimage.jpg')

            with open(file_path, 'wb') as f:
                f.write(image)

            success, message, vault_id = ph_rules.vault_add(container=self.get_container_id(), file_location=file_path, file_name=file_name)

            if success:
                action_result.set_status(phantom.APP_SUCCESS, "Downloaded screenshot")
                _, _, vault_meta_info = ph_rules.vault_info(container_id=self.get_container_id(), vault_id=vault_id)
                if not vault_meta_info:
                    self.debug_print("Error while fetching meta information for vault ID: {}".format(vault_id))
                    return action_result.set_status(phantom.APP_ERROR, "Could not find meta information of the downloaded screenshot's Vault")

                vault_path = list(vault_meta_info)[0]['path']
                summary = {
                        phantom.APP_JSON_VAULT_ID: vault_id,
                        phantom.APP_JSON_NAME: file_name,
                        'vault_file_path': vault_path}

                if permalink:
                    summary['permalink'] = permalink
                action_result.update_summary(summary)
            else:
                return action_result.set_status(phantom.APP_ERROR, "Error occurred while saving file to vault: {}".format(message))

        return action_result.get_status()
    def _download_report_pdf(self, report_id, container_id, action_result,
                             summary_data):

        file_name = 'deepsight_report_{}.pdf'.format(report_id)

        self.send_progress(DEEPSIGHT_MSG_DOWNLOADING_REPORT)

        pdf_accept_headers = {"Accept": "application/pdf"}

        return_val, resp = self._make_rest_call(
            DEEPSIGHT_ENDPOINT_MATI_REPORT_PDF.format(mati_id=report_id),
            action_result,
            accept_header=pdf_accept_headers)

        # Something went wrong with the request
        if phantom.is_fail(return_val):
            return action_result.get_status()

        # Generate pdf from response content
        if (resp.get(DEEPSIGHT_JSON_RESPONSE)):
            pdf_resp = resp.get(DEEPSIGHT_JSON_RESPONSE)
            temp_dir = tempfile.mkdtemp()
            file_path = os.path.join(temp_dir, file_name)
            with open(file_path, 'wb') as fw:
                fw.write(pdf_resp)

            # Check if the report pdf with same file name is already available in vault
            success, message, vault_list = ph_rules.vault_info(
                vault_id=None, file_name=None, container_id=container_id)
            # Iterate through each vault item in the container and compare name and size of file
            for vault in vault_list:
                if vault.get('name') == file_name and vault.get(
                        'size') == os.path.getsize(file_path):
                    self.send_progress(DEEPSIGHT_REPORT_PDF_ALREADY_AVAILABLE)
                    vault_details = {}
                    vault_details[phantom.APP_JSON_SIZE] = vault.get('size')
                    vault_details[
                        phantom.APP_JSON_TYPE] = DEEPSIGHT_REPORT_FILE_TYPE
                    vault_details[phantom.APP_JSON_CONTAINS] = [
                        DEEPSIGHT_REPORT_FILE_TYPE
                    ]
                    vault_details[
                        phantom.APP_JSON_ACTION_NAME] = self.get_action_name()
                    vault_details[
                        phantom.APP_JSON_APP_RUN_ID] = self.get_app_run_id()
                    vault_details[phantom.APP_JSON_VAULT_ID] = vault.get(
                        'vault_id')
                    vault_details[DEEPSIGHT_JSON_REPORT_FILE_NAME] = file_name
                    json_data = action_result.get_data()
                    json_data[0].update({'vault': vault_details})
                    summary_data.update({'vault_id': vault.get('vault_id')})
                    summary_data['pdf_availability'] = True
                    return phantom.APP_SUCCESS

            ret_val = self._move_file_to_vault(container_id,
                                               os.path.getsize(file_path),
                                               DEEPSIGHT_REPORT_FILE_TYPE,
                                               file_path, action_result,
                                               summary_data)
            shutil.rmtree(temp_dir)

            # Something went wrong while moving file to vault
            if phantom.is_fail(ret_val):
                return action_result.get_status()

            summary_data['pdf_availability'] = True

        else:
            # If pdf not available, treated as app success
            self.send_progress(DEEPSIGHT_REPORT_PDF_UNAVAILABLE)
            summary_data['pdf_availability'] = False

        return phantom.APP_SUCCESS