def perform_add_to_campaign(ids, action): demisto.debug('starting add to campaign') campaign_id = demisto.incident()['id'] campaign_incident_context = demisto.executeCommand('getContext', {'id': campaign_id}) demisto.debug(f'got incident context: {campaign_incident_context}') if isError(campaign_incident_context): return_error(COMMAND_ERROR_MSG.format(action=action, ids=','.join(ids), error=get_error(campaign_incident_context))) incident_context = demisto.dt(campaign_incident_context, 'Contents.context.EmailCampaign.incidents') if isinstance(incident_context, dict) or isinstance(incident_context, str): incident_context = [incident_context] for incident_id in ids: search_path = f'Contents.context.EmailCampaign.LowerSimilarityIncidents(val.id=={incident_id})' similar_incident_data = demisto.dt(campaign_incident_context, search_path) if similar_incident_data: similar_incident_data = similar_incident_data[0] _add_campaign_to_incident(incident_id, campaign_id) # Add the incident to context under "incidents": incident_context.append(similar_incident_data) _remove_incident_from_lower_similarity_context(campaign_incident_context, ids) res = demisto.executeCommand('SetByIncidentId', {'key': 'EmailCampaign.incidents', 'value': incident_context}) if is_error(res): return_error('Failed to change current context. Error details:\n{}'.format(get_error(res))) return COMMAND_SUCCESS.format(action=action, ids=','.join(ids))
def fill_nested_fields(incidents_df: pd.DataFrame, incidents: List, *list_of_field_list: List[str], keep_unique_value=False) -> \ pd.DataFrame: """ Handle nested fields by concatening values for each sub list of the field :param incidents_df: DataFrame of incidents :param incidents: List of incident :param list_of_field_list: field which can be nested. Can be also no nested field and will remain the same :return: DataFrame with nested field columns updated """ for field_type in list_of_field_list: for field in field_type: if '.' in field: if isinstance(incidents, list): value_list = [wrapped_list(demisto.dt(incident, field)) for incident in incidents] if not keep_unique_value: value_list = [' '.join( # type: ignore set( list( filter(lambda x: x not in ['None', None, 'N/A'], x) ) ) ) for x in value_list] else: value_list = [most_frequent(list(filter(lambda x: x not in ['None', None, 'N/A'], x))) for x in value_list] else: value_list = wrapped_list(demisto.dt(incidents, field)) value_list = ' '.join( # type: ignore set(list(filter(lambda x: x not in ['None', None, 'N/A'], value_list)))) # type: ignore incidents_df[field] = value_list return incidents_df
def fill_nested_fields(incidents_df: pd.DataFrame, incidents: pd.DataFrame, *list_of_field_list: List[str]) -> \ pd.DataFrame: for field_type in list_of_field_list: for field in field_type: if '.' in field: if isinstance(incidents, list): value_list = [ wrapped_list(demisto.dt(incident, field)) for incident in incidents ] value_list = [ ' '.join( set( list( filter( lambda x: x not in ['None', None, 'N/A'], x)))) for x in value_list ] else: value_list = wrapped_list(demisto.dt(incidents, field)) value_list = ' '.join( # type: ignore set( list( filter( lambda x: x not in ['None', None, 'N/A'], value_list)))) # type: ignore incidents_df[field] = value_list return incidents_df
def query_command(): relevance = demisto.args().get('relevance') results = query(relevance) if results is None: demisto.results('No results') sys.exit(0) output = demisto.dt(results, 'Result.Answer.#text') if not isinstance(output, list): output = [output] demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['json'], 'Contents': results, 'HumanReadable': tableToMarkdown('Query Results: {}'.format(relevance), output, ['Results']), 'EntryContext': { 'Bigfix.QueryResults': output } })
def template_params(self, paramsStr): """ Translate the template params if they exist from the context """ actualParams = {} if paramsStr: try: params = json.loads(paramsStr) except ValueError as e: return_error('Unable to parse templateParams: {}'.format( str(e))) # Build a simple key/value for p in params: if params[p].get('value'): actualParams[p] = params[p]['value'] elif params[p].get('key'): actualParams[p] = demisto.dt(demisto.context(), params[p]['key']) return actualParams else: return None
def delete_group_command(client: MsGraphClient, args: Dict) -> Tuple[str, Dict, Dict]: """Delete a group by group id and return outputs in Demisto's format Args: client: Client object with request args: Usually demisto.args() Returns: Outputs. """ group_id = str(args.get('group_id')) client.delete_group(group_id) # get the group data from the context group_data = demisto.dt( demisto.context(), f'{INTEGRATION_CONTEXT_NAME}(val.ID === "{group_id}")') if isinstance(group_data, list): group_data = group_data[0] # add a field that indicates that the group was deleted group_data['Deleted'] = True # add a field with the members to the group entry_context = { f'{INTEGRATION_CONTEXT_NAME}(val.ID === obj.ID)': group_data } human_readable = f'Group: "{group_id}" was deleted successfully.' return human_readable, entry_context, NO_OUTPUTS
def delete_ticket_command(client, args) -> Tuple[str, dict, dict]: """Function which deleted a specific ticket by ticket id. Args: client : Integretion client which communicates with the api. args: Users arguments of the command. Returns: human readable, context, raw response of this command. """ ticket_id = args.get('ticket_id') try: response = client.delete_ticket_request(ticket_id) except Exception as e: raise DemistoException(e) if response.get('Result') == 'Success': context = {} old_context = demisto.dt(demisto.context(), f'QuestKace.Ticket(val.ID === {ticket_id})') if old_context: if isinstance(old_context, list): old_context = old_context[0] old_context['IsDeleted'] = True context = {'QuestKace.Ticket(val.ID === obj.ID)': old_context} return f'Ticket was deleted successfully. Ticket number {ticket_id}', context, {} else: raise DemistoException('Error while deleting the ticket.')
def policy_delete_command(client: AzureWAFClient, **args: Dict[str, str]): """ Gets a policy name and resource group (or taking instance's default) and delete the policy from the resource group. """ policy_name = str(args.get('policy_name', '')) resource_group_name = str( args.get('resource_group_name', client.resource_group_name)) # policy_path is unique and used as unique id in the product. policy_id = f'/{SUBSCRIPTION_PATH.format(client.subscription_id)}/' \ f'{RESOURCE_PATH.format(resource_group_name)}/{POLICY_PATH}/{policy_name}' status = client.delete_policy(policy_name, resource_group_name) md = "" context = None if status.status_code in [200, 202]: old_context = demisto.dt(demisto.context(), f'AzureWAF.Policy(val.id === "{policy_id}")') # updating the context with deleted policy. if old_context: if isinstance(old_context, list): old_context = old_context[0] old_context['IsDeleted'] = True context = {'AzureWAF.Policy(val.id === obj.id)': old_context} md = f"Policy {policy_name} was deleted successfully." if status.status_code == 204: md = f"Policy {policy_name} was not found." return CommandResults(outputs=context, readable_output=md)
def get(self, key: Optional[str], node: Optional[Any] = None, ignore_errors=False) -> Any: """ Get the context value given the key :param key: The dt expressions (string within ${}). :param node: The current node. :param ignore_errors: Set to True to ignore errors, otherwise False. :return: The value. """ if key is not None: dx = self.__demisto if key != '..' and not key.startswith('..=') and key.startswith( '..'): dx = node key = key[2:] elif key != '.' and not key.startswith('.=') and key.startswith( '.'): dx = self.__value key = key[1:] if not key or key == '.': return dx try: return demisto.dt(dx, key) except Exception: if not ignore_errors: raise return None
def file_upload_raw(body, file_entry_id, filename_to_upload): uri = 'php/fileupload.php' if not filename_to_upload: # first priority for the file name is user's argument # second priority for the file name is the file name in the context filename_dq = demisto.dt( demisto.context(), 'File(val=val.EntryID=="' + file_entry_id + '")=val.Name') if filename_dq and filename_dq[0]: filename_to_upload = filename_dq else: # last priority for the file name is demisto's entryID filename_to_upload = file_entry_id with open(demisto.getFilePath(file_entry_id)['path'], 'rb') as file_to_upload: file_up = {'amas_filename': file_to_upload} result = http_request( uri, 'post', API_HEADERS, body, '', files=file_up, ) if not result['success']: return_error('Failed to upload sample due to: ' + result['errorMessage']) return result
def list_members_command(client: MsGraphClient, args: Dict) -> Tuple[str, Dict, Dict]: """List a group members by group id. return outputs in Demisto's format. Args: client: Client object with request args: Usually demisto.args() Returns: Outputs. """ group_id = str(args.get('group_id')) next_link = args.get('next_link') top = args.get('top') filter_ = args.get('filter') members = client.list_members(group_id, next_link, top, filter_) if not members['value']: human_readable = f'The group {group_id} has no members.' return human_readable, NO_OUTPUTS, NO_OUTPUTS members_readable, members_outputs = parse_outputs(members['value']) # get the group data from the context group_data = demisto.dt( demisto.context(), f'{INTEGRATION_CONTEXT_NAME}(val.ID === "{group_id}")') if not group_data: return_error( 'Could not find group data in the context, please run "!msgraph-groups-get-group" to retrieve group data.' ) if isinstance(group_data, list): group_data = group_data[0] if '@odata.nextLink' in members: next_link_response = members['@odata.nextLink'] group_data[ 'Members'] = members_outputs # add a field with the members to the group group_data['MembersNextLink'] = next_link_response entry_context = { f'{INTEGRATION_CONTEXT_NAME}(val.ID === obj.ID)': group_data } title = f'Group {group_id} members ' \ f'(Note that there are more results. Please use the next_link argument to see them. The value can be ' \ f'found in the context under {INTEGRATION_CONTEXT_NAME}.MembersNextLink): ' else: group_data[ 'Members'] = members_outputs # add a field with the members to the group entry_context = { f'{INTEGRATION_CONTEXT_NAME}(val.ID === obj.ID)': group_data } title = f'Group {group_id} members:' human_readable = tableToMarkdown( name=title, t=members_readable, headers=['ID', 'Display Name', 'Job Title', 'Mail'], removeNull=True) return human_readable, entry_context, members
def domain_delete_command(client: Client, args: dict) -> CommandResults: """ :param client: Cisco Umbrella Client for the api request. :param args: args from the user for the command. :returns (str) confirmation or error regarding deleting a domain. """ response = {} domain_name = args.get('name', '') domain_id = args.get('id', '') if not domain_name and not domain_id: raise DemistoException( 'Both domain name and domain id do not exist, Please supply one of them in order to set the domain to ' 'delete command') try: response = client.delete_domains(domain_id=domain_id, domain_name=domain_name) except Exception as e: # When deleting a domain by id and the id does not exist. if any(exp in str(e) for exp in ["Domain not in domain list", "Not Found"]): return CommandResults( readable_output= 'The domain was not found in the list, Please insert an existing domain name or id.' ) if domain_name: curr_context = demisto.dt( demisto.context(), f'UmbrellaEnforcement.Domains(val.name == "{domain_name}")') else: curr_context = demisto.dt( demisto.context(), f'UmbrellaEnforcement.Domains(val.id == "{domain_id}")') if curr_context: if isinstance(curr_context, list): curr_context = curr_context[0] curr_context['IsDeleted'] = True if response and int(response.status_code) == 204: # type: ignore message = f"{domain_name if domain_name else domain_id} domain was removed from blacklist" else: # When deleting a domain by name, if name does not exist the returned code is 200 but the response is empty. message = f"{domain_name if domain_name else domain_id} domain not in the blacklist or Error" return CommandResults(readable_output=message, outputs_prefix='UmbrellaEnforcement.Domains', outputs_key_field='id', outputs=curr_context)
def extract_dt(dtstr: str, dx: Optional[Dict[str, Any]]) -> Any: """ Extract dt expression :param dtstr: The dt expressions (string within ${}). :param dx: The demisto context. :return: The value extracted. """ return demisto.dt(dx, dtstr) if dx else dtstr
def build_grid(context_path: str, keys: List[str], columns: List[str], unpack_nested_elements: bool) -> pd.DataFrame: """ Build new DateFrame from current context retrieved by DT. There are 3 cases: 1. DT returns dict - In this case we will insert it in the table as key, value in each row. 2. DT returns list - In this case each entry in the list will represent a row. 3. DT return unknown obj (str..) - return empty list. Args: context_path: DT context path. keys: Keys to be included columns: Grid columns name. unpack_nested_elements: True for unpacking nested elements, False otherwise. Returns: pd.DataFrame: New Table include data from Entry Context """ # Retrieve entry context data entry_context_data = demisto.dt(demisto.context(), context_path) # Validate entry context structure data_type = validate_entry_context(context_path, entry_context_data, keys, unpack_nested_elements) demisto.debug('context object is valid. starting to build the grid.') # Building new Grid if unpack_nested_elements: # Handle entry context as dict, with unpacking of nested elements table = pd.DataFrame( unpack_all_data_from_dict(entry_context_data, keys, columns)) table.rename(columns=dict(zip(table.columns, columns)), inplace=True) elif data_type == 'list': # Handle entry context as list of value table = pd.DataFrame(entry_context_data) table.rename(columns=dict(zip(table.columns, columns)), inplace=True) elif isinstance(entry_context_data, list): # Handle entry context as list of dicts entry_context_data = [ filter_dict(item, keys, len(columns)) for item in entry_context_data ] table = pd.DataFrame(entry_context_data) table.rename(columns=dict(zip(table.columns, columns)), inplace=True) elif isinstance(entry_context_data, dict): # Handle entry context key-value of primitive types option # If the keys arg is * it means we don't know which keys we have in the context - Will create key-value table. if keys == ['*']: entry_context_data = filter_dict(entry_context_data, keys).items() table = pd.DataFrame(entry_context_data, columns=columns[:2]) else: entry_context_data = filter_dict(entry_context_data, keys) table = pd.DataFrame([entry_context_data]) table.rename(columns=dict(zip(table.columns, columns)), inplace=True) else: table = [] return table
def get_file_details(self): file_path_data = demisto.getFilePath(demisto.args().get("entryID")) self.file_path = file_path_data.get('path') self.file_name = file_path_data.get('name') file_entry = demisto.dt(self.get_context(), "File(val.EntryID === '{}')".format(demisto.args().get('entryID'))) if isinstance(file_entry, list): file_entry = file_entry[0] self.file_type = file_entry.get("Type")
def _remove_incident_from_lower_similarity_context(incident_context, incident_ids): lower_similarity_incident_context = demisto.dt(incident_context, 'Contents.context.EmailCampaign.LowerSimilarityIncidents') lower_similarity_incident_context = list(filter( lambda x: x.get('id') not in incident_ids, lower_similarity_incident_context)) demisto.executeCommand('DeleteContext', {'key': 'EmailCampaign.LowerSimilarityIncidents'}) res = demisto.executeCommand('SetByIncidentId', {'key': 'EmailCampaign.LowerSimilarityIncidents', 'value': lower_similarity_incident_context}) if is_error(res): return_error('Failed to change context. Error details:\n{}'.format(get_error(res)))
def get_file_details(self): cmd_res = demisto.executeCommand('getFilePath', {'id': demisto.args().get("entryID")}) file_res = cmd_res[0] if isError(file_res): file_res["Contents"] = "Error fetching entryID: " + file_res["Contents"] self.res = file_res else: # Got file path: self.file_path = file_res.get('Contents').get('path') self.file_name = file_res.get('Contents').get('name') file = demisto.dt(demisto.context(), "File(val.EntryID === '{}')".format(demisto.args().get('entryID'))) if isinstance(file, list): file = file[0] self.file_type = file.get("Type")
def publish(): now_utc = datetime.now(timezone.utc) object_id = demisto.getArg('object.id') roles = execute_command('getRoles', {}) execute_command( 'setThreatIntelReport', { 'id': object_id, 'xsoarReadOnlyRoles': demisto.dt(roles, 'DemistoRoles.name'), 'reportstatus': 'Published', 'published': now_utc.isoformat(), }, ) demisto.results('ok')
def get(self, key: Optional[str] = None,) -> Any: """ Get the context value given the key :param key: The dt expressions (string within ${}) :return: The value. """ if key is not None: dx = self.__demisto if key != '.' and key.startswith('.'): dx = self.__value key = key[1:] if not key or key == '.': return dx elif isinstance(dx, (list, dict)): return demisto.dt(dx, key) return None
def template_params(): """ Translate the template params if they exist from the context """ actualParams = {} paramsStr = demisto.getArg('templateParams') if paramsStr: try: params = json.loads(paramsStr) except ValueError as e: return_error_mail_sender('Unable to parse templateParams: %s' % (str(e))) # Build a simple key/value for p in params: if params[p].get('value'): actualParams[p] = params[p]['value'] elif params[p].get('key'): actualParams[p] = demisto.dt(demisto.context(), params[p]['key']) return actualParams
def concat_text_fields(data, target_field, text_fields): for d in data: text = '' for fields in text_fields: for field in fields.strip().split("|"): field = field.strip() if "." in field: value = demisto.dt(d, field) if type(value) is list and len(value) > 0: value = value[0] else: value = d.get(field) or d.get(field.lower(), '') if value and isinstance(value, str): text += value text += ' ' break text = text.strip() d[target_field] = text return data
def hash_incident(): args = demisto.args() fieldsToHash_list = args.pop('fieldsToHash', '').split(',') fieldsToHash_list = set([x.strip() for x in fieldsToHash_list if x]) res = demisto.executeCommand('GetIncidentsByQuery', args) if is_error(res): return_error(get_error(res)) else: entry = res[0] incident_list = json.loads(entry['Contents']) new_incident_list = [] for incident in incident_list: for field in fieldsToHash_list: if field in incident: incident[field] = hash_multiple(incident.get(field)) new_ctx = {} context_keys = [x for x in demisto.args().get('contextKeys', '').split(",") if x] if context_keys: ctx = get_context(incident['id']) for key in context_keys: if key in ctx: new_ctx[key] = demisto.dt(ctx, key) incident['context'] = new_ctx new_incident_list.append(incident) file_name = str(uuid.uuid4()) output_format = args['outputFormat'] if output_format == 'pickle': data_encoded = pickle.dumps(new_incident_list) elif output_format == 'json': data_encoded = json.dumps(new_incident_list) else: return_error("Invalid output format: %s" % output_format) entry = fileResult(file_name, data_encoded) entry['Contents'] = new_incident_list entry['HumanReadable'] = "Fetched %d incidents successfully by the query: %s" % (len(new_incident_list), args.get('query')) entry['EntryContext'] = { 'HashIncidentsFields': { 'Filename': file_name, 'FileFormat': output_format, } } return entry
def upload_file_command(): ticket_type = get_table_name(demisto.args().get('ticket_type')) ticket_id = demisto.args()['id'] file_id = demisto.args()['file_id'] file_name = demisto.args().get('file_name', demisto.dt(demisto.context(), "File(val.EntryID=='" + file_id + "').Name")) file_name = file_name[0] if isinstance(file_name, list) else file_name res = upload_file(ticket_id, file_id, file_name, ticket_type) if not res or 'result' not in res or not res['result']: return_error('Unable to retrieve response') hr = { 'Filename': res['result'].get('file_name'), 'Download link': res['result'].get('download_link'), 'System ID': res['result'].get('sys_id') } context = { 'ID': ticket_id, 'File': {} } context['File']['Filename'] = res['result'].get('file_name') context['File']['Link'] = res['result'].get('download_link') context['File']['SystemID'] = res['result'].get('sys_id') entry = { 'Type': entryTypes['note'], 'Contents': res, 'ContentsFormat': formats['json'], 'ReadableContentsFormat': formats['markdown'], 'HumanReadable': tableToMarkdown('File uploaded successfully', hr), 'EntryContext': { 'ServiceNow.Ticket(val.ID===obj.ID)': context, 'Ticket(val.ID===obj.ID)': context } } return entry
def build_grid(context_path: str, keys: List[str], columns: List[str]) -> pd.DataFrame: """ Build new DateFrame from current context retrieved by DT. There is 3 cases: 1. DT returns dict (list including 1 item only)- In this case we will insert it in the table as key, value each row. 2. DT returns list - In this case each entry in the list will represent a row. 3. DT return unknown obj (str..) - return empty list. Args: context_path: DT context path. keys: Keys to be included columns: Grid columns name. Returns: pd.DataFrame: New Table include data from Entry Context """ # Retrieve entry context data entry_context_data = demisto.dt(demisto.context(), context_path) # Validate entry context structure validate_entry_context(entry_context_data, keys) # Building new Grid if len(entry_context_data) > 1: # Handle entry context list option entry_context_data = [ filter_dict(item, keys, len(columns)) for item in entry_context_data ] table = pd.DataFrame(entry_context_data) table.rename(columns=dict(zip(table.columns, columns)), inplace=True) elif len(entry_context_data) == 1 and isinstance(entry_context_data[0], dict): # Handle entry context key-vlaue option entry_context_data = filter_dict(entry_context_data[0], keys).items() table = pd.DataFrame(entry_context_data, columns=columns[:2]) else: table = [] return table
def map_scim(scim): try: scim = json.loads(scim) except Exception: pass if type(scim) != dict: raise Exception('Provided client data is not JSON compatible') mapping = { "userName": "******", "email": "emails(val.primary && val.primary==true).[0].value", "first_name": "name.givenName", "last_name": "name.familyName", "id": "id", "timezone": "timezone", } parsed_scim = dict() for k, v in mapping.items(): try: parsed_scim[k] = demisto.dt(scim, v) except Exception: parsed_scim[k] = None return parsed_scim
def search_destination_domains(client, organizationId, destinationListId, domains): demisto.debug(f'domains: {domains}') page_limit, page, r = get_first_page_of_destinations( client, organizationId, destinationListId) destination_domains = [] while r.get('meta').get('total') <= page_limit: if r.get('meta').get('total') == 0: # currently, r.meta.total continually returns 100 until the last page, where it will return a value <= 100 # and will never return 0. but if it does, then it's likely the API changed uri = f'/{organizationId}/destinationlists/{destinationListId}/destinations' demisto.info( f'Unexpected "total" value of 0 returned from Umbrella {uri} API call' ) break destination_domains += r.get('data') page += 1 r = client.get_destinations(organizationId, destinationListId, params={ 'page': page, 'limit': page_limit }) destination_domains_found = [] for domain in domains: if domain in demisto.dt(destination_domains, 'destination'): destination_domains_found += [ d for d in destination_domains if d.get('destination') == domain ] demisto.debug( f'destination_domains_found: {destination_domains_found}') return destination_domains_found
dt = get_arg_and_encode('dt') pollingCommand = demisto.getArg('pollingCommand') pollingCommandArgName = demisto.getArg('pollingCommandArgName') tag = get_arg_and_encode('tag') playbookId = ' playbookId="{}"'.format(demisto.getArg('playbookId') if 'playbookId' in demisto.args() else '') interval = int(demisto.getArg('interval')) timeout = int(demisto.getArg('timeout')) args_names = demisto.getArg('additionalPollingCommandArgNames').strip() args_values = get_arg_and_encode('additionalPollingCommandArgValues').strip() if interval <= 0 or timeout <= 0: return_error("Interval and timeout must be positive numbers") # Verify correct dt path (does not verify condition!) if not demisto.dt(demisto.context(), dt): if not demisto.dt(demisto.context(), re.sub('\(.*\)', '', dt)): return_error("Incorrect dt path: no ids found") demisto.results("Warning: no ids matching the dt condition were found.\nVerify that the condition is correct and " "that all ids have finished running.") command_string = '''!GenericPollingScheduledTask pollingCommand="{0}" pollingCommandArgName="{1}"{2} ids="{3}" \ pendingIds="{4}" interval="{5}" timeout="{6}" tag="{7}" additionalPollingCommandArgNames="{8}" \ additionalPollingCommandArgValues="{9}"'''.format(pollingCommand, pollingCommandArgName, playbookId, ids.replace('"', r'\"'), dt.replace('"', r'\"'), interval, timeout, tag, args_names, args_values) res = demisto.executeCommand("ScheduleCommand", { 'command': command_string, 'cron': '*/{} * * * *'.format(interval), 'times': 1 })
def get_endpoint_details(computer_id): fullurl = BASE_URL + '/api/computer/{}'.format(computer_id) res = requests.get(fullurl, auth=(USERNAME, PASSWORD), verify=VERIFY_CERTIFICATE) if res.status_code < 200 or res.status_code >= 300: return_error( 'Failed to get computer {}.\nRequest URL: {}\nStatusCode: {}\nResponse Body: {}' .format(computer_id, fullurl, res.status_code, res.content)) raw_endpoint = json.loads(xml2json(res.content)) if not raw_endpoint or 'BESAPI' not in raw_endpoint: return None raw_endpoint = demisto.get(raw_endpoint, 'BESAPI.Computer') endpoint = { 'ID': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "ID")=val["#text"]')), 'Resource': demisto.get(raw_endpoint, '@Resource'), 'LastReportTime': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Last Report Time")=val["#text"]')), 'ActiveDirectoryPath': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Active Directory Path")=val["#text"]' )), 'AgentType': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "Agent Type")=val["#text"]')), 'AgentVersion': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Agent Version")=val["#text"]')), 'BESRelaySelectionMethod': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "BES Relay Selection Method")=val["#text"]' )), 'BESRelayServiceInstalled': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "BES Relay Selection Method")=val["#text"]' )), 'BESRootServer': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "BES Root Server")=val["#text"]')), 'BIOS': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "BIOS")=val["#text"]')), 'CPU': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "CPU")=val["#text"]')), 'ClientSettings': demisto.dt(raw_endpoint, 'Property(val["@Name"] == "Client Settings")=val["#text"]'), 'ComputerName': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Computer Name")=val["#text"]')), 'ComputerType': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Computer Type")=val["#text"]')), 'DNSName': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "DNS Name")=val["#text"]')), 'IPAddress': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "IP Address")=val["#text"]')), 'DeviceType': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Device Type")=val["#text"]')), 'DistancetoBESRelay': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Distance to BES Relay")=val["#text"]' )), 'FreeSpaceonSystemDrive': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Free Space on System Drive")=val["#text"]' )), 'LicenseType': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "License Type")=val["#text"]')), 'Locked': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "Locked")=val["#text"]')), 'OS': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "OS")=val["#text"]')), 'RAM': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "RAM")=val["#text"]')), 'Relay': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "Relay")=val["#text"]')), 'RelayNameOfClient': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Relay Name of Client")=val["#text"]' )), 'SubnetAddress': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Subnet Address")=val["#text"]')), 'SubscribedSites': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Subscribed Sites")=val["#text"]')), 'TotalSizeofSystemDrive': get_first( demisto.dt( raw_endpoint, 'Property(val["@Name"] == "Total Size of System Drive")=val["#text"]' )), 'UserName': get_first( demisto.dt(raw_endpoint, 'Property(val["@Name"] == "User Name")=val["#text"]')) } return endpoint
def build_report_context(report_summary, upload_data, status, threshold, task_id): context = {} # type: dict if report_summary and report_summary['Subject']: subject = report_summary['Subject'] context = { 'DBotScore': { 'Vendor': 'McAfee Advanced Threat Defense', 'Score': 0 } } if 'FileType' in subject: context['DBotScore']['Indicator'] = subject['md5'] context['DBotScore']['Type'] = 'hash' # default threshold for McAfee ATD is 3 if report_summary['Verdict']['Severity'] > threshold: context['DBotScore']['Score'] = 3 if subject['Type'] == 'application/url': context['URL(val.Name == obj.Data)'] = { 'Type': subject['Type'], 'MD5': subject['md5'], 'SHA1': subject['sha-1'], 'SHA256': subject['sha-256'], 'Size': subject['size'], 'Name': subject['Name'], 'Malicious': { 'Vendor': 'McAfee Advanced Threat Defense', 'Description': 'Severity: ' + report_summary['Verdict']['Severity'] } } else: context['File(val.MD5 == obj.MD5)'] = { 'Type': subject['Type'], 'MD5': subject['md5'], 'SHA1': subject['sha-1'], 'SHA256': subject['sha-256'], 'Size': subject['size'], 'Name': subject['Name'], 'Malicious': { 'Vendor': 'McAfee Advanced Threat Defense', 'Description': 'Severity: ' + report_summary['Verdict']['Severity'] } } else: context['DBotScore']['Score'] = 1 else: # detonation did not return any data # retrieve submission url by the task ID, if exist submission_dt = demisto.dt( demisto.context(), 'ATD.Task(val.taskId === "{}")'.format(task_id)) if isinstance(submission_dt, list): submission = submission_dt[0] else: submission = submission_dt if isinstance(submission, dict): if submission.get('url') and len(str(submission.get('url'))) > 0: context['DBotScore']['Type'] = 'application/url' context['DBotScore']['Indicator'] = submission.get('url') else: # if does not exist, submission is a file if submission.get('SHA256') and len(str(submission.get('SHA256'))) > 0: context['DBotScore']['Indicator'] = submission.get('SHA256') context['DBotScore']['Type'] = 'hash' elif submission.get('SHA1') and len(str(submission.get('SHA1'))) > 0: context['DBotScore']['Indicator'] = submission.get('SHA1') context['DBotScore']['Type'] = 'hash' context['IP'] = {} if 'Ips' in report_summary: ip_addresses = [] for i in range(len(report_summary['Ips'])): ip_addresses.append(report_summary['Ips'][i]['Ipv4']) context['IP']['Address'] = ip_addresses if upload_data: context['ATD'] = {} context['ATD']['Task(val.taskId == obj.taskId)'] = { 'status': status, 'taskId': upload_data['taskId'], 'jobId': upload_data['subId'] if 'subId' in upload_data else None, 'messageId': upload_data['messageId'], 'url': upload_data['url'], 'srcIp': upload_data['srcIp'], 'destIp': upload_data['destIp'], 'MD5': upload_data['md5'], 'SHA1': upload_data['sha1'], 'SHA256': upload_data['sha256'], 'Report': { 'Attachments': report_summary['Attachments'] if 'Attachment' in report_summary else None, 'Environment': report_summary['Environment'] if 'Environment' in report_summary else None, 'Ips': report_summary['Ips'] if 'Ips' in report_summary else None, 'Verdict': report_summary['Verdict'] if 'Verdict' in report_summary else None, 'Data': report_summary['Data'] if 'Data' in report_summary else None, 'Selectors': report_summary['Selectors'] if 'Selectors' in report_summary else None } } return context
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 args = demisto.args() value = args["value"] dt = args["dt"] res = demisto.dt(value, dt) return_results(encode_string_results(res))