def _utilities_attachment_zip_list_function(self, event, *args, **kwargs): """Function: Reads a ZIP file and produces a list of the file paths, and a list with detailed information about each file.""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"]["workflow_instance_id"] # Get the function parameters: incident_id = kwargs.get("incident_id") # number task_id = kwargs.get("task_id") # number attachment_id = kwargs.get("attachment_id") # number log = logging.getLogger(__name__) log.info("incident_id: %s", incident_id) log.info("task_id: %s", task_id) log.info("attachment_id: %s", attachment_id) # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # yield StatusMessage("starting...") # yield StatusMessage("done...") results = { "value": "xyz" } # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _panorama_create_address_function(self, event, *args, **kwargs): """Function: Panorama create new address""" try: yield StatusMessage("Creating new address") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields(["panorama_name_parameter", "panorama_request_body"], kwargs) # Get the function parameters: location = self.get_select_param(kwargs.get("panorama_location")) # select vsys = kwargs.get("panorama_vsys") # text name = kwargs.get("panorama_name_parameter") # text body = self.get_textarea_param(kwargs.get("panorama_request_body")) # textarea # Log inputs if location is None: raise ValueError("panorama_location needs to be set.") log.info("panorama_location: {}".format(location)) log.info("panorama_vsys: {}".format(vsys)) log.info("panorama_request_body: {}".format(body)) log.info("panorama_name_parameter: {}".format(name)) panorama_util = PanoramaClient(self.opts, location, vsys) response = panorama_util.add_address(name, body) yield StatusMessage("Address created") results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def _bit9_file_instance_update_function(self, event, *args, **kwargs): """Function: Update the approval state of a file instance""" try: validate_fields( ["bit9_file_instance_id", "bit9_file_instance_localstate"], kwargs) # Get the function parameters: bit9_file_instance_id = kwargs.get( "bit9_file_instance_id") # number bit9_file_instance_localstate = kwargs.get( "bit9_file_instance_localstate") # number log.info(u"bit9_file_instance_id: %s", bit9_file_instance_id) log.info(u"bit9_file_instance_localstate: %s", bit9_file_instance_localstate) payload = {"localState": bit9_file_instance_localstate} bit9_client = CbProtectClient(self.options) results = bit9_client.update_file_instance(bit9_file_instance_id, payload) log.info("Done") log.debug(results) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as err: log.error(err) yield FunctionError(err)
def _fn_proofpoint_trap_delete_list_member_function( self, event, *args, **kwargs): """Function: Delete the member of a list.""" try: params = transform_kwargs(kwargs) if kwargs else {} rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: trap_list_id = kwargs.get("trap_list_id") # number trap_member_id = kwargs.get("trap_member_id") # number LOG.info("trap_list_id: %s", trap_list_id) LOG.info("trap_member_id: %s", trap_member_id) validate_fields(["trap_list_id", "trap_member_id"], kwargs) pptr = PPTRClient(self.opts, self.options) rtn = pptr.delete_list_member(**params) results = rp.done(True, rtn) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception( "Exception in Resilient Function for Proofpoint TRAP.") yield FunctionError()
def _url_void_function(self, event, *args, **kwargs): """Function: Retrieves information of a URL from the URL Void database.""" try: yield StatusMessage("URL Void function started...") rp = ResultPayload("fn_url_void", **kwargs) # Add support for Requests Common req_common = RequestsCommon(self.opts, self.options) api_key = self.options.get("api_key") identifier = self.options.get("identifier", "api1000") # Get the function parameters: artifact_value = kwargs.get("artifact_value") # text url_void_endpoint = self.get_select_param(kwargs.get("url_void_endpoint", "Retrieve")) # select validate_fields(["artifact_value", "url_void_endpoint"], kwargs) log.info("artifact_value: %s", artifact_value) log.info("url_void_endpoint: %s", url_void_endpoint) response = call_url_void_api(req_common, artifact_value, identifier, api_key, url_void_endpoint) yield StatusMessage("URL Void function completed successfully...") results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def _utilities_resilient_search_function(self, event, *args, **kwargs): """Function: Searches Resilient for incident data. NOTE: The results may include incidents that the current user cannot access. Use with caution, to avoid information disclosure.""" try: # Get the function parameters: resilient_search_template = self.get_textarea_param(kwargs.get("resilient_search_template")) # textarea resilient_search_query = kwargs.get("resilient_search_query") # text log = logging.getLogger(__name__) log.info("resilient_search_template: %s", resilient_search_template) log.info("resilient_search_query: %s", resilient_search_query) # Read the search template as JSON template = json.loads(resilient_search_template) # Add in the search query template["query"] = resilient_search_query # Add in the current organization id (don't want results outside this org!) template["org_id"] = self.rest_client().org_id # Run the search and return the results yield StatusMessage("Searching...") results = self.rest_client().search(template) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _fn_aws_iam_list_user_access_key_ids_function(self, event, *args, **kwargs): """Function: Get information about the access key IDs associated with the specified IAM user. param aws_iam_user_name: An IAM user name. """ try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: aws_iam_user_name = kwargs.get("aws_iam_user_name") # text LOG.info("aws_iam_user_name: %s", aws_iam_user_name) validate_fields(["aws_iam_user_name"], kwargs) iam_cli = AwsIamClient(self.options) rtn = iam_cli.get("list_access_keys", paginate=True, **params) for j in range(len(rtn)): rtn[j]["key_last_used"] = \ iam_cli.get("get_access_key_last_used", AccessKeyId=rtn[j]['AccessKeyId']) 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 _panorama_get_address_groups_function(self, event, *args, **kwargs): """Function: Panorama get address groups returns the list of address groups """ try: yield StatusMessage("Getting list of Address Groups") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields(["panorama_name_parameter"], kwargs) # Get the function parameters: location = self.get_select_param( kwargs.get("panorama_location")) # select vsys = kwargs.get("panorama_vsys") # text name = kwargs.get( "panorama_name_parameter") # text (optional parameter) # Log inputs if location is None: raise ValueError("panorama_location needs to be set.") log.info("panorama_location: {}".format(location)) log.info("panorama_vsys: {}".format(vsys)) log.info("panorama_name_parameter: {}".format(name)) panorama_util = PanoramaClient(self.opts, location, vsys) response = panorama_util.get_address_groups(name) yield StatusMessage("{} groups returned.".format( response["result"]["@count"])) results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def _qradar_advisor_map_rule_function(self, event, *args, **kwargs): """Function: Map rule to MITRE ATT&CK tactic""" try: # Get the function parameters: qradar_rule_name = kwargs.get("qradar_rule_name") # text log = logging.getLogger(__name__) log.info("qradar_rule_name: %s", qradar_rule_name) qradar_verify_cert = True if "verify_cert" in self.options and self.options[ "verify_cert"] == "false": qradar_verify_cert = False yield StatusMessage("starting...") client = QRadarCafmClient( qradar_host=self.options["qradar_host"], cafm_token=self.options["qradar_cafm_token"], cafm_app_id=self.options["qradar_cafm_app_id"], cafile=qradar_verify_cert, log=log) tactics = client.find_tactic_mapping(qradar_rule_name) yield StatusMessage("done...") results = {"tactics": tactics} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: log.exception(str(e)) yield FunctionError()
def _cb_notify_when_host_comes_online_function(self, event, *args, **kwargs): """Function: Notifies the incident owner when a host comes back online.""" results = {} results["was_successful"] = False results["hostname"] = None results["Online"] = False try: # Get the function parameters: incident_id = kwargs.get("incident_id") # number hostname = kwargs.get("hostname") # text max_days = kwargs.get("max_days") # number log = logging.getLogger(__name__) # Establish logging try: days_later_timeout_length = datetime.datetime.now() + datetime.timedelta(days=max_days) # Max duration length before aborting hostname = hostname.upper()[:15] # CB limits hostname to 15 characters sensor = cb.select(Sensor).where('hostname:' + hostname) # Query CB for the hostname's sensor if len(sensor) <= 0: # Host does not have CB agent, abort yield StatusMessage("[FATAL ERROR] CB could not find hostname: " + str(hostname)) yield StatusMessage('[FAILURE] Fatal error caused exit!') yield FunctionResult(results) return sensor = sensor[0] # Get the sensor object from the query results["hostname"] = str(hostname).upper() now = datetime.datetime.now() # Check online status if sensor.status != "Online": yield StatusMessage('[INFO] Hostname: ' + str(hostname) + ' is offline. Will notify when online for ' + str(max_days) + ' days...') while (sensor.status != "Online") and (days_later_timeout_length >= now): # Continuously check if the sensor comes online for max_days time.sleep(3) # Give the CPU a break, it works hard! now = datetime.datetime.now() sensor = (cb.select(Sensor).where('hostname:' + hostname))[0] # Retrieve the latest sensor vitals # Abort after max_days if sensor.status != "Online": yield StatusMessage('[FATAL ERROR] Hostname: ' + str(hostname) + ' is still offline!') yield StatusMessage('[FAILURE] Fatal error caused exit!') yield FunctionResult(results) return except Exception as err: # Catch all other exceptions and abort yield StatusMessage('[FATAL ERROR] Encountered: ' + str(err)) yield StatusMessage('[FAILURE] Fatal error caused exit!') else: yield StatusMessage('[SUCCESS] Hostname: ' + str(hostname) + ' is online!') results["was_successful"] = True results["Online"] = True # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _utility_email_file_parser_function(self, event, *args, **kwargs): """Function: Parses .eml files for email forensics. Useful for reported phishes.""" try: # Get the function parameters: incident_id = kwargs.get("incident_id") # number attachment_id = kwargs.get("attachment_id") # number eml_filename = kwargs.get("attachment_name") # text # Get the eml file attachment by its incident and attachment IDs eml_file = get_file_attachment(self.rest_client(), incident_id, artifact_id=None, task_id=None, attachment_id=attachment_id) yield StatusMessage('Reading and decoding email message (' + eml_filename + ')...') # Parse the email content mail = email.message_from_string(eml_file.decode("utf-8")) # Get the email object from the raw contents email_body, attachments, urls = get_decoded_email_body(self, incident_id, eml_filename, mail) # Get the UTF-8 encoded body from the raw email string email_header = get_decoded_email_header(mail.items()) results = {} results['body'] = str(email_body) # The full email, HTML formatted results['header'] = email_header # List of 2-tuples containing all the message’s field headers and values # results['mail_items'] = mail.items() # List of 2-tuples containing all the decoded message’s field headers and values (3/12/2019: deprecated, use 'header') results['attachments'] = attachments # List of attachment names from EML file results['urls'] = list(set(urls)) # URLs from body. Set inside of the list used to ensures no duplicates. # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def get_content(client, incident_id, attachment_id, artifact_id): entity = { "incident_id": incident_id, "id": None, "type": "", "meta_data": None, "data": None } if attachment_id: return client.get_content( "/incidents/{0}/attachments/{1}/contents".format( entity["incident_id"], attachment_id)) elif artifact_id: entity["meta_data"] = client.get("/incidents/{0}/artifacts/{1}".format( entity["incident_id"], artifact_id)) # handle if artifact has attachment if (entity["meta_data"].get("attachment")): return client.get_content( "/incidents/{0}/artifacts/{1}/contents".format( entity["incident_id"], artifact_id)) else: raise FunctionError("Artifact has no attachment or supported URI") else: raise ValueError('attachment_id AND artifact_id both None')
def _utilities_excel_query_function(self, event, *args, **kwargs): """Function: Extracts ranges of data or named ranges specified by the user from a Microsoft Excel document. The function uses a Python library called openpyxl (http://openpyxl.readthedocs.io/en/stable/) to interface with Excel files.""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"]["workflow_instance_id"] # Get the function parameters: task_id = kwargs.get("task_id") # number excel_ranges = kwargs.get("excel_ranges") # text incident_id = kwargs.get("incident_id") # number excel_defined_names = kwargs.get("excel_defined_names") # text attachment_id = kwargs.get("attachment_id") # number log = logging.getLogger(__name__) log.info("task_id: %s", task_id) log.info("excel_ranges: %s", excel_ranges) log.info("incident_id: %s", incident_id) log.info("excel_defined_names: %s", excel_defined_names) log.info("attachment_id: %s", attachment_id) # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # yield StatusMessage("starting...") # yield StatusMessage("done...") results = { "value": "xyz" } # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _utilities_get_contact_info_function(self, event, *args, **kwargs): """Function: Retrieves contact information of the owner and members of an incident or task.""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"][ "workflow_instance_id"] # Get the function parameters: incident_id = kwargs.get("incident_id") # number task_id = kwargs.get("task_id") # number log = logging.getLogger(__name__) log.info("incident_id: %s", incident_id) log.info("task_id: %s", task_id) # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # yield StatusMessage("starting...") # yield StatusMessage("done...") results = {"value": "xyz"} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _mitre_groups_technique_intersection_function(self, event, *args, **kwargs): """Function: For given Techniques return the Groups that are know to use all of them.""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"][ "workflow_instance_id"] # Get the function parameters: 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) intersection_query = ",".join([t.id for t in techniques]) yield StatusMessage("Getting group intersection information...") groups = mitre_attack.MitreAttackGroup.get_by_technique_intersection( mitre_conn, techniques) if len(groups) == 0: yield StatusMessage( "No groups were found using all of the given techniques. Done" ) else: yield StatusMessage("Done. Returning results.") # Storing the techniques specified to query this group for group in groups: group.technique_id = intersection_query 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: yield FunctionError(e)
def _misp_sighting_list_function(self, event, *args, **kwargs): """Function: Return a list of sightings associated with a given event""" try: API_KEY, URL, VERIFY_CERT = common.validate(self.options) # Get the function parameters: event_id = int(kwargs.get("misp_event_id")) # text log = logging.getLogger(__name__) log.info("event_id: %s", event_id) 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("Getting sighted list") sighting_list_result = misp_helper.get_misp_sighting_list( misp_client, event_id) yield StatusMessage("Finished getting sighting list") results = {"success": True, "content": sighting_list_result} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _utilities_xml_transformation_function(self, event, *args, **kwargs): """Function: Transforms an XML document using a preexisting `xsl` stylesheet. The resulting content is returned.""" 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 'utilities_xml_transformation' running in workflow '{0}'" .format(wf_instance_id)) # Get the function parameters: xml_stylesheet = kwargs.get("xml_stylesheet") # text xml_source = kwargs.get("xml_source") # text log = logging.getLogger(__name__) log.info("xml_stylesheet: %s", xml_stylesheet) log.info("xml_source: %s", xml_source) ############################################## # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # ############################################## yield StatusMessage( "Finished 'utilities_xml_transformation' that was running in workflow '{0}'" .format(wf_instance_id)) results = {"content": "xyz"} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _fn_check_hsts_function(self, event, *args, **kwargs): """Function: None""" 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 'fn_check_hsts' running in workflow '{0}'".format( wf_instance_id)) # Get the function parameters: domain_name = kwargs.get("domain_name") # text log = logging.getLogger(__name__) log.info("domain_name: %s", domain_name) result = self.has_hsts(domain_name) results = {"has_hsts": result} yield StatusMessage( "Finished 'fn_check_hsts' that was running in workflow '{0}'". format(wf_instance_id)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def get_input_entity(client, incident_id, attachment_id, artifact_id): re_uri_match_pattern = r"""(?:(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))?""" entity = {"incident_id": incident_id, "id": None, "type": "", "meta_data": None, "data": None} if (attachment_id): entity["id"] = attachment_id entity["type"] = "attachment" entity["meta_data"] = client.get("/incidents/{0}/attachments/{1}".format(entity["incident_id"], entity["id"])) entity["data"] = client.get_content("/incidents/{0}/attachments/{1}/contents".format(entity["incident_id"], entity["id"])) elif (artifact_id): entity["id"] = artifact_id entity["type"] = "artifact" entity["meta_data"] = client.get("/incidents/{0}/artifacts/{1}".format(entity["incident_id"], entity["id"])) # handle if artifact has attachment if (entity["meta_data"]["attachment"]): entity["data"] = client.get_content("/incidents/{0}/artifacts/{1}/contents".format(entity["incident_id"], entity["id"])) # else handle if artifact.value contains an URI using RegEx else: match = re.match(re_uri_match_pattern, entity["meta_data"]["value"]) if (match): entity["uri"] = match.group() else: raise FunctionError("Artifact has no attachment or supported URI") else: raise ValueError('attachment_id AND artifact_id both None') return entity
def _greynoise_ip_query_function(self, event, *args, **kwargs): """Function: Perform IP Address analysis""" try: # Get the function parameters: greynoise_value = kwargs.get("greynoise_value") # text greynoise_type = self.get_select_param( kwargs.get("greynoise_type")) # select log = logging.getLogger(__name__) log.info("greynoise_value: %s", greynoise_value) log.info("greynoise_type: %s", greynoise_type) # validate input validate_fields(("greynoise_type", "greynoise_value"), kwargs) validate_fields(("api_key"), self.options) yield StatusMessage("starting...") # build result result_payload = ResultPayload(SECTION_HEADER, **kwargs) greynoise_result = call_greynoise(self.opts, self.options, greynoise_type, greynoise_value) results = result_payload.done(True, greynoise_result) yield StatusMessage("done...") # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _a_mock_function_with_no_unicode_characters_in_name_function( self, event, *args, **kwargs): """Function: A mock description of 'A Mock Function with No Unicode Characters in Name' with unicode: ล ฦ ว ศ ษ ส ห ฬ อ""" 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 'a_mock_function_with_no_unicode_characters_in_name' running in workflow '{0}'" .format(wf_instance_id)) # Get the function parameters: mock_input_text = kwargs.get("mock_input_text") # text log = logging.getLogger(__name__) log.info("mock_input_text: %s", mock_input_text) ############################################## # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # ############################################## yield StatusMessage( "Finished 'a_mock_function_with_no_unicode_characters_in_name' that was running in workflow '{0}'" .format(wf_instance_id)) results = {"content": "xyz"} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _funct_zia_get_url_categories_function(self, event, *args, **kwargs): """Function: None""" 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) if fn_inputs.get("zia_category_id") and fn_inputs.get( "zia_custom_only").lower() == "false": raise ValueError( "If parameter '{0}' is set then parameter '{1}' should be set to '{2}'." .format("zia_category_id", "zia_custom_only", "true")) # Test any enabled filters to ensure they are valid regular expressions. for f in ["zia_name_filter", "zia_url_filter"]: patt = fn_inputs.get(f) if patt and not is_regex(patt): raise ValueError( "The query filter '{}' does not have a valid regular expression." .format(repr(f))) # Remove 'zia_' prefix from function parameters. fn_inputs = dict( (k.split('_', 1)[1], v) for k, v in fn_inputs.items()) yield StatusMessage( "Validations complete. Starting business logic") ziacli = ZiaClient(self.opts, self.fn_options) result = ziacli.get_url_categories(**fn_inputs) 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 _utilities_attachment_zip_extract_function(self, event, *args, **kwargs): """Function: Extracts a file from a ZIP file attachment, producing a base64 string. That string can then be used as input to subsequent functions that might write it as a file attachment, as a malware sample artifact, or in other ways.""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"][ "workflow_instance_id"] # Get the function parameters: incident_id = kwargs.get("incident_id") # number task_id = kwargs.get("task_id") # number attachment_id = kwargs.get("attachment_id") # number file_path = kwargs.get("file_path") # text zipfile_password = kwargs.get("zipfile_password") # text log = logging.getLogger(__name__) log.info("incident_id: %s", incident_id) log.info("task_id: %s", task_id) log.info("attachment_id: %s", attachment_id) log.info("file_path: %s", file_path) log.info("zipfile_password: %s", zipfile_password) # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # yield StatusMessage("starting...") # yield StatusMessage("done...") results = {"value": "xyz"} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _base64_to_attachment_function(self, event, *args, **kwargs): """Function: """ try: log = logging.getLogger(__name__) # Get the function parameters: # artifact_file_type: # "Email Attachment", "Malware Sample", "Log File", "X509 Certificate File", "Other File", etc. base64content = kwargs.get("base64content") # text incident_id = kwargs.get("incident_id") # number task_id = kwargs.get("task_id") # number file_name = kwargs.get("file_name") # text content_type = kwargs.get("content_type") # text content_type = content_type \ or mimetypes.guess_type(file_name or "")[0] \ or "application/octet-stream" log.info("incident_id: %s", incident_id) log.info("task_id: %s", task_id) log.info("file_name: %s", file_name) log.info("content_type: %s", content_type) yield StatusMessage("Writing attachment...") datastream = BytesIO(base64.b64decode(base64content)) client = self.rest_client() new_attachment = write_file_attachment(client, file_name, datastream, incident_id, task_id, content_type) log.info(json.dumps(new_attachment)) yield FunctionResult(new_attachment) except Exception: yield FunctionError()
def _utilities_resilient_search_function(self, event, *args, **kwargs): """Function: This function searches the Resilient platform for incident data according to the criteria specified, and returns the results to your workflow. It can be used to find incidents containing data that matches any string, or incidents currently assigned to a given user, or a very wide range of other search conditions. **NOTE:** The search results may include data from incidents that the current Resilient user (the person who triggered the workflow) cannot access. Often your Resilient users have the `Default` role that allows them to only see incidents where they are members. This function runs with the permissions of your integration account, which typically may have much wider access privileges. **Use with caution, to avoid information disclosure.**""" try: # Get the wf_instance_id of the workflow this Function was called in wf_instance_id = event.message["workflow_instance"][ "workflow_instance_id"] # Get the function parameters: resilient_search_template = self.get_textarea_param( kwargs.get("resilient_search_template")) # textarea resilient_search_query = kwargs.get( "resilient_search_query") # text log = logging.getLogger(__name__) log.info("resilient_search_template: %s", resilient_search_template) log.info("resilient_search_query: %s", resilient_search_query) # PUT YOUR FUNCTION IMPLEMENTATION CODE HERE # yield StatusMessage("starting...") # yield StatusMessage("done...") results = {"value": "xyz"} # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _mcafee_epo_find_a_system_function(self, event, *args, **kwargs): """Function: Find an ePO system based on property such as system name, tag, IP address, MAC address, etc.""" try: # Get the function parameters: validate_fields(["mcafee_epo_systems"], kwargs) mcafee_epo_systems = kwargs.get("mcafee_epo_systems") # text client = init_client(self.opts, self.options) log = logging.getLogger(__name__) log.info("mcafee_epo_systems: %s", mcafee_epo_systems) yield StatusMessage("Starting") rc = ResultPayload(PACKAGE_NAME, **kwargs) params = {"searchText": mcafee_epo_systems.strip()} response = client.request("system.find", params) yield StatusMessage("Finished") results = rc.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _fn_amp_get_event_types_function(self, event, *args, **kwargs): """Function: Events are identified and filtered by a unique ID. Provides a human readable name, and short description of each event by ID.""" try: # Get the function parameters: log = logging.getLogger(__name__) amp = Ampclient(self.options, RATE_LIMITER) yield StatusMessage("Running Cisco AMP get computers query...") rtn = amp.get_event_types() query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # Add in "query_execution_time" and "ip_address" to result to facilitate post-processing. results = { "response": rtn, "query_execution_time": query_execution_time } yield StatusMessage("Returning 'event types' results") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception( "Exception in Resilient Function for Cisco AMP for endpoints.") yield FunctionError()
def _fn_get_contact_info_function(self, event, *args, **kwargs): """Function: Retrieve contact information for an incidents owner and members or those from a task""" try: # Get the function parameters: incident_id = kwargs.get("incident_id") # number task_id = kwargs.get("task_id") # number log = logging.getLogger(__name__) log.info("incident_id: %s", incident_id) log.info("task_id: %s", task_id) if incident_id is None: raise ValueError("incident_id is required") yield StatusMessage("starting...") res_client = self.rest_client() if incident_id and task_id is None: results = self.get_contact_info_by_incident( res_client, incident_id) else: results = self.get_contact_info_by_task( res_client, incident_id, task_id) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _fn_bigfix_assets_function(self, event, *args, **kwargs): """Function: Resilient Function : Bigfix assets - Get properties in BigFix for an endpoint.""" try: # Get the function parameters: bigfix_asset_name = kwargs.get("bigfix_asset_name") # text bigfix_asset_id = kwargs.get("bigfix_asset_id") # number bigfix_incident_id = kwargs.get("bigfix_incident_id") # number log = logging.getLogger(__name__) log.info("bigfix_asset_name: %s", bigfix_asset_name) log.info("bigfix_asset_id: %s", bigfix_asset_id) log.info("bigfix_incident_id: %s", bigfix_incident_id) params = { "asset_name": bigfix_asset_name, "asset_id": bigfix_asset_id, "incident_id": bigfix_incident_id } validate_params(params, "fn_bigfix_assets") yield StatusMessage( u"Running BigFix Query for Endpoint id {0}, with name {1} ...". format(params["asset_id"], params["asset_name"])) bigfix_client = BigFixClient(self.options) try: # Perform the BigFix Query response = bigfix_client.get_bf_computer_properties( params["asset_id"]) except Exception as e: log.exception("Failed to query a BigFix asset.") yield StatusMessage( "Failed with exception '{}' while trying to query a BigFix asset" .format(type(e).__name__)) raise Exception( "Failed with exception '{}' while trying to query a BigFix asset" .format(type(e).__name__)) if not response: yield StatusMessage( "No properties retrieved for the asset id '{}'".format( params["asset_id"])) results = {} else: # Create a Resilient attachment file_name = "bigfix-properties-" + params["asset_name"] + "-" + \ datetime.datetime.today().strftime('%Y%m%d') + ".xml" att_report = create_attachment(self.rest_client(), file_name, response, params) results = {"status": "OK", "att_name": att_report["name"]} yield StatusMessage("done...") log.debug(results) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
def _qradar_find_reference_set_item_function(self, event, *args, **kwargs): """Function: Find an item from a given QRadar reference set""" try: # Get the function parameters: qradar_reference_set_name = kwargs.get("qradar_reference_set_name") # text qradar_reference_set_item_value = kwargs.get("qradar_reference_set_item_value") # text log = logging.getLogger(__name__) log.info("qradar_reference_set_name: %s", qradar_reference_set_name) log.info("qradar_reference_set_item_value: %s", qradar_reference_set_item_value) qradar_verify_cert = True if "verify_cert" in self.options and self.options["verify_cert"] == "false": qradar_verify_cert = False log.debug("Connection to {} using {}".format(self.options["host"], self.options["username"])) yield StatusMessage("starting...") qradar_client = QRadarClient(host=self.options["host"], username=self.options["username"], password=self.options["qradarpassword"], token=None, cafile=qradar_verify_cert) result = qradar_client.search_ref_set(qradar_reference_set_name, qradar_reference_set_item_value) yield StatusMessage("done...") # Produce a FunctionResult with the results yield FunctionResult(result) except Exception as e: log.error(str(e)) yield FunctionError()