Ejemplo n.º 1
0
    def _exchange_online_delete_email_function(self, event, *args, **kwargs):
        """Function: Delete a message in the specified user's mailbox."""
        try:
            # Initialize the results payload
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Validate fields
            validate_fields(['exo_email_address', 'exo_messages_id'], kwargs)

            # Get the function parameters
            email_address = kwargs.get('exo_email_address')  # text
            mailfolders_id = kwargs.get('exo_mailfolders_id')  # text
            messages_id = kwargs.get('exo_messages_id')  # text

            LOG.info(u"exo_email_address: %s", email_address)
            LOG.info(u"exo_mailfolders_id: %s", mailfolders_id)
            LOG.info(u"exo_messages_id: %s", messages_id)

            yield StatusMessage(u"Starting delete message for email address: {}".format(email_address))

            # Get the MS Graph helper class
            MS_graph_helper = MSGraphHelper(self.options.get("microsoft_graph_token_url"),
                                            self.options.get("microsoft_graph_url"),
                                            self.options.get("tenant_id"),
                                            self.options.get("client_id"),
                                            self.options.get("client_secret"),
                                            self.options.get("max_messages"),
                                            self.options.get("max_users"),
                                            self.options.get("max_retries_total", MAX_RETRIES_TOTAL),
                                            self.options.get("max_retries_backoff_factor", MAX_RETRIES_BACKOFF_FACTOR),
                                            self.options.get("max_batched_requests", MAX_BATCHED_REQUESTS),
                                            RequestsCommon(self.opts, self.options).get_proxies())

            # Call MS Graph API to get the user profile
            response = MS_graph_helper.delete_message(email_address, mailfolders_id, messages_id)

            # If message was deleted a 204 code is returned.
            if response.status_code == 204:
                success = True
                response_json = {'value': success}
            else:
                success = False
                response_json = response.json()

            results = rp.done(success, response_json)

            yield StatusMessage(u"Returning delete results for email address: {}".format(email_address))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            LOG.error(err)
            yield FunctionError(err)
Ejemplo n.º 2
0
    def _data_feeder_sync_incidents_function(self, event, *args, **kwargs):
        """Function: Synchronize Incident(s) and their associated tasks, notes, attachments, artifacts, milestones and associated datatables"""
        try:
            # Get the wf_instance_id of the workflow this Function was called in
            wf_instance_id = event.message["workflow_instance"][
                "workflow_instance_id"]

            result = ResultPayload("data_feeder", **kwargs)

            # Get the function parameters:
            df_min_incident_id = kwargs.get("df_min_incident_id")  # number
            df_max_incident_id = kwargs.get("df_max_incident_id",
                                            df_min_incident_id)  # number
            df_query_api_method = kwargs.get("df_query_api_method",
                                             False)  # boolean

            log = logging.getLogger(__name__)
            log.info("df_min_incident_id: %s", df_min_incident_id)
            log.info("df_max_incident_id: %s", df_max_incident_id)

            if not df_max_incident_id:
                df_max_incident_id = df_min_incident_id

            if df_min_incident_id > df_max_incident_id:
                raise ValueError(
                    "Min value {} greater than max value {}".format(
                        df_min_incident_id, df_max_incident_id))

            # select all incidents as max
            if df_max_incident_id == 0:
                df_max_incident_id = sys.maxsize

            yield StatusMessage("starting...")
            rest_client_helper = RestClientHelper(self.rest_client)
            feed_outputs = build_feed_outputs(
                rest_client_helper, self.opts,
                self.options.get("feed_names", None))

            df = Reload(rest_client_helper,
                        feed_outputs,
                        query_api_method=df_query_api_method)
            reloaded_incidents = df.reload_all(min_inc_id=df_min_incident_id,
                                               max_inc_id=df_max_incident_id)

            result_payload = result.done(
                True, {"num_of_sync_incidents": reloaded_incidents})

            yield StatusMessage("done...")

            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload)
        except Exception:
            yield FunctionError()
Ejemplo n.º 3
0
    def _teams_post_message_function(self, event, *args, **kwargs):
        """Function: Post a message to a Microsoft Teams channel"""
        try:
            validate_fields(['incident_id', 'teams_channel', 'teams_payload'],
                            kwargs)

            # Get the function parameters:
            incident_id = kwargs.get("incident_id")  # number
            task_id = kwargs.get("task_id")  # number
            teams_channel = kwargs.get("teams_channel")  # text
            teams_payload = kwargs.get("teams_payload")  # text
            teams_mrkdown = kwargs.get("teams_mrkdown", False)  # boolean

            log = logging.getLogger(__name__)
            log.info("incident_id: %s", incident_id)
            log.info("task_id: %s", task_id)
            log.info("teams_channel: %s", teams_channel)
            log.info("teams_payload: %s", teams_payload)
            log.info("teams_mrkdown: %s", teams_mrkdown)

            yield StatusMessage("starting...")
            result_payload = ResultPayload(SECTION_NAME, **kwargs)

            # get the webhook for the channel
            webhook = self.options.get(teams_channel)
            if not webhook:
                raise ValueError("Unable to find channel: %s in app.config",
                                 teams_channel)

            request_common = RequestsCommon(self.opts)

            payload_json = json.loads(
                teams_payload.replace("\n", "").replace("None", "null"))

            proxies = request_common.get_proxies()
            card = pymsteams.connectorcard(
                webhook,
                http_proxy=proxies['http'] if proxies else None,
                https_proxy=proxies['https'] if proxies else None,
                http_timeout=TIMEOUT)

            self.build_conversation(card, incident_id, task_id, payload_json,
                                    teams_mrkdown)
            card.send()

            yield StatusMessage("done...")

            results = result_payload.done(True, None)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _funct_zia_remove_from_allowlist_function(self, event, *args,
                                                  **kwargs):
        """Function: Remove  URLs or IP addresses from the allowlist. See following for URL guidelines https://help.zscaler.com/zia/url-format-guidelines"""
        try:
            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # Get the wf_instance_id of the workflow this Function was called in
            wf_instance_id = event.message["workflow_instance"][
                "workflow_instance_id"]

            yield StatusMessage(
                "Starting '{0}' running in workflow '{1}'".format(
                    FN_NAME, wf_instance_id))

            # Get and validate required function inputs:
            fn_inputs = validate_fields(["zia_allowlisturls", "zia_activate"],
                                        kwargs)

            LOG.info("'{0}' inputs: %s", fn_inputs)

            yield StatusMessage(
                "Validations complete. Starting business logic")

            allowlisturls = fn_inputs.get("zia_allowlisturls")
            activate = fn_inputs.get("zia_activate")

            ziacli = ZiaClient(self.opts, self.fn_options)

            result = {
                "response":
                ziacli.allowlist_action(allowlisturls, "REMOVE_FROM_LIST")
            }

            result["activation"] = ziacli.activate(activate)

            yield StatusMessage(
                "Finished '{0}' that was running in workflow '{1}'".format(
                    FN_NAME, wf_instance_id))

            results = rp.done(True, result)

            LOG.info("'%s' complete", FN_NAME)

            yield StatusMessage(
                "Returning results for function '{}' with parameters '{}'.".
                format(
                    FN_NAME, ", ".join("{!s}={!r}".format(k, v)
                                       for (k, v) in fn_inputs.items())))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as e:
            yield FunctionError(e)
    def _exchange_online_move_message_to_folder_function(self, event, *args, **kwargs):
        """Function: This function will move an Exchange Online message to the specified folder in the users mailbox."""
        try:
            # Initialize the results payload
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Validate fields
            validate_fields(['exo_email_address', 'exo_messages_id', 'exo_destination_mailfolder_id'], kwargs)

            # Get the function parameters:
            email_address = kwargs.get("exo_email_address")  # text
            message_id = kwargs.get("exo_messages_id")  # text
            mailfolders_id = kwargs.get("exo_mailfolders_id")  # text
            destination_id = kwargs.get("exo_destination_mailfolder_id")  # text

            LOG.info(u"exo_email_address: %s", email_address)
            LOG.info(u"exo_messages_id: %s", message_id)
            LOG.info(u"exo_mailfolders_id: %s", mailfolders_id)
            LOG.info(u"exo_destination_id: %s", destination_id)

            yield StatusMessage(u"Starting move message for email address: {} to mail folder {}".format(email_address, destination_id))

            # Get the MS Graph helper class
            MS_graph_helper = MSGraphHelper(self.options.get("microsoft_graph_token_url"),
                                            self.options.get("microsoft_graph_url"),
                                            self.options.get("tenant_id"),
                                            self.options.get("client_id"),
                                            self.options.get("client_secret"),
                                            self.options.get("max_messages"),
                                            self.options.get("max_users"),
                                            RequestsCommon(self.opts, self.options).get_proxies())

            # Call MS Graph API to get the user profile
            response = MS_graph_helper.move_message(email_address, mailfolders_id, message_id, destination_id)

            # If message was deleted a 201 code is returned.
            if response.status_code == 201:
                success = True
                new_message_id = response.json().get('id')
                response_json = {'new_message_id': new_message_id}
            else:
                success = False
                response_json = response.json()

            results = rp.done(success, response_json)

            yield StatusMessage(u"Returning delete results for email address: {}".format(email_address))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            LOG.error(err)
            yield FunctionError(err)
    def _incident_utils_close_incident_function(self, event, *args, **kwargs):
        """Function: Function that takes a JSON String of field and value pairs to close an Incident."""
        try:
            # Get the function parameters:
            incident_id = kwargs.get("incident_id")  # number
            close_fields = kwargs.get("close_fields")  # text

            log = logging.getLogger(__name__)
            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # Check JSON string and convert it to dict
            if close_fields is None:
                close_fields = {}
            else:
                try:
                    close_fields = json.loads(close_fields)
                except ValueError as jerr:
                    reason = "Failure parsing 'close_fields': {}".format(str(jerr))
                    log.error(reason)
                    yield FunctionResult(rp.done(False, None, reason=reason))
                    return

            log.info("incident_id: %s", incident_id)
            log.info("close_fields: %s", close_fields)

            yield StatusMessage("starting...")
            # Instansiate new Resilient API object
            res_client = self.rest_client()

            # API call to Close an Incident
            response = close_incident(res_client, incident_id, close_fields)

            results = rp.done(True, response.json())

            yield StatusMessage("done...")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _fn_sep_add_fingerprint_list_function(self, event, *args, **kwargs):
        """Function: Add a hash to a new fingerprint list."""
        try:
            params = transform_kwargs(kwargs) if kwargs else {}

            # Instantiate result payload object
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Get the function parameters:
            sep_fingerprintlist_name = kwargs.get(
                "sep_fingerprintlist_name")  # text
            sep_description = kwargs.get("sep_description")  # text
            sep_domainid = kwargs.get("sep_domainid")  # text
            sep_hash_value = kwargs.get("sep_hash_value")  # text

            LOG.info("sep_fingerprintlist_name: %s", sep_fingerprintlist_name)
            LOG.info("sep_description: %s", sep_description)
            LOG.info("sep_domainid: %s", sep_domainid)
            LOG.info("sep_hash_value: %s", sep_hash_value)

            validate_fields([
                "sep_fingerprintlist_name", "sep_description", "sep_domainid",
                "sep_hash_value"
            ], kwargs)

            yield StatusMessage(
                "Running Symantec SEP Add Fingerprint List action ...")

            sep = Sepclient(self.options, params)

            rtn = sep.add_fingerprint_list(**params)

            if "errors" in rtn and rtn["errors"][0]["error_code"] == 409:
                # If this error was trapped user probably tried to re-add a hash to a fingerprint list.
                yield StatusMessage(
                    u"Got a 409 error while attempting to get a fingerprint list for fingerprint name '{0}' "
                    "because of a possible invalid or deleted id.".format(
                        sep_fingerprintlist_name))
            else:
                yield StatusMessage(
                    u"Returning 'Symantec SEP Add Fingerprint List' results for fingerprint name '{}'."
                    .format(sep_fingerprintlist_name))

            results = rp.done(True, rtn)

            LOG.debug(json.dumps(results["content"]))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            LOG.exception("Exception in Resilient Function for Symantec SEP.")
            yield FunctionError()
    def _exchange_online_send_message_function(self, event, *args, **kwargs):
        """Function: This function will create a message and send to the specified recipients."""
        try:
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Validate fields
            validate_fields(['exo_email_address', 'exo_recipients'], kwargs)

            # Get the function parameters:
            email_address = kwargs.get("exo_email_address")  # text
            recipients = kwargs.get("exo_recipients")  # text
            message_subject = kwargs.get("exo_message_subject")  # text
            message_body = kwargs.get("exo_message_body")  # text

            log = logging.getLogger(__name__)
            log.info(u"exo_email_address: %s", email_address)
            log.info(u"exo_recipients: %s", recipients)
            log.info(u"exo_message_subject: %s", message_subject)
            log.info(u"exo_message_body: %s", message_body)

            yield StatusMessage(u"Starting send message from email address: {}".format(email_address))

            # Get the MS Graph helper class
            MS_graph_helper = MSGraphHelper(self.options.get("microsoft_graph_token_url"),
                                            self.options.get("microsoft_graph_url"),
                                            self.options.get("tenant_id"),
                                            self.options.get("client_id"),
                                            self.options.get("client_secret"),
                                            self.options.get("max_messages"),
                                            self.options.get("max_users"),
                                            RequestsCommon(self.opts, self.options).get_proxies())

            # Call MS Graph API to send the message
            response = MS_graph_helper.send_message(email_address, recipients, message_subject, message_body)

            # If message was sent a 202 code is returned...nothing is returned in the response.
            if response.status_code == 202:
                success = True
                response_json = {'value': success}
            else:
                success = False
                response_json = response.json()

            results = rp.done(success, response_json)

            yield StatusMessage(u"Returning send mail results by email address: {}".format(email_address))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            LOG.error(err)
            yield FunctionError(err)
Ejemplo n.º 9
0
    def _secureworks_ctp_close_ticket_function(self, event, *args, **kwargs):
        """Function: Close a Secureworks CTP in an incident that has a Secureworks CTP ticket associated with it."""
        try:
            # Initialize the results payload
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Get the function parameters:
            incident_id = kwargs.get("incident_id")  # number

            log = logging.getLogger(__name__)
            log.info("incident_id: %s", incident_id)

            yield StatusMessage(u"Starting Close Secureworks CTP ticket.")

            # Get the incident
            uri = u"/incidents/{}?handle_format=names".format(incident_id)
            incident = self.rest_client().get(uri)

            if not incident:
                IntegrationError(
                    "Secureworks CTP close ticket: Incident {0} not found".
                    format(incident_id))

            # Make sure there is an SecureWorks CTP ticket associated with this incident
            ticket_id = incident.get('properties',
                                     {}).get('scwx_ctp_ticket_id', None)

            if not ticket_id:
                raise IntegrationError(
                    "Secureworks CTP close ticket: Incident {0} does not contain a ticketId"
                    .format(incident_id))

            resolution_summary = clean_html(incident.get('resolution_summary'))
            close_code = incident.get('properties',
                                      {}).get('scwx_ctp_close_code', None)

            response = self.scwx_client.post_tickets_close(
                ticket_id, resolution_summary, close_code)

            success = bool(response.get('code') == 'SUCCESS')

            results = rp.done(success, response)

            yield StatusMessage(
                u"Returning results for Close Secureworks CTP ticketId: {0} incident ID: {1}"
                .format(ticket_id, incident_id))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            log.error(err)
            yield FunctionError()
Ejemplo n.º 10
0
    def _exchange_online_get_email_user_profile_function(
            self, event, *args, **kwargs):
        """Function: This function will get Exchange Online user profile for a given email address."""
        try:
            # Initialize the results payload
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Validate fields
            validate_fields(['exo_email_address'], kwargs)

            # Get the function parameters
            email_address = kwargs.get('exo_email_address')  # text

            LOG.info(u"exo_email_address: %s", email_address)

            yield StatusMessage(
                u"Starting user profile query for email address: {}".format(
                    email_address))

            # Get the MS Graph helper class
            # Get the MS Graph helper class
            MS_graph_helper = MSGraphHelper(
                self.options.get("microsoft_graph_token_url"),
                self.options.get("microsoft_graph_url"),
                self.options.get("tenant_id"), self.options.get("client_id"),
                self.options.get("client_secret"),
                self.options.get("max_messages"),
                self.options.get("max_users"),
                RequestsCommon(self.opts, self.options).get_proxies())
            # Call MS Graph API to get the user profile
            response = MS_graph_helper.get_user_profile(email_address)

            response_json = response.json()
            results = rp.done(True, response_json)

            # Add pretty printed string for easier to read output text in note.
            pretty_string = json.dumps(response_json,
                                       ensure_ascii=False,
                                       sort_keys=True,
                                       indent=4,
                                       separators=(',', ': '))
            results['pretty_string'] = pretty_string

            yield StatusMessage(
                u"Returning user profile results for email address: {}".format(
                    email_address))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            LOG.error(err)
            yield FunctionError(err)
Ejemplo n.º 11
0
    def _fn_aws_iam_deactivate_mfa_devices_function(self, event, *args,
                                                    **kwargs):
        """Function: Deactivate an MFA device and remove it from association with the user name for which it
        was originally enabled.

        param aws_iam_user_name: An IAM user name.
        param aws_iam_mfa_serial_numbers: A comma separated list of IAM MFA serial numbers or arns.
        """
        try:
            params = transform_kwargs(kwargs) if kwargs else {}
            # Instantiate result payload object
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            aws_iam_user_name = kwargs.get("aws_iam_user_name")  # text
            aws_iam_mfa_serial_nums = kwargs.get(
                "aws_iam_mfa_serial_nums")  # text

            LOG.info("aws_iam_user_name: %s", aws_iam_user_name)
            LOG.info("aws_iam_mfa_serial_nums: %s", aws_iam_mfa_serial_nums)

            validate_fields(["aws_iam_user_name", "aws_iam_mfa_serial_nums"],
                            kwargs)

            iam_cli = AwsIamClient(self.options)
            # Delete 'MfaSerialNums' parameter from params.
            if "MfaSerialNums" in params:
                del params["MfaSerialNums"]

            rtn = []
            # Iterate over mfa serial numbers in the comma separated list in parameter
            # 'param aws_iam_mfa_serial_numbers'. Add each in turn to the 'params' dict then attempt to deactivate each
            # mfa for the user in parameter 'aws_iam_user_name'. Include the status of each attempt in the returned
            # result.
            for mfa_ser_num in re.split(r"\s*,\s*", aws_iam_mfa_serial_nums):
                params.update({"SerialNumber": mfa_ser_num})
                rtn.append({
                    "SerialNumber":
                    mfa_ser_num,
                    "Status":
                    iam_cli.post("deactivate_mfa_device", **params)
                })

            results = rp.done(True, rtn)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)

        except Exception as aws_err:
            LOG.exception(
                "ERROR with Exception '%s' in Resilient Function for AWS IAM.",
                aws_err.__repr__())
            yield FunctionError()
    def _fn_sep_scan_endpoints_function(self, event, *args, **kwargs):
        """Function: Run a Evidence of Compromise (EOC) scan on Symantec Endpoint Protection endpoints."""
        try:
            params = transform_kwargs(kwargs) if kwargs else {}

            # Instantiate result payload object.
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Get the function parameters:
            sep_group_ids = kwargs.get("sep_group_ids")  # text
            sep_computer_ids = kwargs.get("sep_computer_ids")  # text
            sep_scan_type = self.get_select_param(kwargs.get(
                "sep_scan_type"))  # select, values: "QUICK_SCAN", "FULL_SCAN"
            sep_file_name = kwargs.get("sep_file_path")  # text
            sep_sha256 = kwargs.get("sep_sha256")  # text
            sep_sha1 = kwargs.get("sep_sha1")  # text
            sep_md5 = kwargs.get("sep_md5")  # text
            sep_description = kwargs.get("sep_description")  # text
            sep_scan_action = self.get_select_param(
                kwargs.get(
                    "sep_scan_action"))  # select, values: "scan", "remediate"

            LOG.info("sep_group_ids: %s", sep_group_ids)
            LOG.info("sep_computer_ids: %s", sep_computer_ids)
            LOG.info("sep_scan_type: %s", sep_scan_type)
            LOG.info("sep_file_path: %s", sep_file_name)
            LOG.info("sep_sha256: %s", sep_sha256)
            LOG.info("sep_sha1: %s", sep_sha1)
            LOG.info("sep_md5: %s", sep_md5)
            LOG.info("sep_description: %s", sep_description)
            LOG.info("sep_scan_action: %s", sep_scan_action)

            validate_fields(["sep_scan_type", "sep_description"], kwargs)

            yield StatusMessage(
                "Running Symantec SEP Scan Endpoints command...")

            sep = Sepclient(self.options, params)

            rtn = sep.scan_endpoints(**params)

            results = rp.done(True, rtn)
            yield StatusMessage(
                "Returning 'Symantec SEP Scan Endpoints' results")

            LOG.debug(json.dumps(results["content"]))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            LOG.exception("Exception in Resilient Function for Symantec SEP.")
            yield FunctionError()
    def _mitre_technique_information_function(self, event, *args, **kwargs):
        """Function: Get ATT&CK information about MITRE ATT&CK technique"""
        try:
            # Get the function parameters:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text
            mitre_technique_mitigation_only = kwargs.get("mitre_technique_mitigation_only")  # boolean

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)
            log.info("mitre_technique_mitigation_only: %s", mitre_technique_mitigation_only)

            if not mitre_technique_name and not mitre_technique_id:
                raise ValueError("Neither name nor id is provided for getting technique information.")

            result_payload = ResultPayload("fn_mitre_integration", mitre_technique_name=mitre_technique_name,
                                           mitre_technique_id=mitre_technique_id,
                                           mitre_technique_mitigation_only=mitre_technique_mitigation_only)
            yield StatusMessage("starting...")
            yield StatusMessage("querying MITRE STIX TAXII server. It might take several minutes...")

            mitre_conn = mitre_attack.MitreAttackConnection()
            techniques = mitre_attack.MitreAttackTechnique.get(mitre_conn, name=mitre_technique_name,
                                                               id=mitre_technique_id)

            if not techniques:
                raise ValueError(
                    "Technique with name/id {}/{} can't be found".format(mitre_technique_name, mitre_technique_id))

            techs = []
            for technique in techniques:
                tactics = technique.get_tactic(mitre_conn)
                tech_dict = technique.dict_form()
                tech_dict.update(
                    {
                        "tactic": ",".join(x.name for x in tactics) if tactics else None,  # there should be 1 tactic per technique
                        "mitre_mitigations": [x.dict_form() for x in technique.get_mitigations(mitre_conn)]
                    }
                )
                techs.append(tech_dict)

            yield StatusMessage("done...")

            results = {
                "mitre_techniques": techs
            }
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            log.exception(str(e))
            yield FunctionError()
    def _wiki_lookup_function(self, event, *args, **kwargs):
        """Function: """
        try:
            validate_fields(["wiki_path"], kwargs)
            # Get the function parameters:
            wiki_path = kwargs.get("wiki_path")  # text
            wiki_search_term = kwargs.get("wiki_search_term")  # text

            log = logging.getLogger(__name__)
            log.info("wiki_path: %s", wiki_path)
            log.info(u"wiki_search_term: %s", wiki_search_term)

            # Setup Resilient rest client
            helper = WikiHelper(self.rest_client())
            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # separate the target wiki from it's parent path
            wiki_list = wiki_path.strip().split("/")
            wiki_title = wiki_list.pop()

            reason = matching_wiki_content = None

            content = helper.get_wiki_contents(wiki_title, wiki_list)

            if not content:
                reason = u"Can't find the wiki with path: '{}'".format(
                    wiki_path)
                yield StatusMessage(reason)
            else:
                log.debug(content)

                matching_wiki_content = do_lookup(wiki_search_term, content)

                # Handle no matches
                if not matching_wiki_content:
                    reason = u"No matches found for {} in the Wiki {}".format(
                        wiki_search_term, wiki_title)
                    yield StatusMessage(reason)

                yield StatusMessage("Found {} matching entries".format(
                    len(matching_wiki_content)))

            results = rp.done(not bool(reason),
                              matching_wiki_content,
                              reason=reason)
            # add the title of the wiki page
            results['title'] = content.get('title') if content else None

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _mitre_groups_using_technique_function(self, event, *args, **kwargs):
        """Function: Get a list of groups that are using the given technique(s)."""
        try:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)

            result_payload = ResultPayload(
                "fn_mitre_integration",
                mitre_technique_name=mitre_technique_name,
                mitre_technique_id=mitre_technique_id)

            if not mitre_technique_id and not mitre_technique_name:
                raise ValueError(
                    "At least one of the inputs(mitre_technique_name or mitre_technique_id) "
                    "should be provided.")

            yield StatusMessage("Getting technique information...")

            mitre_conn = mitre_attack.MitreAttackConnection()

            techniques = mitre_attack_utils.get_multiple_techniques(
                mitre_conn,
                mitre_technique_ids=mitre_technique_id,
                mitre_technique_names=mitre_technique_name)

            yield StatusMessage("Getting group information...")
            groups = []
            for technique in techniques:
                groups.extend(
                    mitre_attack.MitreAttackGroup.get_by_technique(
                        mitre_conn, technique))

            if len(groups) == 0:
                yield StatusMessage(
                    "No groups were found using any of the given techniques. Done."
                )
            else:
                yield StatusMessage("Done. Returning results.")

            groups = [x.dict_form()
                      for x in groups]  # prepare the data for viewing

            results = {"mitre_groups": groups}
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            log.exception(str(e))
            yield FunctionError()
    def _have_i_been_pwned_get_pastes_function(self, event, *args, **kwargs):
        """Function: Get all pastes of an email account from Have I Been Pwned."""
        try:
            yield StatusMessage("starting...")

            HAVE_I_BEEN_PWNED_PASTES_URL = "https://haveibeenpwned.com/api/v3/pasteaccount/"
            result_payload = ResultPayload("hibp", **kwargs)

            # Get the function parameters:
            email_address = kwargs.get("email_address")  # text

            log = logging.getLogger(__name__)
            if email_address is not None:
                log.info("email_address: %s", email_address)
            else:
                raise ValueError("email_address is required to run this function")

            hibp_api_key = self.get_config_option("hibp_api_key")

            headers={
                        'User-Agent': 'Resilient HIBP/2.0',
                        'hibp-api-key': hibp_api_key
                    }

            breach_url = "{0}{1}".format(HAVE_I_BEEN_PWNED_PASTES_URL, email_address)
            pastes_response = requests.get(breach_url, headers=headers,proxies=self.PROXIES)

            pastes = None
            # Good response
            if pastes_response.status_code == 200:
                pastes = pastes_response.json()
            # 404 is returned when an email was not found
            elif pastes_response.status_code == 404:
                yield StatusMessage("No pastes found on email address: {}".format(email_address))
                pastes = None
            # Rate limit was hit, wait 2 seconds and try again
            elif pastes_response.status_code == 429:
                time.sleep(2)
            else:
                log.warn("Have I Been Pwned returned " + str(pastes_response.status_code) + " unexpected status code")
                yield FunctionError("Have I Been Pwned returned " + str(pastes_response.status_code) + " status code")

            results = {
                "Pastes": pastes
            }

            yield StatusMessage("Lookup complete")
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            yield FunctionError(e)
Ejemplo n.º 17
0
    def _icdx_get_archive_list_function(self, event, *args, **kwargs):
        """Function: The Get Archive List API is used to return a list of archives in the ICDx system. The response is an unsorted list of archive metadata objects which can then be searched by a user."""

        log = logging.getLogger(__name__)
        try:
            rc = ResultPayload(ICDX_SECTION, **kwargs)

            helper = ICDXHelper(self.options)
            yield StatusMessage(
                "Attempting to gather config and setup the AMQP Client")
            try:
                # Initialise the AmqpFacade, pass in config values
                amqp_client = AmqpFacade(
                    host=helper.get_config_option("icdx_amqp_host"),
                    port=helper.get_config_option("icdx_amqp_port", True),
                    virtual_host=helper.get_config_option("icdx_amqp_vhost"),
                    username=helper.get_config_option("icdx_amqp_username"),
                    amqp_password=helper.get_config_option(
                        "icdx_amqp_password"))

                yield StatusMessage(
                    "Config options gathered and AMQP client setup.")
            except Exception:
                raise FunctionError(
                    "Encountered error while initialising the AMQP Client")
            # Prepare request payload
            request = {"id": GET_ARCHIVE_LIST_CODE}

            # Make the call to ICDx and get a handle on any results
            archives, status = amqp_client.call(json.dumps(request))

            yield StatusMessage(
                "ICDX call complete with status: {}".format(status))

            # If status code in the message header is 200 we have results, 204 is empty response.
            results = rc.done(
                success=False if status != 200 else True,
                content={
                    "archives":
                    (json.loads(archives) if archives is not None else None)
                })
            results.update({
                "archives":
                (json.loads(archives) if archives is not None else None)
            })

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
            log.info("Complete")
        except Exception:
            yield FunctionError()
    def _exchange_online_get_message_function(self, event, *args, **kwargs):
        """Function: This function returns the contents of an Exchange Online message."""
        try:
            # Initialize the results payload
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Validate fields
            validate_fields(['exo_email_address', 'exo_messages_id'], kwargs)

            # Get the function parameters:
            email_address = kwargs.get("exo_email_address")  # text
            message_id = kwargs.get("exo_messages_id")  # text

            LOG.info(u"exo_email_address: %s", email_address)
            LOG.info(u"exo_messages_id: %s", message_id)

            yield StatusMessage(u"Starting get message for email address: {}".format(email_address))

            # Get the MS Graph helper class
            MS_graph_helper = MSGraphHelper(self.options.get("microsoft_graph_token_url"),
                                            self.options.get("microsoft_graph_url"),
                                            self.options.get("tenant_id"),
                                            self.options.get("client_id"),
                                            self.options.get("client_secret"),
                                            self.options.get("max_messages"),
                                            self.options.get("max_users"),
                                            self.options.get("max_retries_total", MAX_RETRIES_TOTAL),
                                            self.options.get("max_retries_backoff_factor", MAX_RETRIES_BACKOFF_FACTOR),
                                            self.options.get("max_batched_requests", MAX_BATCHED_REQUESTS),
                                            RequestsCommon(self.opts, self.options).get_proxies())

            # Call MS Graph API to get the user profile
            response = MS_graph_helper.get_message(email_address, message_id)

            response_json = response.json()
            results = rp.done(True, response_json)

            # Add pretty printed string for easier to read output text in note.
            pretty_string = json.dumps(response_json, ensure_ascii=False, sort_keys=True, indent=4,
                                       separators=(',', ': '))
            results['pretty_string'] = pretty_string

            yield StatusMessage(u"Returning results for get message for email address: {}".format(email_address))

            LOG.debug(json.dumps(pretty_string))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as err:
            LOG.error(err)
            yield FunctionError(err)
Ejemplo n.º 19
0
    def _sentinel_get_incident_entities_function(self, event, *args, **kwargs):
        """Function: Get the Entities associated with a Sentinel Incident"""
        try:
            validate_fields(["sentinel_profile", "sentinel_incident_id"],
                            kwargs)

            yield StatusMessage("Starting 'sentinel_get_incident_entities'")

            rc = ResultPayload(PACKAGE_NAME, **kwargs)

            # Get the function parameters:
            sentinel_incident_id = kwargs.get("sentinel_incident_id")  # text
            sentinel_profile = kwargs.get("sentinel_profile")  # text

            log = logging.getLogger(__name__)
            log.info("sentinel_incident_id: %s", sentinel_incident_id)
            log.info("sentinel_profile: %s", sentinel_profile)

            sentinel_api = SentinelAPI(self.options['tenant_id'],
                                       self.options['client_id'],
                                       self.options['app_secret'], self.opts,
                                       self.options)

            profile_data = self.sentinel_profiles.get_profile(sentinel_profile)
            # read all entities associated with a Sentinel incident
            result, status, reason = sentinel_api.get_incident_entities(
                profile_data, sentinel_incident_id)

            log.debug(result)
            # iterate over the alerts and get all the entities
            entities = {}
            if status:
                for alert in result['value']:
                    log.debug("Alert: %s", alert['name'])
                    entity_result, entity_status, entity_reason = \
                        sentinel_api.get_incident_alert_entities(alert['properties']['relatedResourceId'])
                    # organize entities using the key of the alert_id
                    if entity_status:
                        entities[
                            alert['name']] = entity_result['value']['entities']
                    else:
                        reason = entity_reason

            yield StatusMessage("Finished 'sentinel_get_incident_entities'")

            results = rc.done(status, entities, reason=reason)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _fn_ansible_function(self, event, *args, **kwargs):
        """Function: Ansible is simple IT engine for automation, it is designed for manage many systems, rather than just one at a time."""
        try:
            # Get the function parameters:
            ansible_playbook = kwargs.get("ansible_playbook_name")  # text
            ansible_parameters = kwargs.get("ansible_parameters")  # text

            log = logging.getLogger(__name__)
            log.info(u"playbook_name: %s", ansible_playbook)
            log.info(u"ansible_parameters: %s", ansible_parameters)

            # use the workflow_id to identify the ansible process
            workflow_id = event.message['workflow_instance'][
                'workflow_instance_id']

            result = ResultPayload(SECTION_HDR, **kwargs)

            # Prepare playbook vars
            extra_vars = {}
            if ansible_parameters:
                for item in ansible_parameters.split(u";"):
                    if len(item.strip(u' ')) > 0:
                        k, v = item.split(u"=")
                        extra_vars[k.strip(u' ')] = v.strip(u' ')

            # prepare playbook arg
            playbook_extension = ansible_playbook.split(u".")[-1]
            if playbook_extension != "yml":
                ansible_playbook = u"{}.yml".format(
                    ansible_playbook.strip(u' '))

            playbook_results = run_playbook(id=workflow_id,
                                            private_data_dir=self.runner_dir,
                                            artifact_dir=self.artifact_dir,
                                            playbook_name=ansible_playbook,
                                            playbook_args=extra_vars)

            result_payload = result.done(True, playbook_results)

            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload)
        except Exception:
            yield FunctionError()
        finally:
            log.info(
                "Running cleanup_artifact_dir for {} previous runs".format(
                    self.artifact_rentention_num))
            cleanup_artifact_dir(
                self.artifact_dir if self.artifact_dir else self.runner_dir,
                self.artifact_rentention_num)
Ejemplo n.º 21
0
    def _remove_a_scheduled_job(self, event, *args, **kwargs):
        try:
            scheduler_label = kwargs.get("scheduler_label")  # text
            log.info(u"scheduler_label: %s", scheduler_label)
            validate_fields(["scheduler_label"], kwargs)

            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            scheduler = ResilientScheduler.get_scheduler()

            try:
                scheduler.remove_job(scheduler_label)
                log.info(u"Rule '{}' deleted".format(scheduler_label))

                yield StatusMessage("Scheduled rule removed")
                result = rc.done(True, None)
            except JobLookupError:
                yield StatusMessage("Scheduled rule not found")
                result = rc.done(False, None)

            yield FunctionResult(result)
        except Exception:
            yield FunctionError()
Ejemplo n.º 22
0
    def _qradar_reference_table_update_item_function(self, event, *args, **kwargs):
        """Function: Update an item in a given QRadar reference table"""
        try:

            # Get the wf_instance_id of the workflow this Function was called in, if not found return a backup string
            wf_instance_id = event.message.get("workflow_instance", {}).get("workflow_instance_id", "no instance id found")

            yield StatusMessage("Starting 'qradar_reference_table_update_item' running in workflow '{0}'".format(wf_instance_id))

            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # Get the function parameters:
            qradar_reference_table_name = kwargs.get("qradar_reference_table_name")  # text
            qradar_reference_table_item_value = kwargs.get("qradar_reference_table_item_value")  # text
            qradar_reference_table_item_inner_key = kwargs.get("qradar_reference_table_item_inner_key")  # text
            qradar_reference_table_item_outer_key = kwargs.get("qradar_reference_table_item_outer_key")  # text

            LOG.info("qradar_reference_table_name: %s", qradar_reference_table_name)
            LOG.info("qradar_reference_table_item_value: %s", qradar_reference_table_item_value)
            LOG.info("qradar_reference_table_item_inner_key: %s", qradar_reference_table_item_inner_key)
            LOG.info("qradar_reference_table_item_outer_key: %s", qradar_reference_table_item_outer_key)

            qradar_verify_cert = True
            if "verify_cert" in self.options and self.options["verify_cert"].lower() == "false":
                qradar_verify_cert = False

            LOG.debug("Connecting to QRadar instance @ {}".format(self.options["host"]))

            qradar_client = QRadarClient(host=self.options["host"],
                                         username=self.options.get("username", None),
                                         password=self.options.get("qradarpassword", None),
                                         token=self.options.get("qradartoken", None),
                                         cafile=qradar_verify_cert,
                                         opts=self.opts, function_opts=self.options)

            result = qradar_client.update_ref_table_element(qradar_reference_table_name, qradar_reference_table_item_inner_key, qradar_reference_table_item_outer_key, qradar_reference_table_item_value)
            
            status_code = bool(result.get('status_code', False) < 300)
            reason = None if status_code else result['content'].get('message', None)
            results = rp.done(success=status_code,
                              content=result,
                              reason=reason)

            yield StatusMessage("Call made to QRadar and response code returned: {}".format(result.get('status_code', 'no response code found')))
            yield StatusMessage("Finished 'qradar_reference_table_update_item' that was running in workflow '{0}'".format(wf_instance_id))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Ejemplo n.º 23
0
    def _fn_api_void_request_function(self, event, *args, **kwargs):
        """Function: Use the APIVoid API to make an APIVoid API request.  Results are written to an incident note."""
        try:
            yield StatusMessage("APIVoid API request function started...")
            log = logging.getLogger(__name__)
            rp = ResultPayload("fn_api_void", **kwargs)

            # Add support for Requests Common
            rc = RequestsCommon(self.opts, self.options)

            # Get app.config parameters
            apivoid_base_url = self.options.get("apivoid_base_url")
            apivoid_sub_url = self.options.get("apivoid_sub_url")
            apivoid_api_key = self.options.get("apivoid_api_key")

            # Get the function parameters:
            validate_fields([
                "api_void_request_type", "api_void_artifact_type",
                "api_void_artifact_value"
            ], kwargs)
            api_void_request_type = self.get_select_param(
                kwargs.get("api_void_request_type"))  # select
            api_void_artifact_type = kwargs.get(
                "api_void_artifact_type")  # text
            api_void_artifact_value = kwargs.get(
                "api_void_artifact_value")  # text

            log.info("api_void_artifact_value: %s", api_void_artifact_value)

            yield StatusMessage(u"Getting Intelligence for {0}: {1}".format(
                api_void_artifact_type, api_void_artifact_value))

            # Execute APIVoid API call
            response = make_apivoid_api_call(base_url=apivoid_base_url,
                                             sub_url=apivoid_sub_url,
                                             query_type=api_void_request_type,
                                             value=api_void_artifact_value,
                                             api_key=apivoid_api_key,
                                             rc=rc)

            response_json = response.json()

            yield StatusMessage(
                "APIVoid request function completed successfully...")
            results = rp.done(True, response_json)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as e:
            yield FunctionError(e)
Ejemplo n.º 24
0
    def _fn_sep_assign_fingerprint_list_to_group_function(
            self, event, *args, **kwargs):
        """Function: Assign a fingerprint list to a group for lock-down."""
        try:
            params = transform_kwargs(kwargs) if kwargs else {}

            # Instantiate result payload object
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            # Get the function parameters:
            sep_fingerprintlist_id = kwargs.get(
                "sep_fingerprintlist_id")  # text
            sep_groupid = kwargs.get("sep_groupid")  # text

            LOG.info("sep_fingerprintlist_id: %s", sep_fingerprintlist_id)
            LOG.info("sep_groupid: %s", sep_groupid)

            validate_fields(["sep_fingerprintlist_id", "sep_groupid"], kwargs)

            yield StatusMessage(
                "Running Symantec SEP Assign Fingerprint List to Group for Lock-down action ..."
            )

            sep = Sepclient(self.options, params)

            rtn = sep.assign_fingerprint_list_to_group(**params)

            results = rp.done(True, rtn)

            if "errorCode" in rtn and int(rtn["errorCode"]) == 400:
                # If this error was trapped user probably tried to get an invalid fingerprint list.
                yield StatusMessage(
                    "Symantec SEP Assign Fingerprint List to Group for Lock-down: Got a 400 error "
                    "while attempting to assign a fingerprint list for fingerprint id '{0}' because of a "
                    "possible invalid or deleted fingerprintlist id.".format(
                        sep_fingerprintlist_id))
            else:
                yield StatusMessage(
                    "Returning 'Symantec SEP Assign Fingerprint List to Group for Lock-down' results for "
                    "fingerprintlist_id '{0}' and groupid '{1}'".format(
                        sep_fingerprintlist_id, sep_groupid))

            LOG.debug(json.dumps(results["content"]))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            LOG.exception("Exception in Resilient Function for Symantec SEP.")
            yield FunctionError()
    def _func_aws_guardduty_archive_finding_function(self, event, *args,
                                                     **kwargs):
        """Function: Archive an AWS GuardDuty finding.

        :param aws_gd_finding_id: An AWS GuardDuty finding ID.
        :param aws_gd_detector_id: An AWS GuardDuty detector ID.
        :param aws_gd_region: An AWS GuardDuty region ID.
        """
        try:

            # Get the wf_instance_id of the workflow this Function was called in
            wf_instance_id = event.message["workflow_instance"][
                "workflow_instance_id"]

            yield StatusMessage(
                "Starting 'func_aws_guardduty_archive_finding' running in workflow '{0}'"
                .format(wf_instance_id))

            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # Get the function parameters:
            aws_gd_region = kwargs.get("aws_gd_region")  # text
            aws_gd_finding_id = kwargs.get("aws_gd_finding_id")  # text
            aws_gd_detector_id = kwargs.get("aws_gd_detector_id")  # text

            validate_fields(REQUIRED_FIELDS, kwargs)

            log = logging.getLogger(__name__)
            log.info("aws_gd_region: %s", aws_gd_region)
            log.info("aws_gd_finding_id: %s", aws_gd_finding_id)
            log.info("aws_gd_detector_id: %s", aws_gd_detector_id)

            # Instantiate AWS GuardDuty client object.
            aws_gd = AwsGdClient(self.opts, self.options, region=aws_gd_region)

            result = aws_gd.post("archive_findings",
                                 DetectorId=aws_gd_detector_id,
                                 FindingIds=[aws_gd_finding_id])

            results = rp.done(True, result)

            yield StatusMessage(
                "Finished 'func_aws_guardduty_archive_finding' that was running in workflow '{0}'"
                .format(wf_instance_id))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Ejemplo n.º 26
0
    def _fn_aws_iam_delete_ssh_keys_function(self, event, *args, **kwargs):
        """Function: Delete Secure Shell (SSH) public keys associated with the specified IAM user.

        param aws_iam_user_name: An IAM user name.
        aws_iam_ssh_key_ids: A comma separated list of SSH key ids credential ids.
        """
        try:
            params = transform_kwargs(kwargs) if kwargs else {}
            # Instantiate result payload object
            rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs)

            aws_iam_user_name = kwargs.get("aws_iam_user_name")  # text
            aws_iam_ssh_key_ids = kwargs.get("aws_iam_ssh_key_ids")  # text

            LOG.info("aws_iam_user_name: %s", aws_iam_user_name)
            LOG.info("aws_iam_ssh_key_ids: %s", aws_iam_ssh_key_ids)

            validate_fields(["aws_iam_user_name", "aws_iam_ssh_key_ids"],
                            kwargs)

            iam_cli = AwsIamClient(self.options)

            # Delete 'SshKeyIds' parameter from params.
            if "SshKeyIds" in params:
                del params["SshKeyIds"]

            rtn = []
            # Iterate over SSH public key ids in the comma separated list in parameter 'aws_iam_ssh_key_ids'.
            # Add each in turn to the 'params' dict then attempt to delete each key for the user in parameter
            # 'aws_iam_user_name'. Include the status of each attempt in the returned result.
            for ssh_key_id in re.split(r"\s*,\s*", aws_iam_ssh_key_ids):
                params.update({"SSHPublicKeyId": ssh_key_id})
                rtn.append({
                    "SSHPublicKeyId":
                    ssh_key_id,
                    "Status":
                    iam_cli.post("delete_ssh_public_key", **params)
                })

            results = rp.done(True, rtn)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)

        except Exception as aws_err:
            LOG.exception(
                "ERROR with Exception '%s' in Resilient Function for AWS IAM.",
                aws_err.__repr__())
            yield FunctionError()
    def _ansible_tower_list_job_templates_function(self, event, *args, **kwargs):
        """Function: Run an ansible module outside of the job template"""
        try:
            validate_fields(("url"), self.options) # validate key app.config settings

            # Get the function parameters:
            tower_hosts = kwargs.get("tower_hosts")  # text
            tower_module = self.get_select_param(kwargs.get("tower_module"))  # text
            tower_arguments = kwargs.get("tower_arguments")  # text
            tower_inventory = kwargs.get("tower_inventory") # number
            tower_credential = kwargs.get("tower_credential") # number

            log = logging.getLogger(__name__)
            log.info("tower_hosts: %s", tower_hosts)
            log.info("tower_module: %s", tower_module)
            log.info("tower_arguments: %s", tower_arguments)
            log.info("tower_inventory: %s", tower_inventory)
            log.info("tower_credential: %s", tower_credential)

            result = ResultPayload(SECTION_HDR, **kwargs)
            rc = RequestsCommon(self.opts, self.options)

            # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE
            yield StatusMessage("starting...")

            url = "/".join((clean_url(self.options['url']), TOWER_API_BASE, AD_HOC_URL))
            # common
            basic_auth, cafile = get_common_request_items(self.options)

            arguments = {
                "module_name": tower_module,
                "limit": tower_hosts,
                "module_args": tower_arguments,
                "inventory": tower_inventory,
                "credential": tower_credential
            }

            rc = RequestsCommon(self.opts, self.options)
            results = rc.execute_call_v2("post", url, auth=basic_auth,
                                         json=arguments, headers=JSON_HEADERS,
                                         verify=cafile)

            result_payload = result.done(True, results.json())
            yield StatusMessage("done...")

            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload)
        except Exception:
            yield FunctionError()
Ejemplo n.º 28
0
    def _netwitness_query_function(self, event, *args, **kwargs):
        """Function: Queries NetWitness and returns back a list of session \
            IDs based on the provided query"""
        try:
            yield StatusMessage("Querying NetWitness...")
            # Get the function parameters:
            nw_query = self.get_textarea_param(
                kwargs.get("nw_query"))  # textarea
            nw_results_size = str(kwargs.get("nw_results_size", ''))  # number

            # Fail if query is not set
            if len(nw_query) < 1:
                raise FunctionError(
                    "nw_query must be set in order to run this function.")

            # Initialize resilient_lib objects
            results_payload = ResultPayload("fn_rsa_netwitness", **{"nw_query": nw_query, \
                "nw_results_size": nw_results_size})
            req_common = RequestsCommon(self.opts)

            log.info("nw_query: %s", nw_query)
            log.info("nw_results_size: %s", nw_results_size)

            # Query Netwitness
            nw_query_results = query_netwitness(
                self.options.get("nw_packet_server_url"),
                self.options.get("nw_packet_server_user"),
                self.options.get("nw_packet_server_password"),
                self.options.get("nw_packet_server_verify"),
                query=nw_query,
                req_common=req_common,
                size=nw_results_size)

            log.debug(nw_query_results)

            if nw_query_results:
                StatusMessage("Query results found")
            else:
                StatusMessage("No query results found")
            yield StatusMessage("Complete...")

            results = results_payload.done(True, \
                nw_query_results.json() if nw_query_results else None)
            log.debug("RESULTS: %s", results)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as error:
            yield FunctionError(error)
    def _fn_get_wiki_contents_function(self, event, *args, **kwargs):
        """Function: None"""
        try:
            validate_fields(["wiki_path"], kwargs)
            # Get the wf_instance_id of the workflow this Function was called in
            #wf_instance_id = event.message["workflow_instance"]["workflow_instance_id"]
            #yield StatusMessage("Starting 'fn_get_wiki_contents' running in workflow '{0}'".format(wf_instance_id))

            # Get the function parameters:
            wiki_contents_as_json = str_to_bool(
                kwargs.get("wiki_contents_as_json", "False"))  # boolean
            wiki_path = kwargs.get("wiki_path")  # text

            log = logging.getLogger(__name__)
            log.info("wiki_contents_as_json: %s", wiki_contents_as_json)
            log.info(u"wiki_path: %s", wiki_path)

            ##############################################
            # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE #
            ##############################################
            rp = ResultPayload(PACKAGE_NAME, **kwargs)
            helper = WikiHelper(self.rest_client())

            # separate the target wiki from it's parent path
            wiki_list = wiki_path.strip().split("/")
            wiki_title = wiki_list.pop()

            # find the wiki page
            content = helper.get_wiki_contents(wiki_title, wiki_list)
            log.debug(content)

            content_text = reason = None
            if content:
                content_text = content['text']
                if wiki_contents_as_json:
                    content['json'] = json.loads(content_text.replace(
                        '\n', ''))
            else:
                reason = u"Unable to find wiki by path: {}".format(wiki_path)
                yield StatusMessage(reason)

            results = rp.done(not bool(reason), content, reason=reason)
            # add the title of the wiki page
            results['title'] = content.get('title') if content else None

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _funct_zia_get_blocklist_function(self, event, *args, **kwargs):
        """Function: Get a list of block-listed URLs.
        """
        try:
            rp = ResultPayload(PACKAGE_NAME, **kwargs)

            # Get the wf_instance_id of the workflow this Function was called in
            wf_instance_id = event.message["workflow_instance"][
                "workflow_instance_id"]

            yield StatusMessage(
                "Starting '{0}' running in workflow '{1}'".format(
                    FN_NAME, wf_instance_id))

            # Get and validate required function inputs:
            fn_inputs = validate_fields([], kwargs)

            LOG.info("'{0}' inputs: %s", fn_inputs)

            url_filter_patt = fn_inputs.get("zia_url_filter")
            if url_filter_patt and not is_regex(url_filter_patt):
                raise ValueError(
                    "The url query filter '{}' does not have a valid regular expression."
                    .format("zia_url_filter"))

            yield StatusMessage(
                "Validations complete. Starting business logic")

            ziacli = ZiaClient(self.opts, self.fn_options)
            result = ziacli.get_blocklist_urls(url_filter=url_filter_patt)

            yield StatusMessage(
                "Finished '{0}' that was running in workflow '{1}'".format(
                    FN_NAME, wf_instance_id))

            results = rp.done(True, result)

            LOG.info("'%s' complete", FN_NAME)

            yield StatusMessage(
                "Returning results for function '{}' with parameters '{}'.".
                format(
                    FN_NAME, ", ".join("{!s}={!r}".format(k, v)
                                       for (k, v) in fn_inputs.items())))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception as e:
            yield FunctionError(e)