def _umbrella_pattern_search_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Pattern Search.""" try: # Get the function parameters: umbinv_regex = kwargs.get("umbinv_regex") # text umbinv_start_epoch = kwargs.get("umbinv_start_epoch") # datetimepicker umbinv_start_relative = kwargs.get("umbinv_start_relative") # text umbinv_limit = kwargs.get("umbinv_limit") # number umbinv_include_category = kwargs.get("umbinv_include_category") # boolean log = logging.getLogger(__name__) log.info("umbinv_regex: %s", umbinv_regex) log.info("umbinv_start_epoch: %s", umbinv_start_epoch) log.info("umbinv_start_relative: %s", umbinv_start_relative) log.info("umbinv_limit: %s", umbinv_limit) log.info("umbinv_include_category: %s", umbinv_include_category) if is_none(umbinv_regex): raise ValueError("Required parameter 'regex' not set") yield StatusMessage("Starting...") regex = None process_result = {} params = {"regex": umbinv_regex.strip(), "start_epoch": umbinv_start_epoch, "start_relative": umbinv_start_relative, "limit": umbinv_limit, "include_category": umbinv_include_category} validate_params(params) process_params(params, process_result) if "_regex" not in process_result: raise ValueError("Parameter 'umbinv_regex' was not processed correctly") else: regex = process_result.pop("_regex") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.search(regex, **omit_params(params, ["regex"])) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if len(rtn["matches"]) == 0: log.debug(json.dumps(rtn)) yield StatusMessage("No Results returned for regular expression '{}'.".format(regex)) results = {} else: # Add "query_execution_time" to result to facilitate post-processing. results = {"search_matches": json.loads(json.dumps(rtn)), "query_execution_time": query_execution_time} yield StatusMessage("Returning 'search_matches' results for regex '{}'.".format(regex)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_domain_related_domains_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for lrelated domains for a Domain.""" try: # Get the function parameters: umbinv_domain = kwargs.get("umbinv_domain") # text log = logging.getLogger(__name__) log.info("umbinv_domain: %s", umbinv_domain) if is_none(umbinv_domain): raise ValueError("Required parameter 'umbinv_domain' not set") yield StatusMessage("Starting...") domain = None process_result = {} params = {"domain": umbinv_domain.strip()} validate_params(params) process_params(params, process_result) if "_domain" not in process_result: raise ValueError( "Parameter 'umbinv_domain' was not processed correctly") else: domain = process_result.pop("_domain") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.related(domain) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if rtn["found"] is None or str(rtn["found"]).lower() == 'false': log.debug(json.dumps(rtn)) yield StatusMessage( "No Results returned for domain '{}'.".format(domain)) results = {} else: # Add "query_execution_time" and "domain_name" to result to facilitate post-processing. results = { "related_domains": json.loads(json.dumps(rtn)), "domain_name": domain, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'related_domains' results for domain '{}'.". format(domain)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_ip_latest_malicious_domains_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Latest Malicious Domains for an IP.""" try: # Get the function parameters: umbinv_ipaddr = kwargs.get("umbinv_ipaddr") # text log = logging.getLogger(__name__) log.info("umbinv_ipaddr: %s", umbinv_ipaddr) if is_none(umbinv_ipaddr): raise ValueError("Required parameter 'umbinv_ipaddr' not set") yield StatusMessage("Starting...") ipaddr = None process_result = {} params = {"ipaddr": umbinv_ipaddr.strip()} validate_params(params) process_params(params, process_result) if "_ipaddr" not in process_result: raise ValueError( "Parameter 'ipaddr' was not processed correctly") else: ipaddr = process_result.pop("_ipaddr") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.latest_domains(ipaddr) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if len(rtn) == 0: log.debug(json.dumps(rtn)) yield StatusMessage( "No Results returned for ip address '{}'.".format(ipaddr)) results = {} else: # Add "query_execution_time" and "ip_address" to result to facilitate post-processing. results = { "latest_malicious_domains": json.loads(json.dumps(rtn)), "ip_address": ipaddr, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'latest_malicious_domains' results for ip address '{}'." .format(ipaddr)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def selftest_function(opts): """ Simple test to confirm access to Cisco Umbrella Investigate for API connectivity. """ options = opts.get("fn_cisco_umbrella_inv", {}) api_token = options.get("api_token") base_url = options.get("base_url") try: rinv = ResilientInv(api_token, base_url) r = rinv.test_connectivity() if r.status_code == 200: return {"state": "success", "status_code": r.status_code} else: return {"state": "failure", "status_code": r.status_code} except Exception as e: return {"state": "failure", "status_code": e}
def _umbrella_ip_as_info_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for ASA information for an IP address.""" try: # Get the function parameters: umbinv_resource = kwargs.get("umbinv_resource") # text log = logging.getLogger(__name__) log.info("umbinv_resource: %s", umbinv_resource) if is_none(umbinv_resource): raise ValueError( "Required parameter 'umbinv_resource' not set") yield StatusMessage("Starting...") res = None res_type = None process_result = {} params = {"resource": umbinv_resource.strip()} validate_params(params) process_params(params, process_result) if "_res" not in process_result or "_res_type" not in process_result: raise ValueError( "Parameter 'umbinv_resource' was not processed correctly") else: res = process_result.pop("_res") res_type = process_result.pop("_res_type") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") if res_type == "ip_address": rtn = rinv.as_for_ip(res) # Add "query_execution_time" and "ip_address" key to result to facilitate post-processing. query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') results = { "as_for_ip": json.loads(json.dumps(rtn)), "ip_address": res, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'as_for_ip' results for ip address '{}'.". format(res)) elif res_type == "as_number": rtn = rinv.prefixes_for_asn(res) # Add "query_execution_time" and "ip_address" key to result to facilitate post-processing. query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') results = { "prefixes_for_asn": json.loads(json.dumps(rtn)), "asn": res, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'prefixes_for_asn' results for AS number '{}'.". format(res)) else: raise ValueError( "Parameter 'umbinv_resource' was an incorrect type '{}' should be an 'ip address' " "or an 'AS number'".format(res_type)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_domain_whois_info_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Domain Whois info.""" try: # Get the function parameters: umbinv_resource = kwargs.get("umbinv_resource") # text umbinv_limit = kwargs.get("umbinv_limit") # number umbinv_sortby = kwargs.get("umbinv_sortby") # text umbinv_offset = kwargs.get("umbinv_offset") # number log = logging.getLogger(__name__) log.info("umbinv_resource: %s", umbinv_resource) log.info("umbinv_limit: %s", umbinv_limit) log.info("umbinv_sortby: %s", umbinv_sortby) log.info("umbinv_offset: %s", umbinv_offset) if is_none(umbinv_resource): raise ValueError( "Required parameter 'umbinv_resource' not set") yield StatusMessage("Starting...") res = None res_type = None process_result = {} params = { "resource": umbinv_resource.strip(), "limit": umbinv_limit, "sort_field": umbinv_sortby, "offset": umbinv_offset } validate_params(params) process_params(params, process_result) if "_res" not in process_result or "_res_type" not in process_result: raise ValueError( "Parameter 'umbinv_resource' was not processed correctly") else: res = process_result.pop("_res") res_type = process_result.pop("_res_type") if res_type != "domain_name" and res_type != "email_address": raise ValueError( "Parameter 'umbinv_resource' was an incorrect type '{}', should be a 'domain name', " "an 'email address' or a 'nameserver'.".format(res_type)) api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url) yield StatusMessage("Running Cisco Investigate query...") if res_type == "domain_name": # Can be either domain name or name server. # Execute wois query for domain history. rtn_dom = rinv.domain_whois_history(res, params["limit"]) # Execute whois query for nameserver. rtn_ns = rinv.ns_whois(res, **omit_params(params, ["resource"])) query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') if len(rtn_dom) != 0: # Test if resource is a name server. for entry in rtn_dom: for ns in entry["nameServers"]: if res == ns: res_type = "nameserver" log.debug( "Resource '{}' is a nameserver.".format( res)) break # Add "query_execution_time", 'resource' and 'resource_type' key to result to facilitate post-processing. results = { "domain_whois": json.loads(json.dumps(rtn_dom)), "ns_whois": json.loads(json.dumps(rtn_ns)), "resource": res, "resource_type": res_type, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'whois' results for resource '{}' of resource type '{}'." .format(res, res_type)) elif res_type == "email_address": rtn = rinv.email_whois(res, **omit_params(params, ["resource"])) query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') # Add "query_execution_time" and "emails" key to result to facilitate post-processing. results = { "email_whois": json.loads(json.dumps(rtn)), "emails": res, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'email_whois' results for resource '{}'.". format(res)) else: raise ValueError( "Parameter 'umbinv_resource' was an incorrect type '{}', should be a 'domain name', " "an 'email address' or a 'nameserver'.".format(res_type)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_timeline_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate Investigate for Timeline.""" try: # Get the function parameters: umbinv_resource = kwargs.get("umbinv_resource") # text log = logging.getLogger(__name__) log.info("resource: %s", umbinv_resource) if is_none(umbinv_resource): raise ValueError("Required parameter 'umbinv_resource' not set") yield StatusMessage("Starting...") res = None res_type = None process_result = {} params = {"resource": umbinv_resource.strip()} validate_params(params) process_params(params, process_result) if "_res" not in process_result or "_res_type" not in process_result: raise ValueError("Parameter 'umbinv_resource' was not processed correctly") else: res = process_result.pop("_res") res_type = process_result.pop("_res_type") if res_type != "domain_name" and res_type != "ip_address" and res_type != "url": raise ValueError("Parameter 'umbinv_resource' was an incorrect type '{}', should be a 'domain name', " "an 'ip address' or a 'url'.".format(res_type)) api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.timeline(res) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if len(rtn) == 0: log.debug(json.dumps(rtn)) yield StatusMessage("No Results returned for resource '{}'.".format(res)) results = {} else: # Make timestamp more readable for x in range(len(rtn)): try: secs = int(rtn[x]['timestamp']) / 1000 ts_readable = datetime.fromtimestamp(secs).strftime('%Y-%m-%d %H:%M:%S') rtn[x]['timestamp_converted'] = ts_readable except ValueError: yield FunctionError('timestamp value incorrectly specified') # Add "query_execution_time" to result to facilitate post-processing. results = {"timeline": json.loads(json.dumps(rtn)), "resource_name": res, "query_execution_time": query_execution_time} yield StatusMessage("Returning 'thread_grid_samples' results for resource '{}'.".format(res)) yield StatusMessage("done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_threat_grid_sample_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Threat Grid sample for an MD5, SHA1 or SHA256 hash .""" try: # Get the function parameters: umbinv_hash = kwargs.get("umbinv_hash") # text umbinv_sample_endpoint = self.get_select_param(kwargs.get( "umbinv_sample_endpoint")) # select, values: "basic", "artifacts", "connections", "samples", "behaviors" umbinv_limit = kwargs.get("umbinv_limit") # number umbinv_offset = kwargs.get("umbinv_offset") # number log = logging.getLogger(__name__) log.info("umbinv_hash: %s", umbinv_hash) log.info("umbinv_sample_endpoint: %s", umbinv_sample_endpoint) log.info("umbinv_limit: %s", umbinv_limit) log.info("umbinv_offset: %s", umbinv_offset) if is_none(umbinv_hash): raise ValueError("Required parameter 'umbinv_hash' not set") if is_none(umbinv_sample_endpoint): raise ValueError("Required parameter 'umbinv_sample_endpoint' not set") yield StatusMessage("Starting...") hash = None process_result = {} params = {"hash": umbinv_hash.strip(), "sample_endpoint": umbinv_sample_endpoint, "limit": umbinv_limit, "offset": umbinv_offset} validate_params(params) process_params(params, process_result) if "_hash" not in process_result: raise ValueError("Parameter 'umbinv_hash' was not processed correctly") else: hash = process_result.pop("_hash") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") params = omit_params(params, ["hash", "sample_endpoint"]) if umbinv_sample_endpoint == "basic": rtn = rinv.sample(hash, **params) result_header = "sample_basic" elif umbinv_sample_endpoint == "artifacts": rtn = rinv.sample_artifacts(hash, **params) result_header = "sample_artifacts" elif umbinv_sample_endpoint == "connections": rtn = rinv.sample_connections(hash, **params) result_header = "sample_connections" elif umbinv_sample_endpoint == "samples": rtn = rinv.sample_samples(hash, **params) result_header = "sample_samples" elif umbinv_sample_endpoint == "behaviors": rtn = rinv.sample_behaviors(hash, **params) result_header = "sample_behaviors" else : raise ValueError("Incorrect value for parameter parameter 'umbinv_sample_endpoint'.") query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if ("error" in rtn and len(rtn["error"]) != 0): log.debug(json.dumps(rtn)) yield StatusMessage("Umbrella Investigate returned error message '{}'.".format(rtn["error"])) results = {} else: # Add "query_execution_time" and "hash" key to result to facilitate post-processing. results = {result_header: json.loads(json.dumps(rtn)), "hash": hash, "query_execution_time": query_execution_time} yield StatusMessage("Returning '{}' results for hash '{}'.".format(result_header, hash)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_dns_rr_hist_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for DNS RR History for a IP, Type and Domain Name""" try: # Get the function parameters: umbinv_resource = kwargs.get("umbinv_resource") # text umbinv_dns_type = self.get_select_param( kwargs.get("umbinv_dns_type") ) # select, values: "A", "NS", "MX", "TXT", "CNAME" incident_id = kwargs.get("incident_id") # number artifact_type = kwargs.get("artifact_type") # text log = logging.getLogger(__name__) log.info("umbinv_resource: %s", umbinv_resource) log.info("umbinv_dns_type: %s", umbinv_dns_type) log.info("incident_id: %s", incident_id) log.info("artifact_type: %s", artifact_type) if is_none(umbinv_resource): raise ValueError( "Required parameter 'umbinv_resource' not set") if is_none(umbinv_dns_type): raise ValueError( "Required parameter 'umbinv_dns_type' not set") if is_none(incident_id): raise ValueError("Required parameter 'incident_id' not set") if is_none(artifact_type): raise ValueError("Required parameter 'artifact_type' not set") yield StatusMessage("Starting...") res = None res_type = None process_result = {} func_name = event.name params = { "resource": umbinv_resource.strip(), "dns_type": umbinv_dns_type, "incident_id": incident_id, "artifact_type": artifact_type } validate_params(params) process_params(params, process_result) if "_res" not in process_result or "_res_type" not in process_result: raise ValueError( "Parameter 'umbinv_resource' was not processed correctly") else: res = process_result.pop("_res") res_type = process_result.pop("_res_type") if res_type != "domain_name" and res_type != "ip_address": raise ValueError( "Parameter 'umbinv_resource' was an incorrect type '{}', should be a 'domain name', " "or an 'ip address'.".format(res_type)) api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.rr_history(res, query_type=umbinv_dns_type) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if ("rrs" in rtn and len(rtn["rrs"]) == 0) \ or ("rrs_tf" in rtn and len(rtn["rrs_tf"]) == 0): log.debug(json.dumps(rtn)) yield StatusMessage( "No Results returned for resource '{}' with query type '{}'." .format(res, umbinv_dns_type)) results = {} elif ("rrs" in rtn and len(rtn["rrs"]) > int(self.options.get("results_limit", "200"))) \ or ("rrs_tf" in rtn and len(rtn["rrs_tf"]) > int(self.options.get("results_limit", "200"))): att_report = create_attachment(self, func_name, res, params, rtn, query_execution_time) # Add in "query_execution_time" and "ip_address" to result to facilitate post-processing. results = { "over_limit": True, "resource_name": res, "att_name": att_report["name"], "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'dns_rr_history' results for resource '{0}' as attachment: {1} ." .format(res, att_report["name"])) else: # Add in "query_execution_time" and "ip_address" to result to facilitate post-processing. results = { "dns_rr_history": json.loads(json.dumps(rtn)), "resource_name": res, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'dns_rr_history' results for resource '{}'.". format(res)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_domain_volume_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Domain Volume.""" try: # Get the function parameters: umbinv_domain = kwargs.get("umbinv_domain") # text umbinv_match = self.get_select_param(kwargs.get( "umbinv_match")) # select, values: "all", "component", "exact" umbinv_start_epoch = kwargs.get( "umbinv_start_epoch") # datetimepicker umbinv_start_relative = kwargs.get("umbinv_start_relative") # text umbinv_stop_epoch = kwargs.get( "umbinv_stop_epoch") # datetimepicker umbinv_stop_relative = kwargs.get("umbinv_stop_relative") # text log = logging.getLogger(__name__) log.info("umbinv_domain: %s", umbinv_domain) log.info("umbinv_match: %s", umbinv_match) log.info("umbinv_start_epoch: %s", umbinv_start_epoch) log.info("umbinv_start_relative: %s", umbinv_start_relative) log.info("umbinv_stop_epoch: %s", umbinv_stop_epoch) log.info("umbinv_stop_relative: %s", umbinv_stop_relative) if is_none(umbinv_domain): raise ValueError("Required parameter 'umbinv_domain' not set") if is_none(umbinv_match): raise ValueError("Required parameter 'umbinv_match' not set") yield StatusMessage("Starting...") domain = None process_result = {} params = { "domain": umbinv_domain.strip(), "start_epoch": umbinv_start_epoch, "match": str(umbinv_match), "start_relative": umbinv_start_relative, "stop_epoch": umbinv_stop_epoch, "stop_relative": umbinv_stop_relative } validate_params(params) process_params(params, process_result) if "_domain" not in process_result: raise ValueError( "Parameter 'umbinv_domain' was not processed correctly") else: domain = process_result.pop("_domain") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.domain_volume(domain, **omit_params(params, ["domain"])) dates_converted = [] for d in rtn["dates"]: try: secs = int(d) / 1000 ts_readable = datetime.fromtimestamp(secs).strftime( '%Y-%m-%d %H:%M:%S') dates_converted.append(ts_readable) except ValueError: yield FunctionError( 'timestamp value incorrectly specified') rtn["dates_converted"] = dates_converted query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') results = { "domain_volume": json.loads(json.dumps(rtn)), "domain_name": domain, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'domain_volume' results for domain '{}'.".format( domain)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_classifiers_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Classifiers.""" try: # Get the function parameters: umbinv_domain = kwargs.get("umbinv_domain") # text log = logging.getLogger(__name__) log.info("umbinv_domain: %s", umbinv_domain) if is_none(umbinv_domain): raise ValueError("Required parameter 'umbinv_domain' not set.") yield StatusMessage("Starting...") domain = None process_result = {} params = {"domain": umbinv_domain.strip()} validate_params(params) process_params(params, process_result) if "_domain" not in process_result: raise ValueError( "Parameter 'umbinv_domain' was not processed correctly") else: domain = process_result.pop("_domain") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url) yield StatusMessage("Running Cisco Investigate query...") classifiers_res = True info_res = True # Run against 'classifiers' endpoint rtn_classifiers = rinv.classifiers_classifiers(domain) # Run against 'info' endpoint rtn_info = rinv.classifiers_info(domain) query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if ("securityCategories" in rtn_classifiers and not rtn_classifiers["securityCategories"]) and \ ("attacks" in rtn_classifiers and not rtn_classifiers["attacks"]) and \ ("threatTypes" in rtn_classifiers and not rtn_classifiers["threatTypes"]): classifiers_res = False if "firstQueried" in rtn_info and rtn_info["firstQueried"] is None: info_res = False else: # Make 'firstQueried' more readable fq = rtn_info["firstQueried"] try: secs = int(fq) / 1000 fq_readable = datetime.fromtimestamp(secs).strftime( '%Y-%m-%d %H:%M:%S') rtn_info["first_queried_converted"] = fq_readable except ValueError: yield FunctionError( 'timestamp value incorrectly specified') if not classifiers_res and not info_res: log.debug(json.dumps(rtn_classifiers)) log.debug(json.dumps(rtn_info)) results = {} yield StatusMessage( "No Results returned for domain '{}'.".format(domain)) else: # Add "query_execution_time" and "domain_name" to result to facilitate post-processing. results = { "classifiers_classifiers": json.loads(json.dumps(rtn_classifiers)), "classifiers_info": json.loads(json.dumps(rtn_info)), "domain_name": domain, "query_execution_time": query_execution_time } yield StatusMessage( "Returning 'classifiers and info' results for domain '{}'." .format(domain)) yield StatusMessage("done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_domain_status_and_category_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Domain Status and Categorization.""" try: # Get the function parameters: umbinv_domains = kwargs.get("umbinv_domains") # text umbinv_showlabels = kwargs.get("umbinv_showlabels") # boolean umbinv_status_endpoint = self.get_select_param( kwargs.get("umbinv_status_endpoint") ) # select, values: "categorization", "categories" log = logging.getLogger(__name__) log.info("umbinv_domains: %s", umbinv_domains) log.info("umbinv_showlabels: %s", umbinv_showlabels) log.info("umbinv_status_endpoint: %s", umbinv_status_endpoint) if is_none(umbinv_status_endpoint): raise ValueError( "Required parameter 'umbinv_status_endpoint' not set") if is_none(umbinv_domains ) and umbinv_status_endpoint == "categorization": raise ValueError( "Parameter 'umbinv_domains' should be set if 'umbinv_status_endpoint' has value 'categories'." ) if not is_none( umbinv_domains) and umbinv_status_endpoint == "categories": raise ValueError( "Parameter 'umbinv_domains' should not be set if 'umbinv_status_endpoint' has value 'categories'." ) yield StatusMessage("Starting...") domains = None process_result = {} params = { "domains": umbinv_domains, "showlabels": umbinv_showlabels, "status_endpoint": umbinv_status_endpoint } # Reset 'domains' and 'showlabels' param if inmput paramater set. if not is_none(umbinv_domains): params.setdefault("domains", umbinv_domains.strip()) if umbinv_showlabels: params.setdefault('showlabels', None) validate_params(params) process_params(params, process_result) if umbinv_status_endpoint == "categorization": if "_domains" not in process_result: raise ValueError( "Parameter 'umbinv_domains' was not processed correctly" ) else: domains = process_result.pop("_domains") api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") if (umbinv_status_endpoint == "categories"): cat_keys = [] # Add metadata of "query_execution_time", "min_id" and "max_id" keys to make it easier in post-processing. rtn = rinv.categories() query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') for c in rtn: cat_keys.append(c) cat_keys_int = list(map(int, cat_keys)) max_cat_keys = max(cat_keys_int) results = { "categories": json.loads(json.dumps(rtn)), "min_id": min(cat_keys_int), "max_id": max(cat_keys_int), "query_execution_time": query_execution_time } yield StatusMessage("Returning 'categories' list results.") elif (umbinv_status_endpoint == "categorization"): dom_list = [] if domains is not None: rtn = rinv.categorization(domains, params["showlabels"]) for d in rtn: dom_list.append(d) query_execution_time = datetime.now().strftime( '%Y-%m-%d %H:%M:%S') # Add "query_execution_time" and "domains" key to result to facilitate post-processing. results = { "statuses": json.loads(json.dumps(rtn)), "domains": dom_list, "query_execution_time": query_execution_time } yield StatusMessage( "Returning categorization 'statuses' results for domains '{}'." .format(dom_list)) yield StatusMessage("Done...") log.debug(json.dumps(results)) #Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()
def _umbrella_threat_grid_samples_function(self, event, *args, **kwargs): """Function: Resilient Function : Cisco Umbrella Investigate for Threat Grid samples for domain, IP or URL resource.""" try: # Get the function parameters: umbinv_resource = kwargs.get("umbinv_resource") # text umbinv_limit = kwargs.get("umbinv_limit") # number umbinv_offset = kwargs.get("umbinv_offset") # number umbinv_sortby = kwargs.get("umbinv_sortby") # text log = logging.getLogger(__name__) log.info("umbinv_resource: %s", umbinv_resource) log.info("umbinv_limit: %s", umbinv_limit) log.info("umbinv_offset: %s", umbinv_offset) log.info("umbinv_sortby: %s", umbinv_sortby) if is_none(umbinv_resource): raise ValueError("Required parameter 'umbinv_resource' not set") yield StatusMessage("Starting...") res = None res_type = None process_result = {} params = {"resource": umbinv_resource.strip(), "limit": umbinv_limit, "sortby": umbinv_sortby, "offset": umbinv_offset} validate_params(params) process_params(params, process_result) if "_res" not in process_result or "_res_type" not in process_result: raise ValueError("Parameter 'umbinv_resource' was not processed correctly") else: res = process_result.pop("_res") res_type = process_result.pop("_res_type") if res_type != "domain_name" and res_type != "ip_address" and res_type != "url": raise ValueError("Parameter 'umbinv_resource' was an incorrect type '{}', should be a 'domain name', " "an 'ip address' or a 'url'.".format(res_type)) api_token = self.options.get("api_token") base_url = self.options.get("base_url") rinv = ResilientInv(api_token, base_url, proxies=self.proxies) yield StatusMessage("Running Cisco Investigate query...") rtn = rinv.samples(res, **omit_params(params, ["resource", "resource_type"])) if "error" in rtn: log.debug(json.dumps(rtn)) yield StatusMessage("Investigate returned 'error' status: '{}'.".format(rtn["error"])) results = {} elif len(rtn) == 0 or ("samples" in rtn and len(rtn["samples"]) == 0): log.debug(json.dumps(rtn)) yield StatusMessage("No Results returned for resource '{}'.".format(res)) results = {} else: query_execution_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # Make each sample 'firstSeen' and "lastSeen" property more readable. for i in range(len(rtn["samples"])): fs = rtn["samples"][i]["firstSeen"] ls = rtn["samples"][i]["lastSeen"] try: secs = int(fs) / 1000 fs_readable = datetime.fromtimestamp(secs).strftime('%Y-%m-%d %H:%M:%S') rtn["samples"][i]["first_seen_converted"] = fs_readable secs = int(ls) / 1000 ls_readable = datetime.fromtimestamp(secs).strftime('%Y-%m-%d %H:%M:%S') rtn["samples"][i]["last_seen_converted"] = ls_readable except ValueError: yield FunctionError('Timestamp value incorrectly specified') # Add "query_execution_time" and "domains" key to result to facilitate post-processing. results = {"thread_grid_samples": json.loads(json.dumps(rtn)), "resource_name": params["resource"], "query_execution_time": query_execution_time} yield StatusMessage("Returning 'thread_grid_samples' results for resource '{}'.".format(res)) yield StatusMessage("Done...") log.debug(json.dumps(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: log.exception("Exception in Resilient Function.") yield FunctionError()