def execute_call(self, url, depth=1):
        """
        make call to HIBP, returning the results
        :param url:
        :param depth: recursion count
        :return: json returns
        """
        response = requests.get(url,
                                headers=self.make_headers(),
                                proxies=self.get_proxies())

        results = None
        # Good response
        if response.status_code == 200:
            results = response.json()
        # 404 is returned when an email was not found
        elif response.status_code == 404:
            pass
        # Rate limit was hit, wait 2 seconds and try again
        elif response.status_code == 429:
            if depth == 1:
                time.sleep(SLEEP_SECS)
                return self.execute_call(url, depth + 1)

            raise IntegrationError("Rate limit exceeded")
        else:
            raise IntegrationError(
                "Have I Been Pwned returned {} unexpected status code".format(
                    response.status_code))

        return results
    def __init__(self, opts, rest_client_helper):
        """
        configure the rest_client for the destination resilient
        :param opts: used for Resilient target
        :param rest_client_helper: used for Resilient source
        """
        self.opts = opts

        # rest_client_helper is None for destination Resilient org
        try:
            if rest_client_helper:
                self.rest_client = rest_client_helper.rest_client(
                )  # source resilient
            else:
                self.rest_client = resilient.get_client(
                    self.opts)  # target resilient
        except Exception as err:
            raise IntegrationError(str(err))

        # get the class to maintain the reference map: either datatable or sqlite
        # only needed for target Resilient
        if not rest_client_helper:
            self.dbsync = DBSyncFactory.get_dbsync(
                self.rest_client.org_id, self.opts.get("sqlite_sync_file",
                                                       None),
                self.opts.get("postgresql_connect", None),
                self.opts.get("postgresql_uid", None),
                self.opts.get("postgresql_pwd", None))
            if not self.dbsync:
                raise IntegrationError("Unable to create DBSync object")
示例#3
0
    def _misp_create_tag_function(self, event, *args, **kwargs):
        """Function: Creates a Tag"""
        try:

            # Get the function parameters:
            misp_tag_type = self.get_select_param(kwargs.get(
                "misp_tag_type"))  # select, values: "Event", "Attribute"
            misp_tag_name = kwargs.get("misp_tag_name")  # text
            misp_attribute_value = kwargs.get("misp_attribute_value")  # text
            misp_event_id = kwargs.get("misp_event_id")  # number

            # ensure misp_event_id is an integer so we can get an event by it's index
            if not isinstance(misp_event_id, int):
                raise IntegrationError(
                    u"Unexpected input type for MISP Event ID. Expected and integer, received {}"
                    .format(type(misp_event_id)))

            API_KEY, URL, VERIFY_CERT = common.validate(self.options)

            log = logging.getLogger(__name__)
            log.info("misp_tag_type: %s", misp_tag_type)
            log.info("misp_tag_name: %s", misp_tag_name)
            log.info("misp_attribute_value: %s", misp_attribute_value)
            log.info("misp_event_id: %s", misp_event_id)

            if sys.version_info.major < 3:
                raise FunctionError(
                    "Tagging is only supported when using Python 3")

            yield StatusMessage("Setting up connection to MISP")

            proxies = common.get_proxies(self.opts, self.options)

            misp_client = misp_helper.get_misp_client(URL,
                                                      API_KEY,
                                                      VERIFY_CERT,
                                                      proxies=proxies)

            yield StatusMessage(u"Tagging {} with {}".format(
                misp_tag_type, misp_tag_name))

            tag_result = misp_helper.create_tag(misp_client,
                                                misp_attribute_value,
                                                misp_tag_type, misp_tag_name,
                                                misp_event_id)
            if 'errors' in tag_result:
                raise IntegrationError(u"Unable to save the tag. {}".format(
                    tag_result['errors'][1]['errors']))

            log.debug(tag_result)

            yield StatusMessage("Tag has been created")

            response_results = {"success": True}

            # Produce a FunctionResult with the results
            yield FunctionResult(response_results)
        except Exception:
            yield FunctionError()
示例#4
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()
def artifact_to_network_object(artifact_type, artifact_value, netmask,
                               range_end_ip, fqdn_version):
    """ Given an artifact type and value, return the Cisco ASA network object kind and value.
    """
    if artifact_type == "DNS Name":
        network_object_kind = fqdn_version
        network_object_value = artifact_value
    elif artifact_type == "IP Address":
        if netmask:
            network_object_kind, network_object_value = compute_ip_with_netmask(
                "IPv4Network", artifact_value, netmask)
        elif range_end_ip:
            network_object_kind = "IPv4Range"
            network_object_value = compute_ip_with_range(
                "IPv4Address", artifact_value, range_end_ip)
        else:
            network_object_kind = "IPv4Address"
            network_object_value = artifact_value
    elif artifact_type == "String":
        if is_valid_ipv4_addr(artifact_value):
            if netmask:
                network_object_kind, network_object_value = compute_ip_with_netmask(
                    "IPv4Network", artifact_value, netmask)
            elif range_end_ip:
                network_object_kind = "IPv4Range"
                network_object_value = compute_ip_with_range(
                    "IPv4Address", artifact_value, range_end_ip)
            else:
                network_object_kind = "IPv4Address"
                network_object_value = artifact_value
        elif is_valid_ipv6_addr(artifact_value):
            if netmask:
                network_object_kind, network_object_value = compute_ip_with_netmask(
                    "IPv6Network", artifact_value, netmask)
            elif range_end_ip:
                network_object_kind = "IPv6Range"
                network_object_value = compute_ip_with_range(
                    "IPv6Address", artifact_value, range_end_ip)
            else:
                network_object_kind = "IPv6Address"
                network_object_value = artifact_value
        else:
            raise IntegrationError(
                "Unknown artifact type to convert to network object.")
    else:
        raise IntegrationError(
            "Unknown artifact type to convert to network object.")

    return network_object_kind, network_object_value
def get_jira_client(app_configs, rc):
    """
    Function that gets the client for JIRA

    :param app_configs: The app_configs for fn_jira
    :param rc: resilient_lib.RequestsCommon object used to get proxies
    :raise: IntegrationError if auth_method set in app.config is unsupported
    :return: Instance to jira client
    :rtype: JIRA object. See: https://jira.readthedocs.io/en/latest/api.html 
    """
    auth_method = app_configs.get("auth_method", SUPPORTED_AUTH_METHODS[0])
    server = app_configs.get("url")
    verify = app_configs.get("verify_cert")
    proxies = rc.get_proxies()

    try:
        timeout = int(app_configs.get("timeout", 10))
    except ValueError:
        raise IntegrationError(
            "Ensure 'timeout' is an integer in your config file")

    # AUTH
    if auth_method == SUPPORTED_AUTH_METHODS[0]:
        return JIRA(
            auth=(app_configs.get("user"), app_configs.get("password")),
            options={
                "server": server,
                "verify": verify
            },
            proxies=proxies,
            timeout=timeout,
        )

    # BASIC
    elif auth_method == SUPPORTED_AUTH_METHODS[1]:
        return JIRA(
            basic_auth=(app_configs.get("user"), app_configs.get("password")),
            options={
                "server": server,
                "verify": verify
            },
            proxies=proxies,
            timeout=timeout,
        )

    else:
        raise IntegrationError(
            "{0} auth_method is not supported. Supported methods: {1}".format(
                auth_method, SUPPORTED_AUTH_METHODS))
    def _escalate(self):
        """ Search for Secureworks CTP tickets and create incidents in Resilient for them
        :return:
        """
        LOG.info(u"Secureworks CTP escalate.")
        try:
            # Call Secureworks endpoint for each ticketType groupingType combination the user has
            # specified in the app.config
            for query in self.scwx_client.query_types:

                # Get list of tickets needing updating
                ticket_type = query.get('ticketType')
                grouping_type = query.get('groupingType')
                response = self.scwx_client.post_tickets_updates(
                    ticket_type, grouping_type)

                tickets = response.get('tickets')
                ticket_id_list = [ticket.get('ticketId') for ticket in tickets]
                message = u"Secureworks CTP tickets to be processed this poll:\nticketType: {0} groupingType: {1}".format(
                    ticket_type, grouping_type)
                LOG.info(message)
                LOG.info(u"ticket list: %s", ticket_id_list)

                for ticket in tickets:
                    code = self.process_ticket(ticket)

        except Exception as err:
            raise IntegrationError(err)
        finally:
            # We always want to reset the timer to wake up, no matter failure or success
            self.fire(PollCompleted())
示例#8
0
def selftest_function(opts):
    """
    Placeholder for selftest function. An example use would be to test package api connectivity.
    Suggested return values are be unimplemented, success, or failure.
    """

    app_configs = opts.get(CONFIG_DATA_SECTION, {})
    rc = RequestsCommon(opts, app_configs)

    try:
        # Get and validate app configs
        valid_app_configs = validate_fields(["url"], app_configs)

        # Execute api call
        res = make_api_call(call_type="lookup",
                            base_url=valid_app_configs.get("url"),
                            artifact_type="URL",
                            artifact_value="www.ibm.com",
                            rc=rc)

        if res.status_code == 200:
            log.info("Test was successful!")
            return {"state": "success"}

        else:
            raise IntegrationError("Response was not successful")

    except Exception as err:
        print_error(err, app_configs)
        return {"state": "failure", "reason": err}
def init_select_list_choices(rest_client, field_name, field_value=None):
    """
    Update the rule activity select field choices at run time.  
    We do not know the firewall and network object group lists till run time as
    these are defined by the user in the app.config.  
    """
    try:
        # Get the current firewall rule activity select list.
        uri = "/types/actioninvocation/fields/{0}".format(field_name)
        get_response = rest_client.get(uri)

        values = []

        # Add each firewall as a select list entry.
        for label in field_value:
            entry = {'label': label, 'enabled': True, 'hidden': False}
            values.append(entry)

        # Put the new values into the select list to replace the current values there.
        get_response['values'] = values
        put_response = rest_client.put(uri, payload=get_response)

        return put_response

    except Exception as err:
        raise IntegrationError(err)
示例#10
0
    def request(self, command_name, params):
        """
        make the call to ePO, returning results as json formatted
        :param command_name:
        :param params: ePO command params
        :return:
        """
        params_ext = params.copy() if params else {}
        params_ext.setdefault(':output', 'json')

        request_params = {
            "params": params_ext,
            "auth": (self.username, self.password),
            "verify": False if self.trust_cert == "false" else True
        }
        url = urljoin(self.url, 'remote/{}'.format(command_name))

        # Make request
        r = self.rc.execute_call_v2("get", url, **request_params)

        status_code = r.status_code
        if status_code >= 300 or not r.text.startswith('OK'):
            raise IntegrationError("find tags failed: {}".format(r.text))

        # convert result to true json
        try:
            result = json.loads(b_to_s(r.text).replace("OK:", ""))
        except json.decoder.JSONDecodeError:
            result = {}

        return result
示例#11
0
def selftest_function(opts):
    """
    Placeholder for selftest function. An example use would be to test package api connectivity.
    Suggested return values are be unimplemented, success, or failure.
    """
    app_configs = opts.get(CONFIG_DATA_SECTION, {})
    rc = RequestsCommon(opts, app_configs)

    try:
        # Get and validate app configs
        valid_app_configs = validate_fields([{
            "name": "shodan_apikey",
            "placeholder": "<your-api-key>"
        }], app_configs)

        # Execute api call
        res = make_api_call(call_type="info",
                            rc=rc,
                            api_key=valid_app_configs.get("shodan_apikey"),
                            app_configs=valid_app_configs)

        if not res.get("query_credits") is None:
            log.info("Test was successful!\nResponse from Shodan:\n%s", res)
            return {"state": "success"}

        else:
            raise IntegrationError("Response from Shodan was not successful")

    except Exception as err:
        print_error(err, app_configs)
        return {"state": "failure", "reason": err}
    def _patch_incident(self, incident_id, incident_payload):
        """ _patch_incident will update an incident with the specified json payload.
        :param incident_id: incident ID of incident to be updated.
        ;param incident_payload: incident fields to be updated.
        :return:
        """
        try:
            # Update incident
            incident_url = "/incidents/{0}".format(incident_id)
            incident = self.rest_client.get(incident_url)
            patch = resilient.Patch(incident)

            # Iterate over payload dict.
            for name, _ in incident_payload.items():
                if name == 'properties':
                    for field_name, field_value in incident_payload[
                            'properties'].items():
                        patch.add_value(field_name, field_value)
                else:
                    payload_value = incident_payload.get(name)
                    patch.add_value(name, payload_value)

            patch_result = self.rest_client.patch(incident_url, patch)
            result = self._chk_status(patch_result)
            # add back the incident id
            result['id'] = incident_id
            return result

        except Exception as err:
            raise IntegrationError(err)
示例#13
0
    def update_incident(self, payload, existing_incident):
        """ update_incident will update an incident with the specified json payload.
        ;param payload: incident fields to be updated.
        existing_incident ([dict]): existing incident fields, or None for create operation
        :return: incident updated
        """
        try:
            # Update incident
            incident_url = "/".join([INCIDENT_URL, str(existing_incident['id'])])

            patch = resilient.Patch(existing_incident)

            # Iterate over payload dict.
            for name, _ in payload.items():
                if name == 'properties':
                    for field_name, field_value in payload['properties'].items():
                        patch.add_value(field_name, field_value)
                else:
                    payload_value = payload.get(name)
                    patch.add_value(name, payload_value)

            patch_result = self.rest_client.patch(incident_url, patch)
            result = self._chk_status(patch_result)
            # add back the incident id
            result['id'] = existing_incident['id']
            return result

        except Exception as err:
            raise IntegrationError(err)
def compute_ip_with_range(ip_kind, ip_value, ip_end_range):
    """ Compute the network object value of an IPv4Range kind of network object.
    """
    if not ip_end_range:
        raise IntegrationError("IP netmask not defined.")

    if ip_kind == "IPv4Address":
        if not is_valid_ipv4_addr(ip_end_range):
            raise IntegrationError("IPv4Address end range is not a valid IP.")
    elif ip_kind == "IPv6Address":
        if not is_valid_ipv6_addr(ip_end_range):
            raise IntegrationError("IPv6Address end range is not a valid IP.")
    else:
        raise IntegrationError("Invalid network object kind for IP end range.")

    network_object_value = u"{0}-{1}".format(ip_value, ip_end_range)
    return network_object_value
    def get_incident_comments(self, incident_id):
        try:
            uri = u'/incidents/{0}/comments'.format(incident_id)

            comment_response = self.rest_client.get(uri=uri)
            return comment_response

        except Exception as err:
            raise IntegrationError(err)
示例#16
0
    def _chk_status(self, resp, rc=200):
        """
        check the return status. If return code is not met, raise IntegrationError,
        if success, return the json payload
        :param resp:
        :param rc:
        :return:
        """
        if hasattr(resp, "status_code"):
            if isinstance(rc, list):
                if resp.status_code < rc[0] or resp.status_code > rc[1]:
                    raise IntegrationError(u"status code failure: {0}".format(resp.status_code))
            elif resp.status_code != rc:
                raise IntegrationError(u"status code failure: {0}".format(resp.status_code))

            return resp.json()

        return {}
    def _add_worklog_notes(self, incident, ticket):
        """
        For each worklog of a Secureworks CTP ticket, post a note in the corresponding Resilient incident.
        Only post the worklog note if it has not been posted already.  Check the "dateCreated" timestamp
        of the worklog and compare to the timestamp stored in the first line of the resilient note to
        determine of the worklog is already in Resilient.  Seems like Secureworks should only send worklogs
        that are updated and not ALL as it does.  There is a conflict with calling worklogs=UPDATED as
        newly created tickets will not be sent to Resilient if we use this parameter.
        :param incident: Resilient incident
        :param ticket: Secureworks ticket
        :return:
        """
        try:
            incident_id = incident.get('id')

            # Get worklogs list and reverse the order so that older notes are added first.
            worklogs = ticket.get('worklogs')
            worklogs.reverse()

            # Loop through the list of worklogs for the ticket and add a Resilient incident note.
            for worklog in worklogs:
                date_timestamp = worklog.get('dateCreated')
                worklog_type = worklog.get('type')
                # Determine if the note for this worklog is already in Resilent.
                found = self._find_note_in_incident(incident_id,
                                                    date_timestamp,
                                                    worklog_type)
                if found:
                    continue

                # Continue on to build the note string and post to Resilient
                description = worklog.get('description')
                worklog_type = worklog.get('type')
                created_by = worklog.get('createdBy')
                note = u"<b>Secureworks CTP Worklog:</b> {0}<br />".format(
                    date_timestamp)
                if worklog_type:
                    note = u"{0}    <b>Type:</b> {1}<br />".format(
                        note, worklog_type)
                if date_timestamp:
                    created = readable_datetime(date_timestamp)
                    note = u"{0}    <b>Date Created:</b> {1}<br />".format(
                        note, created)
                if created_by:
                    note = u"{0}    <b>Created by:</b> {1}<br />".format(
                        note, created_by)
                if description:
                    description = description.replace("\n", "<br />")
                    note = u"{0}    <b>Description:</b><br /> {1}".format(
                        note, description)

                LOG.info(u"Writing note to incident %d: %s", incident_id, note)
                response = self._create_incident_comment(incident_id, note)
                LOG.debug(response)

        except Exception as err:
            raise IntegrationError(err)
    def _add_ticket_attachments(self, incident, ticket):
        """
        Add the list of Secureworks ticket attachments to the Resilient incident.  Only add attachments that
        are not already in Resilient.  To make sure this is the case, add the Secureworks attachmentInfo id
        to the attachment name in Resilient and then check whether this attachment name is already in Resilient.
        :param incident: Resilient incident
        :param ticket:  Secureworks ticket
        :return:
        """
        try:
            attachment_info_list = ticket.get('attachmentInfo')
            incident_id = incident.get('id')
            ticket_id = ticket.get('ticketId')

            # Get the list of attachments in this incident.
            uri = u'/incidents/{0}/attachments'.format(incident_id)
            res_attachments = self.rest_client().get(uri)

            for attachment in attachment_info_list:
                attachment_id = attachment.get('id')

                # Get ticket attachment and name
                response = self.scwx_client.get_tickets_attachment(
                    ticket_id, attachment_id)
                attachment_name = attachment.get('name')

                # Use the Secureworks attachmentInfo id in the name to uniquely identify it.
                if not attachment_name:
                    res_attachment_name = u"attachmentInfo-id-{0}".format(
                        attachment_id)
                else:
                    res_attachment_name = u"{0}-attachmentInfo-id-{1}".format(
                        attachment_name, attachment_id)

                attachment_in_incident = False
                for r_attachment in res_attachments:
                    if r_attachment.get("name") == res_attachment_name:
                        attachment_in_incident = True

                if attachment_in_incident:
                    # Don't create attachment as it is already in Resilient
                    continue

                content = response.get('content')
                datastream = BytesIO(content)
                # Write the file as attachement: failures will raise an exception
                message = u"Writing {0} for Secureworks CTP ticket {1} to Resilient incident {2}".format(
                    attachment_name, ticket_id, incident_id)
                LOG.info(message)
                new_attachment = write_file_attachment(self.rest_client(),
                                                       res_attachment_name,
                                                       datastream, incident_id,
                                                       None)
                LOG.debug(new_attachment)
        except Exception as err:
            raise IntegrationError(err)
    def _close_incident(self, incident, ticket):
        """
        Close a Resilient incident by rendering a jinja2 template
        :param ticket: Secureworks CTP ticket (json object)
        :return: Resilient incident
        """

        try:
            # Close a Resilient incident from this ticket
            # using a JSON (JINJA2) template file
            template_file_path = self.options.get('template_file_close')
            if template_file_path and not os.path.exists(template_file_path):
                LOG.warning(u"Template file '%s' not found.",
                            template_file_path)
                template_file_path = None
            if not template_file_path:
                # Use the template file installed by this package
                template_file_path = resource_filename(
                    Requirement("fn-secureworks-ctp"),
                    "fn_secureworks_ctp/data/scwx_ctp_template_close.jinja")
                if not os.path.exists(template_file_path):
                    raise Exception(
                        u"Template file for close'{0}' not found".format(
                            template_file_path))

            LOG.info(
                u"Secureworks CTP jinja template file for closing incident: %s",
                template_file_path)
            with open(template_file_path, "r") as definition:
                close_template = definition.read()

            incident_payload = render_json(close_template, ticket)
            # Set the scwx_ctp_status incident field to the ticket status (Closed or Resolved) so that the
            # automatic rule to close the Securework ticket is not triggered as the ticket is already closed in SCWX.
            incident_payload['properties']['scwx_ctp_status'] = ticket.get(
                "status")

            # Render the template.
            incident_id = incident.get('id')
            result = self._update_incident(incident_id, incident_payload)
            LOG.debug(incident_payload)

            ticket_id = ticket.get('ticketId')
            if result and result.get('success'):
                message = u"Closed incident {0} for Secureworks CTP ticket {1}".format(
                    incident_id, ticket_id)
                LOG.info(message)
            else:
                message = u"Unable to update incident {0} for closing. Secureworks CTP ticket {1}".format(
                    incident_id, ticket_id)
                LOG.error(message)
            return result

        except Exception as err:
            raise IntegrationError(err)
def spamhaus_call_error(res):
    """
    :param res: Object returned from ResilientCommon.execute_call_v2 call
    :return: res or raise an SpamhausRequestCallError with the reason
    """

    if res.status_code == 200 or res.status_code == 404:
        return res
    else:
        raise IntegrationError(
            "Call to Spamhaus API failed. Reason: {0}".format(res.reason))
示例#21
0
def get_broker_section(opts, broker_label):
    # find the broker section
    broker_section_name = "{}:{}".format(PACKAGE_NAME, broker_label)
    broker_section = opts.get(broker_section_name)
    if not broker_section:
        msg = "Unable to find app.config section: {}".format(
            broker_section_name)
        raise IntegrationError(msg)
    else:
        validate_fields(["bootstrap_servers"], broker_section)

    return broker_section
    def update_incident(self, incident_id, incident_payload):
        """
        Update a Resilient incident by rendering a jinja2 template
        :param sentinel_incident: Secureworks CTP sentinel_incident (json object)
        :return: Resilient incident
        """

        try:
            result = self._patch_incident(incident_id, incident_payload)
            return result

        except Exception as err:
            raise IntegrationError(err)
    def create_incident(self, incident_payload):
        """
        Create a new Resilient incident by rendering a jinja2 template
        :param sentinel_incident: sentinel_incident (json object)

        :return: Resilient incident
        """
        try:
            # Post incident to Resilient
            incident = self.rest_client.post("/incidents", incident_payload)
            return incident
        except Exception as err:
            raise IntegrationError(str(err))
示例#24
0
def get_attribute_uuid(misp_client, misp_attribute_value, misp_event_id):
    misp_event = MISPEvent()
    misp_event.id = int(misp_event_id)
    event_response = misp_client.get_event(misp_event)
    attribute_uuid = None
    if not event_response['Event']['Attribute']:
        log.error(
            "Could not get a uuid for event = {} and attribute = {}. Does it exist?"
            .format(misp_event_id, misp_attribute_value))
        raise IntegrationError(
            "Failed to find any attributes on event {}".format(misp_event_id))

    else:
        for attribute in event_response['Event']['Attribute']:
            if attribute['value'] == misp_attribute_value:
                attribute_uuid = attribute['uuid']
        if attribute_uuid:
            return attribute_uuid
        else:
            raise IntegrationError(
                "Failed to match attribute value = {} for any attributes associated with event = {}"
                .format(misp_attribute_value, misp_event_id))
示例#25
0
    def create_note_callback(self, resp):
        """ handle results such as this
            {"error":{"message":"Invalid Input Provided","code":2001,"errors":["Content cannot be empty."]}}
        """
        result = resp.json()
        if 'error' in result and result['error']['code'] == 2001:
            msg = ": ".join(
                (result['error']['message'], str(result['error']['errors'])))
            self.log.warning(msg)
            StatusMessage(msg)
            return {}

        raise IntegrationError(resp.text)
    def _update_custom_fields(self, incident, ticket):
        """
        Update a Resilient incident by rendering a jinja2 template
        :param ticket: Secureworks CTP ticket (json object)
        :return: Resilient incident
        """

        try:
            # Update Resilient custom incident fields from this ticket
            # using a JSON (JINJA2) template file
            template_file_path = self.options.get('template_file_update')
            if template_file_path and not os.path.exists(template_file_path):
                LOG.warning(u"Template file '%s' not found.",
                            template_file_path)
                template_file_path = None
            if not template_file_path:
                # Use the template file installed by this package
                template_file_path = resource_filename(
                    Requirement("fn-secureworks-ctp"),
                    "fn_secureworks_ctp/data/scwx_ctp_template_update.jinja")
                if not os.path.exists(template_file_path):
                    raise Exception(
                        u"Template file for updating incident'{0}' not found".
                        format(template_file_path))

            LOG.info(
                u"Secureworks CTP jinja template file for updating incident: %s",
                template_file_path)
            with open(template_file_path, "r") as definition:
                update_template = definition.read()

            incident_payload = render_json(update_template, ticket)

            # Render the template.
            incident_id = incident.get('id')
            result = self._update_incident(incident_id, incident_payload)
            LOG.debug(incident_payload)

            ticket_id = ticket.get('ticketId')
            if result and result.get('success'):
                message = u"Updated incident {0} for Secureworks CTP ticket {1}".format(
                    incident_id, ticket_id)
                LOG.info(message)
            else:
                message = u"Unable to update incident {0} for Secureworks CTP ticket {1}".format(
                    incident_id, ticket_id)
                LOG.error(message)
            return result

        except Exception as err:
            raise IntegrationError(err)
    def update_type(self, mapped_type_name, sync_inc_id, sync_type_id,
                    sync_task_id, payload):
        """
        update the object. This will require reading the current record to collect the existing version number
        :param mapped_type_name:
        :param sync_inc_id:
        :param sync_type_id:
        :param sync_task_id:
        :param payload:
        :return:
        """
        uri, is_datatable = get_url(sync_task_id or sync_inc_id,
                                    mapped_type_name,
                                    update_flag=True)

        # get uri to our record
        update_uri = "{}/{}".format(uri, sync_type_id)

        # datatables need to go row by row to find the existing record to update
        if is_datatable:
            existing_object = self.get_existing_datatable_row(
                sync_inc_id, mapped_type_name, sync_type_id)
        else:
            # get the existing record
            # some objects, like milestones, cannot be individually referenced
            try:
                existing_object = self.rest_client.get(update_uri)
            except Exception as err:
                existing_object = None

        # set the version of this record, if applicable
        if existing_object:
            # some objects have 'vers' and others have 'version'
            key = [
                vers for vers in ['vers', 'version'] if vers in existing_object
            ]
            if key:
                ## collect the version number
                version = existing_object[key[0]]
                ## add correct version number
                payload[key[0]] = version

        try:
            response = self.rest_client.put(update_uri, payload)

        except Exception as err:
            LOG.warning("Unable to update %s %s, Incident %s, %s",
                        mapped_type_name, sync_type_id, sync_inc_id, err)
            LOG.debug(update_uri)
            LOG.debug(payload)
            raise IntegrationError(str(err))
def compute_ip_with_netmask(ip_kind, ip_value, ip_netmask):
    """ Compute the network object value of an IPv4Range or IPv6Range kind of network object.
    """
    if not ip_netmask:
        raise IntegrationError("IP netmask not defined.")

    # IPv4 netmask contains / in the input but IPv6 does not.
    # Using the same input format as ASDM.
    if "/" in ip_netmask:
        netmask = int(ip_netmask.split("/")[1])
    else:
        netmask = int(ip_netmask)
    if ip_kind == "IPv4Network":
        # Netmask /32 is treated differently. It is a single IP address where as other
        # netmask cover a range of IPs.  Set the network object type to IPv4Address
        # in this special case.

        if netmask == 32:
            network_object_kind = "IPv4Address"
            network_object_value = u"{0}/{1}".format(ip_value,
                                                     "255.255.255.255")
        else:
            network_object_kind = "IPv4Network"
            network_object_value = u"{0}/{1}".format(ip_value, netmask)
    elif ip_kind == "IPv6Network":
        if netmask > 128 or netmask < 8:
            raise IntegrationError(
                "Invalid IPv6Network prefix length must be less than or equal to 128 and greater than 8."
            )
        if netmask == 128:
            network_object_kind = "IPv6Address"
        else:
            network_object_kind = "IPv6Network"
        network_object_value = u"{0}/{1}".format(ip_value, ip_netmask)
    else:
        raise IntegrationError("Invalid network object kind for IP netmask.")

    return network_object_kind, network_object_value
示例#29
0
def create_incident_comment(rest_client, incident_id, note):
    """
    Add a comment to the specified Resilient Incident by ID
    :param incident_id:  Resilient Incident ID
    :param note: Content to be added as note
    :return: Response from Resilient for debug
    """
    try:
        uri = '/incidents/{}/comments'.format(incident_id)

        note_json = {'format': 'html', 'content': note}
        payload = {'text': note_json}
        comment_response = rest_client.post(uri=uri, payload=payload)
        return comment_response

    except Exception as err:
        raise IntegrationError(err)
示例#30
0
def search_misp_attribute(misp_client, search_attribute):
    search_results = misp_client.search(value=search_attribute)
    if not isinstance(search_results, list):
        raise IntegrationError(
            "Received an unexpected response type from the MISP API. Expected a list but received: {}"
            .format(type(search_results)))
    search_results_len = len(search_results)
    if search_results_len == 0:
        success_status = False
    elif search_results_len > 0:
        success_status = True
    else:
        success_status = False
    search_results_response = {
        "search_status": success_status,
        "search_results": search_results
    }
    return search_results_response