From 8ad5bf14783d4f7a71703fb5eb9a0f6b84127c9e Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Mon, 6 Mar 2023 10:57:09 -0600 Subject: [PATCH 1/4] AD LDAP Entity Attributes Lookup playbook --- .../AD_LDAP_Entity_Attribute_Lookup.json | 682 ++++++++++++++++++ playbooks/AD_LDAP_Entity_Attribute_Lookup.png | Bin 0 -> 70571 bytes playbooks/AD_LDAP_Entity_Attribute_Lookup.py | 610 ++++++++++++++++ playbooks/AD_LDAP_Entity_Attribute_Lookup.yml | 23 + 4 files changed, 1315 insertions(+) create mode 100644 playbooks/AD_LDAP_Entity_Attribute_Lookup.json create mode 100644 playbooks/AD_LDAP_Entity_Attribute_Lookup.png create mode 100644 playbooks/AD_LDAP_Entity_Attribute_Lookup.py create mode 100644 playbooks/AD_LDAP_Entity_Attribute_Lookup.yml diff --git a/playbooks/AD_LDAP_Entity_Attribute_Lookup.json b/playbooks/AD_LDAP_Entity_Attribute_Lookup.json new file mode 100644 index 0000000000..b7b18a7fcc --- /dev/null +++ b/playbooks/AD_LDAP_Entity_Attribute_Lookup.json @@ -0,0 +1,682 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Attribute Lookup", + "coa": { + "data": { + "description": "Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device.", + "edges": [ + { + "id": "port_3_to_port_1", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_10_to_port_3", + "sourceNode": "10", + "sourcePort": "10_out", + "targetNode": "3", + "targetPort": "3_in" + }, + { + "id": "port_8_to_port_10", + "sourceNode": "8", + "sourcePort": "8_out", + "targetNode": "10", + "targetPort": "10_in" + }, + { + "id": "port_0_to_port_14", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "14", + "targetPort": "14_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_14_to_port_2", + "sourceNode": "14", + "sourcePort": "14_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "id": "port_15_to_port_16", + "sourceNode": "15", + "sourcePort": "15_out", + "targetNode": "16", + "targetPort": "16_in" + }, + { + "id": "port_16_to_port_17", + "sourceNode": "16", + "sourcePort": "16_out", + "targetNode": "17", + "targetPort": "17_in" + }, + { + "id": "port_17_to_port_1", + "sourceNode": "17", + "sourcePort": "17_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_2_to_port_18", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "18", + "targetPort": "18_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_18_to_port_8", + "sourceNode": "18", + "sourcePort": "18_out", + "targetNode": "8", + "targetPort": "8_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_19_to_port_15", + "sourceNode": "19", + "sourcePort": "19_out", + "targetNode": "15", + "targetPort": "15_in" + }, + { + "conditions": [ + { + "index": 1 + } + ], + "id": "port_14_to_port_20", + "sourceNode": "14", + "sourcePort": "14_out", + "targetNode": "20", + "targetPort": "20_in" + }, + { + "id": "port_20_to_port_11", + "sourceNode": "20", + "sourcePort": "20_out", + "targetNode": "11", + "targetPort": "11_in" + }, + { + "id": "port_11_to_port_19", + "sourceNode": "11", + "sourcePort": "11_out", + "targetNode": "19", + "targetPort": "19_in" + } + ], + "hash": "1161e9894971caa9d512c12b7eb803d24bf949bf", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 190, + "y": 0 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionId": 1, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n", + "warnings": {}, + "x": 190, + "y": 1414 + }, + "10": { + "data": { + "action": "run query", + "actionType": "investigate", + "advanced": { + "customName": "get user group attributes", + "customNameId": 0, + "description": "Get details for the groups to which the user belongs.", + "join": [], + "note": "Get details for the groups to which the user belongs." + }, + "connector": "AD LDAP", + "connectorConfigs": [ + "ad_ldap" + ], + "connectorId": "a5730e5d-a396-4695-92c2-35ff391aaf45", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_user_group_attributes", + "id": "10", + "parameters": { + "attributes": "description;name;memberOf;distinguishedName", + "filter": { + "functionId": 1, + "parameters": [ + "merge_user_groups:custom_function:list" + ], + "template": "(|\n%%\n(distinguishedName={0})\n%%\n)\n" + } + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "filter" + }, + { + "data_type": "string", + "default": "sAMAccountName", + "field": "attributes" + } + ], + "type": "action" + }, + "errors": {}, + "id": "10", + "type": "action", + "warnings": {}, + "x": 0, + "y": 1042 + }, + "11": { + "data": { + "action": "run query", + "actionType": "investigate", + "advanced": { + "customName": "get device attributes", + "customNameId": 0, + "description": "Query for the device attributes for filtered playbook inputs.", + "join": [], + "note": "Query for the device attributes for filtered playbook inputs." + }, + "connector": "AD LDAP", + "connectorConfigs": [ + "ad_ldap" + ], + "connectorId": "a5730e5d-a396-4695-92c2-35ff391aaf45", + "connectorVersion": "v1", + "functionId": 3, + "functionName": "get_device_attributes", + "id": "11", + "parameters": { + "attributes": "description;distinguishedName;objectSid;memberOf;name;sAMAccountName", + "filter": "format_device_query:formatted_data.*" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "filter" + }, + { + "data_type": "string", + "default": "sAMAccountName", + "field": "attributes" + } + ], + "type": "action" + }, + "errors": {}, + "id": "11", + "type": "action", + "warnings": {}, + "x": 340, + "y": 506 + }, + "14": { + "data": { + "advanced": { + "customName": "playbook inputs filter", + "customNameId": 0, + "description": "Filter inputs to route inputs to appropriate actions.", + "join": [], + "note": "Filter inputs to route inputs to appropriate actions." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:user", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "user", + "logic": "and" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "!=", + "param": "playbook_input:device", + "value": "None" + } + ], + "conditionIndex": 1, + "customName": "device", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "playbook_inputs_filter", + "id": "14", + "type": "filter" + }, + "errors": {}, + "id": "14", + "type": "filter", + "warnings": { + "config": [ + "Reconfigure invalid datapath." + ] + }, + "x": 230, + "y": 148 + }, + "15": { + "data": { + "advanced": { + "customName": "merge device groups", + "customNameId": 0, + "description": "Merge device groups, from preceding action block results, into a single deduplicated list.", + "join": [], + "note": "Merge device groups, from preceding action block results, into a single deduplicated list." + }, + "customDatapaths": { + "filter_device_results": { + "condition_1:get_device_attributes:action_result.data.*.entries.*.attributes.memberOf": { + "contains": [], + "isCustomDatapath": true, + "label": "condition_1:get_device_attributes:action_result.data.*.entries.*.attributes.memberOf", + "value": "filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.data.*.entries.*.attributes.memberOf" + } + } + }, + "functionId": 3, + "functionName": "merge_device_groups", + "id": "15", + "inputParameters": [ + "filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.data.*.entries.*.attributes.memberof" + ], + "outputVariables": [ + "list" + ], + "type": "code" + }, + "errors": {}, + "id": "15", + "type": "code", + "userCode": "\n group_list = []\n for group in filtered_result_0_data___entries___attributes_memberof:\n group_list.extend(group)\n \n merge_device_groups__list = list(set(group_list))\n\n", + "warnings": {}, + "x": 340, + "y": 864 + }, + "16": { + "data": { + "action": "run query", + "actionType": "investigate", + "advanced": { + "customName": "get device group attributes", + "customNameId": 0, + "description": "Get details for the groups to which the device belongs.", + "join": [], + "note": "Get details for the groups to which the device belongs." + }, + "connector": "AD LDAP", + "connectorConfigs": [ + "ad_ldap" + ], + "connectorId": "a5730e5d-a396-4695-92c2-35ff391aaf45", + "connectorVersion": "v1", + "functionId": 2, + "functionName": "get_device_group_attributes", + "id": "16", + "parameters": { + "attributes": "description;name;memberOf;distinguishedName", + "filter": { + "functionId": 2, + "parameters": [ + "merge_device_groups:custom_function:list" + ], + "template": "(|\n%%\n(distinguishedName={0})\n%%\n)" + } + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "filter" + }, + { + "data_type": "string", + "default": "sAMAccountName", + "field": "attributes" + } + ], + "type": "action" + }, + "errors": {}, + "id": "16", + "type": "action", + "warnings": {}, + "x": 340, + "y": 1042 + }, + "17": { + "data": { + "advanced": { + "customName": "format device outputs", + "customNameId": 0, + "description": "Format a normalized output for each device.", + "join": [], + "note": "Format a normalized output for each device." + }, + "functionId": 4, + "functionName": "format_device_outputs", + "id": "17", + "inputParameters": [ + "filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.data.*.entries.*.attributes", + "filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.parameter.filter", + "get_device_group_attributes:action_result.data.*.entries.*.attributes" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "17", + "type": "code", + "userCode": " import re\n \n format_device_outputs__observable_array = []\n \n def extract_domain_name(dn):\n dn_rex = re.search(r'(DC=.+)', dn)\n if dn_rex:\n dc_list = dn_rex.group(1).replace('DC=', '').split(',')\n return '.'.join(dc_list)\n \n def extract_ou(dn):\n dn_rex = re.search(r'(OU=.+?),DC', dn)\n if dn_rex:\n ou_list = dn_rex.group(1).replace('OU=', '').split(',')\n return ou_list\n \n def extract_pb_input_from_filter(filter_query_list):\n pb_input_list = []\n for query in filter_query_list:\n query_rex = re.search(r'sAMAccountName=([^\\)]+)', query)\n hostname = query_rex.group(1).replace('*', '')\n pb_input_list.append(hostname)\n return pb_input_list\n \n # create dictionary of group attributes\n group_dict = {}\n for group in get_device_group_attributes_result_item_0:\n group_dict[group['distinguishedname']] = group\n \n pb_input_hostname_list = extract_pb_input_from_filter(filtered_result_0_parameter_filter)\n # create normalized output dictionary\n for pb_input, device in zip(pb_input_hostname_list, filtered_result_0_data___entries___attributes):\n device_dict = {\n \"desc\": device['description'],\n \"domain\": extract_domain_name(device['distinguishedname']),\n \"hostname\": device['name'],\n \"name\": device['samaccountname'],\n \"type\": \"Unknown\",\n \"type_id\": 0,\n \"uid\": device['objectsid'] \n }\n \n # use OUs as labels\n ou_list = extract_ou(device['distinguishedname'])\n if ou_list:\n device_dict['labels'] = ou_list\n \n # lookup groups\n group_list = []\n for group in device['memberof']:\n if group_dict.get(group):\n group_details = group_dict[group]\n if not group_details['description']:\n group_details['description'].append(\"None\")\n temp_group_dict = {\n \"type\": \"Domain\",\n \"desc\": group_details['description'][0],\n \"name\": group_details['name'],\n \"privileges\": group_details['memberof'],\n \"uid\": group_details['distinguishedname']\n }\n # drop values with []\n for k,v in temp_group_dict.copy().items():\n if v == []:\n temp_group_dict.pop(k)\n group_list.append(temp_group_dict)\n if group_list:\n device_dict['groups'] = group_list\n\n \n final_output = {\n \"type\": \"host name\",\n \"value\": pb_input,\n \"attributes\": device_dict,\n \"source\": \"AD LDAP\"\n }\n format_device_outputs__observable_array.append(final_output)\n \n # phantom.debug(format_device_outputs__observable_array)\n\n", + "warnings": {}, + "x": 340, + "y": 1236 + }, + "18": { + "data": { + "advanced": { + "customName": "filter user results", + "customNameId": 0, + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "get_user_attributes:action_result.summary.total_objects", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "user results exist", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "filter_user_results", + "id": "18", + "type": "filter" + }, + "errors": {}, + "id": "18", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 684 + }, + "19": { + "data": { + "advanced": { + "customName": "filter device results", + "customNameId": 0, + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "get_device_attributes:action_result.summary.total_objects", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "device results exist", + "logic": "and" + } + ], + "functionId": 3, + "functionName": "filter_device_results", + "id": "19", + "type": "filter" + }, + "errors": {}, + "id": "19", + "type": "filter", + "warnings": {}, + "x": 400, + "y": 684 + }, + "2": { + "data": { + "action": "get attributes", + "actionType": "investigate", + "advanced": { + "customName": "get user attributes", + "customNameId": 0, + "description": "Query for the user attributes for filtered playbook inputs.", + "join": [], + "note": "Query for the user attributes for filtered playbook inputs." + }, + "connector": "AD LDAP", + "connectorConfigs": [ + "ad_ldap" + ], + "connectorId": "a5730e5d-a396-4695-92c2-35ff391aaf45", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_user_attributes", + "id": "2", + "parameters": { + "attributes": "userPrincipalName;mail;accountExpires;name;memberOf;title;department;manager;sAMAccountName;distinguishedName;mobile;ipPhone;homePhone;telephoneNumber;otherMobile;otherIpPhone;otherHomePhone;otherTelephone;whenCreated;objectSid;objectGUID", + "principals": "filtered-data:playbook_inputs_filter:condition_1:playbook_input:user" + }, + "requiredParameters": [ + { + "data_type": "string", + "default": "sAMAccountName", + "field": "attributes" + }, + { + "data_type": "string", + "field": "principals" + } + ], + "type": "action" + }, + "errors": {}, + "id": "2", + "type": "action", + "warnings": {}, + "x": 0, + "y": 506 + }, + "20": { + "data": { + "advanced": { + "customName": "format device query", + "customNameId": 0, + "description": "Iterate through the playbook inputs and format a list of queries.", + "join": [], + "note": "Iterate through the playbook inputs and format a list of queries." + }, + "functionId": 1, + "functionName": "format_device_query", + "id": "20", + "parameters": [ + "filtered-data:playbook_inputs_filter:condition_2:playbook_input:device" + ], + "template": "%%\n(&(objectCategory=computer)(|(sAMAccountName={0}*)(distinguishedName={0}*)(userPrincipalName={0}*)))\n%%", + "type": "format" + }, + "errors": {}, + "id": "20", + "type": "format", + "warnings": {}, + "x": 340, + "y": 328 + }, + "3": { + "data": { + "advanced": { + "customName": "format user outputs", + "customNameId": 0, + "description": "Format a normalized output for each user.", + "join": [], + "note": "Format a normalized output for each user." + }, + "functionId": 1, + "functionName": "format_user_outputs", + "id": "3", + "inputParameters": [ + "filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.data.*.entries.*.attributes", + "filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.parameter.principals", + "get_user_group_attributes:action_result.data.*.entries.*.attributes" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "3", + "type": "code", + "userCode": " \n format_user_outputs__observable_array = []\n \n # create dictionary of group attributes\n group_dict = {}\n for group in get_user_group_attributes_result_item_0:\n group_dict[group['distinguishedname']] = group\n \n # create normalized output dictionary\n for pb_input, user in zip(filtered_result_0_parameter_principals, filtered_result_0_data___entries___attributes):\n user_dict = {\n \"account_type\": \"LDAP Account\",\n \"account_type_id\": 1,\n \"account_uid\": user['userPrincipalName'],\n \"domain\": user['userPrincipalName'].split('@')[1],\n \"email_addr\": user['mail'],\n \"end_date\": user['accountExpires'],\n \"full_name\": user['name'],\n \"labels\": [\n user['title'],\n user['department']\n ],\n \"managed_by\": user['manager'],\n \"name\": user['sAMAccountName'],\n \"start_date\": user['whenCreated'],\n \"type\": \"User\",\n \"type_id\": 1,\n \"uid\": user['distinguishedName'],\n \"uuid\": user['objectGUID']\n }\n phones = [\n user['mobile'],\n user['ipPhone'],\n user['homePhone'],\n user['telephoneNumber'],\n user['otherMobile'],\n user['otherIpPhone'],\n user['otherHomePhone'],\n user['otherTelephone']\n ]\n \n # lookup groups\n group_list = []\n for group in user['memberOf']:\n if group_dict.get(group):\n group_details = group_dict[group]\n if not group_details['description']:\n group_details['description'].append(\"None\")\n temp_group_dict = {\n \"type\": \"Domain\",\n \"desc\": group_details['description'][0],\n \"name\": group_details['name'],\n \"privileges\": group_details['memberof'],\n \"uid\": group_details['distinguishedname']\n }\n # drop values with []\n for k,v in temp_group_dict.copy().items():\n if v == []:\n temp_group_dict.pop(k)\n group_list.append(temp_group_dict)\n \n \n if group_list:\n user_dict['groups'] = group_list\n \n # clean up phone numbers\n phones = [phone for phone in phones if phone != []]\n if phones:\n user_dict['phones'] = phones\n \n \n final_output = {\n \"type\": \"user\",\n \"value\": pb_input,\n \"attributes\": user_dict,\n \"soure\": \"AD LDAP\"\n }\n format_user_outputs__observable_array.append(final_output)\n \n # phantom.debug(format_user_outputs__observable_array)\n \n\n", + "warnings": {}, + "x": 0, + "y": 1236 + }, + "8": { + "data": { + "advanced": { + "customName": "merge user groups", + "customNameId": 0, + "description": "Merge user groups, from preceding action block results, into a single deduplicated list.", + "join": [], + "note": "Merge user groups, from preceding action block results, into a single deduplicated list." + }, + "customDatapaths": { + "filter_user_results": { + "condition_1:get_user_attributes:action_result.data.*.entries.*.attributes.memberOf": { + "contains": [], + "isCustomDatapath": true, + "label": "condition_1:get_user_attributes:action_result.data.*.entries.*.attributes.memberOf", + "value": "filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.data.*.entries.*.attributes.memberOf" + } + } + }, + "functionId": 2, + "functionName": "merge_user_groups", + "id": "8", + "inputParameters": [ + "filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.data.*.entries.*.attributes.memberOf" + ], + "outputVariables": [ + "list" + ], + "type": "code" + }, + "errors": {}, + "id": "8", + "type": "code", + "userCode": "\n \n group_list = []\n for group in filtered_result_0_data___entries___attributes_memberof:\n group_list.extend(group)\n \n merge_user_groups__list = list(set(group_list))\n \n", + "warnings": {}, + "x": 0, + "y": 864 + } + }, + "notes": "Inputs: user, device\nInteractions: AD LDAP\nActions: get attributes, run query\nOutputs: report, observables" + }, + "input_spec": [ + { + "contains": [ + "user name" + ], + "description": "A user identity in Active Directory such as sAMAccountName, userPrincipalName, or distinguishedName", + "name": "user" + }, + { + "contains": [ + "host name" + ], + "description": "A device in Active Directory.", + "name": "device" + } + ], + "output_spec": [ + { + "contains": [], + "datapaths": [ + "format_user_outputs:custom_function:observable_array", + "format_device_outputs:custom_function:observable_array" + ], + "deduplicate": false, + "description": "An array of observable dictionaries ", + "metadata": {}, + "name": "observable" + } + ], + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-03-03T18:13:51.717485+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "attributes", + "user", + "device", + "ad_ldap" + ] +} \ No newline at end of file diff --git a/playbooks/AD_LDAP_Entity_Attribute_Lookup.png b/playbooks/AD_LDAP_Entity_Attribute_Lookup.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf3e74588b112ae7a2195f789989c662ea2b644 GIT binary patch literal 70571 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

6cV9U>oN`qkjg^C-h%UI5 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 b%PPJ~pIQVW)v|p8{3+a5zL$6B>8t+%_P}S* literal 0 HcmV?d00001 diff --git a/playbooks/AD_LDAP_Entity_Attribute_Lookup.py b/playbooks/AD_LDAP_Entity_Attribute_Lookup.py new file mode 100644 index 0000000000..635072270d --- /dev/null +++ b/playbooks/AD_LDAP_Entity_Attribute_Lookup.py @@ -0,0 +1,610 @@ +""" +Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device. +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'playbook_inputs_filter' block + playbook_inputs_filter(container=container) + + return + +@phantom.playbook_block() +def get_user_attributes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("get_user_attributes() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Query for the user attributes for filtered playbook inputs. + ################################################################################ + + filtered_input_0_user = phantom.collect2(container=container, datapath=["filtered-data:playbook_inputs_filter:condition_1:playbook_input:user"]) + + parameters = [] + + # build parameters list for 'get_user_attributes' call + for filtered_input_0_user_item in filtered_input_0_user: + if filtered_input_0_user_item[0] is not None: + parameters.append({ + "attributes": "userPrincipalName;mail;accountExpires;name;memberOf;title;department;manager;sAMAccountName;distinguishedName;mobile;ipPhone;homePhone;telephoneNumber;otherMobile;otherIpPhone;otherHomePhone;otherTelephone;whenCreated;objectSid;objectGUID", + "principals": filtered_input_0_user_item[0], + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("get attributes", parameters=parameters, name="get_user_attributes", assets=["ad_ldap"], callback=filter_user_results) + + return + + +@phantom.playbook_block() +def format_user_outputs(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_user_outputs() called") + + ################################################################################ + # Format a normalized output for each user. + ################################################################################ + + filtered_result_0_data_filter_user_results = phantom.collect2(container=container, datapath=["filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.data.*.entries.*.attributes","filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.parameter.principals"]) + get_user_group_attributes_result_data = phantom.collect2(container=container, datapath=["get_user_group_attributes:action_result.data.*.entries.*.attributes"], action_results=results) + + filtered_result_0_data___entries___attributes = [item[0] for item in filtered_result_0_data_filter_user_results] + filtered_result_0_parameter_principals = [item[1] for item in filtered_result_0_data_filter_user_results] + get_user_group_attributes_result_item_0 = [item[0] for item in get_user_group_attributes_result_data] + + format_user_outputs__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + format_user_outputs__observable_array = [] + + # create dictionary of group attributes + group_dict = {} + for group in get_user_group_attributes_result_item_0: + group_dict[group['distinguishedname']] = group + + # create normalized output dictionary + for pb_input, user in zip(filtered_result_0_parameter_principals, filtered_result_0_data___entries___attributes): + user_dict = { + "account_type": "LDAP Account", + "account_type_id": 1, + "account_uid": user['userPrincipalName'], + "domain": user['userPrincipalName'].split('@')[1], + "email_addr": user['mail'], + "end_date": user['accountExpires'], + "full_name": user['name'], + "labels": [ + user['title'], + user['department'] + ], + "managed_by": user['manager'], + "name": user['sAMAccountName'], + "start_date": user['whenCreated'], + "type": "User", + "type_id": 1, + "uid": user['distinguishedName'], + "uuid": user['objectGUID'] + } + phones = [ + user['mobile'], + user['ipPhone'], + user['homePhone'], + user['telephoneNumber'], + user['otherMobile'], + user['otherIpPhone'], + user['otherHomePhone'], + user['otherTelephone'] + ] + + # lookup groups + group_list = [] + for group in user['memberOf']: + if group_dict.get(group): + group_details = group_dict[group] + if not group_details['description']: + group_details['description'].append("None") + temp_group_dict = { + "type": "Domain", + "desc": group_details['description'][0], + "name": group_details['name'], + "privileges": group_details['memberof'], + "uid": group_details['distinguishedname'] + } + # drop values with [] + for k,v in temp_group_dict.copy().items(): + if v == []: + temp_group_dict.pop(k) + group_list.append(temp_group_dict) + + + if group_list: + user_dict['groups'] = group_list + + # clean up phone numbers + phones = [phone for phone in phones if phone != []] + if phones: + user_dict['phones'] = phones + + + final_output = { + "type": "user", + "value": pb_input, + "attributes": user_dict, + "soure": "AD LDAP" + } + format_user_outputs__observable_array.append(final_output) + + # phantom.debug(format_user_outputs__observable_array) + + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="format_user_outputs:observable_array", value=json.dumps(format_user_outputs__observable_array)) + + return + + +@phantom.playbook_block() +def merge_user_groups(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("merge_user_groups() called") + + ################################################################################ + # Merge user groups, from preceding action block results, into a single deduplicated + # list. + ################################################################################ + + filtered_result_0_data_filter_user_results = phantom.collect2(container=container, datapath=["filtered-data:filter_user_results:condition_1:get_user_attributes:action_result.data.*.entries.*.attributes.memberOf"]) + + filtered_result_0_data___entries___attributes_memberof = [item[0] for item in filtered_result_0_data_filter_user_results] + + merge_user_groups__list = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + + group_list = [] + for group in filtered_result_0_data___entries___attributes_memberof: + group_list.extend(group) + + merge_user_groups__list = list(set(group_list)) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="merge_user_groups:list", value=json.dumps(merge_user_groups__list)) + + get_user_group_attributes(container=container) + + return + + +@phantom.playbook_block() +def get_user_group_attributes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("get_user_group_attributes() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + filter_formatted_string = phantom.format( + container=container, + template="""(|\n%%\n(distinguishedName={0})\n%%\n)\n""", + parameters=[ + "merge_user_groups:custom_function:list" + ]) + + ################################################################################ + # Get details for the groups to which the user belongs. + ################################################################################ + + merge_user_groups__list = json.loads(_ if (_ := phantom.get_run_data(key="merge_user_groups:list")) != "" else "null") # pylint: disable=used-before-assignment + + parameters = [] + + if filter_formatted_string is not None: + parameters.append({ + "filter": filter_formatted_string, + "attributes": "description;name;memberOf;distinguishedName", + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("run query", parameters=parameters, name="get_user_group_attributes", assets=["ad_ldap"], callback=format_user_outputs) + + return + + +@phantom.playbook_block() +def get_device_attributes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("get_device_attributes() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Query for the device attributes for filtered playbook inputs. + ################################################################################ + + format_device_query__as_list = phantom.get_format_data(name="format_device_query__as_list") + + parameters = [] + + # build parameters list for 'get_device_attributes' call + for format_device_query__item in format_device_query__as_list: + if format_device_query__item is not None: + parameters.append({ + "filter": format_device_query__item, + "attributes": "description;distinguishedName;objectSid;memberOf;name;sAMAccountName", + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("run query", parameters=parameters, name="get_device_attributes", assets=["ad_ldap"], callback=filter_device_results) + + return + + +@phantom.playbook_block() +def playbook_inputs_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("playbook_inputs_filter() called") + + ################################################################################ + # Filter inputs to route inputs to appropriate actions. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["playbook_input:user", "!=", None] + ], + name="playbook_inputs_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + get_user_attributes(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + # collect filtered artifact ids and results for 'if' condition 2 + matched_artifacts_2, matched_results_2 = phantom.condition( + container=container, + conditions=[ + ["playbook_input:device", "!=", None] + ], + name="playbook_inputs_filter:condition_2") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_2 or matched_results_2: + format_device_query(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2) + + return + + +@phantom.playbook_block() +def merge_device_groups(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("merge_device_groups() called") + + ################################################################################ + # Merge device groups, from preceding action block results, into a single deduplicated + # list. + ################################################################################ + + filtered_result_0_data_filter_device_results = phantom.collect2(container=container, datapath=["filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.data.*.entries.*.attributes.memberof"]) + + filtered_result_0_data___entries___attributes_memberof = [item[0] for item in filtered_result_0_data_filter_device_results] + + merge_device_groups__list = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + group_list = [] + for group in filtered_result_0_data___entries___attributes_memberof: + group_list.extend(group) + + merge_device_groups__list = list(set(group_list)) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="merge_device_groups:list", value=json.dumps(merge_device_groups__list)) + + get_device_group_attributes(container=container) + + return + + +@phantom.playbook_block() +def get_device_group_attributes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("get_device_group_attributes() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + filter_formatted_string = phantom.format( + container=container, + template="""(|\n%%\n(distinguishedName={0})\n%%\n)""", + parameters=[ + "merge_device_groups:custom_function:list" + ]) + + ################################################################################ + # Get details for the groups to which the device belongs. + ################################################################################ + + merge_device_groups__list = json.loads(_ if (_ := phantom.get_run_data(key="merge_device_groups:list")) != "" else "null") # pylint: disable=used-before-assignment + + parameters = [] + + if filter_formatted_string is not None: + parameters.append({ + "filter": filter_formatted_string, + "attributes": "description;name;memberOf;distinguishedName", + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("run query", parameters=parameters, name="get_device_group_attributes", assets=["ad_ldap"], callback=format_device_outputs) + + return + + +@phantom.playbook_block() +def format_device_outputs(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_device_outputs() called") + + ################################################################################ + # Format a normalized output for each device. + ################################################################################ + + filtered_result_0_data_filter_device_results = phantom.collect2(container=container, datapath=["filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.data.*.entries.*.attributes","filtered-data:filter_device_results:condition_1:get_device_attributes:action_result.parameter.filter"]) + get_device_group_attributes_result_data = phantom.collect2(container=container, datapath=["get_device_group_attributes:action_result.data.*.entries.*.attributes"], action_results=results) + + filtered_result_0_data___entries___attributes = [item[0] for item in filtered_result_0_data_filter_device_results] + filtered_result_0_parameter_filter = [item[1] for item in filtered_result_0_data_filter_device_results] + get_device_group_attributes_result_item_0 = [item[0] for item in get_device_group_attributes_result_data] + + format_device_outputs__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + import re + + format_device_outputs__observable_array = [] + + def extract_domain_name(dn): + dn_rex = re.search(r'(DC=.+)', dn) + if dn_rex: + dc_list = dn_rex.group(1).replace('DC=', '').split(',') + return '.'.join(dc_list) + + def extract_ou(dn): + dn_rex = re.search(r'(OU=.+?),DC', dn) + if dn_rex: + ou_list = dn_rex.group(1).replace('OU=', '').split(',') + return ou_list + + def extract_pb_input_from_filter(filter_query_list): + pb_input_list = [] + for query in filter_query_list: + query_rex = re.search(r'sAMAccountName=([^\)]+)', query) + hostname = query_rex.group(1).replace('*', '') + pb_input_list.append(hostname) + return pb_input_list + + # create dictionary of group attributes + group_dict = {} + for group in get_device_group_attributes_result_item_0: + group_dict[group['distinguishedname']] = group + + pb_input_hostname_list = extract_pb_input_from_filter(filtered_result_0_parameter_filter) + # create normalized output dictionary + for pb_input, device in zip(pb_input_hostname_list, filtered_result_0_data___entries___attributes): + device_dict = { + "desc": device['description'], + "domain": extract_domain_name(device['distinguishedname']), + "hostname": device['name'], + "name": device['samaccountname'], + "type": "Unknown", + "type_id": 0, + "uid": device['objectsid'] + } + + # use OUs as labels + ou_list = extract_ou(device['distinguishedname']) + if ou_list: + device_dict['labels'] = ou_list + + # lookup groups + group_list = [] + for group in device['memberof']: + if group_dict.get(group): + group_details = group_dict[group] + if not group_details['description']: + group_details['description'].append("None") + temp_group_dict = { + "type": "Domain", + "desc": group_details['description'][0], + "name": group_details['name'], + "privileges": group_details['memberof'], + "uid": group_details['distinguishedname'] + } + # drop values with [] + for k,v in temp_group_dict.copy().items(): + if v == []: + temp_group_dict.pop(k) + group_list.append(temp_group_dict) + if group_list: + device_dict['groups'] = group_list + + + final_output = { + "type": "host name", + "value": pb_input, + "attributes": device_dict, + "source": "AD LDAP" + } + format_device_outputs__observable_array.append(final_output) + + # phantom.debug(format_device_outputs__observable_array) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="format_device_outputs:observable_array", value=json.dumps(format_device_outputs__observable_array)) + + return + + +@phantom.playbook_block() +def filter_user_results(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_user_results() called") + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["get_user_attributes:action_result.summary.total_objects", ">", 0] + ], + name="filter_user_results:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + merge_user_groups(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def filter_device_results(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_device_results() called") + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["get_device_attributes:action_result.summary.total_objects", ">", 0] + ], + name="filter_device_results:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + merge_device_groups(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def format_device_query(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_device_query() called") + + ################################################################################ + # Iterate through the playbook inputs and format a list of queries. + ################################################################################ + + template = """%%\n(&(objectCategory=computer)(|(sAMAccountName={0}*)(distinguishedName={0}*)(userPrincipalName={0}*)))\n%%""" + + # parameter list for template variable replacement + parameters = [ + "filtered-data:playbook_inputs_filter:condition_2:playbook_input:device" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="format_device_query") + + get_device_attributes(container=container) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + format_user_outputs__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="format_user_outputs:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + format_device_outputs__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="format_device_outputs:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + observable_combined_value = phantom.concatenate(format_user_outputs__observable_array, format_device_outputs__observable_array) + + output = { + "observable": observable_combined_value, + } + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # This function is called after all actions are completed. + # summary of all the action and/or all details of actions + # can be collected here. + + # summary_json = phantom.get_summary() + # if 'result' in summary_json: + # for action_result in summary_json['result']: + # if 'action_run_id' in action_result: + # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False) + # phantom.debug(action_results) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_playbook_output_data(output=output) + + return \ No newline at end of file diff --git a/playbooks/AD_LDAP_Entity_Attribute_Lookup.yml b/playbooks/AD_LDAP_Entity_Attribute_Lookup.yml new file mode 100644 index 0000000000..9b98ce7457 --- /dev/null +++ b/playbooks/AD_LDAP_Entity_Attribute_Lookup.yml @@ -0,0 +1,23 @@ +name: AD LDAP Entity Attribute Lookup +id: fc0edc96-aa2b-4cb0-7b4d-63da67d3fe74 +version: 1 +date: '2023-01-11' +author: Kelby Shelton, Lou Stella, Splunk +type: Investigation +description: "Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device." +playbook: AD_LDAP_Entity_Attribute_Lookup +how_to_implement: This input playbook requires the AD LDAP connector to be configured. It is designed to work in conjunction with the Dynamic Attribute Lookup playbook or other playbooks in the same style. +references: [] +app_list: + - AD LDAP +tags: + platform_tags: + - attributes + - user + - device + - ad_ldap + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR \ No newline at end of file From 813ce6f1828521a88a1e7d4a17e629d6df8fac84 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Mon, 6 Mar 2023 10:57:30 -0600 Subject: [PATCH 2/4] Azure AD Graph User Attribute Lookup Playbook --- .../Azure_AD_Graph_User_Attribute_Lookup.json | 277 ++++++++++++++++++ .../Azure_AD_Graph_User_Attribute_Lookup.png | Bin 0 -> 30833 bytes .../Azure_AD_Graph_User_Attribute_Lookup.py | 209 +++++++++++++ .../Azure_AD_Graph_User_Attribute_Lookup.yml | 23 ++ 4 files changed, 509 insertions(+) create mode 100644 playbooks/Azure_AD_Graph_User_Attribute_Lookup.json create mode 100644 playbooks/Azure_AD_Graph_User_Attribute_Lookup.png create mode 100644 playbooks/Azure_AD_Graph_User_Attribute_Lookup.py create mode 100644 playbooks/Azure_AD_Graph_User_Attribute_Lookup.yml diff --git a/playbooks/Azure_AD_Graph_User_Attribute_Lookup.json b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.json new file mode 100644 index 0000000000..d3d34d968d --- /dev/null +++ b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.json @@ -0,0 +1,277 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Attribute Lookup", + "coa": { + "data": { + "description": "Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device.", + "edges": [ + { + "id": "port_3_to_port_1", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_0_to_port_14", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "14", + "targetPort": "14_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_14_to_port_2", + "sourceNode": "14", + "sourcePort": "14_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "id": "port_2_to_port_15", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "15", + "targetPort": "15_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_15_to_port_3", + "sourceNode": "15", + "sourcePort": "15_out", + "targetNode": "3", + "targetPort": "3_in" + } + ], + "hash": "be0b1202e1571a6a8a4d345c6d14d30afcef8422", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 20, + "y": 0 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionId": 1, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n", + "warnings": {}, + "x": 20, + "y": 864 + }, + "14": { + "data": { + "advanced": { + "customName": "playbook inputs filter", + "customNameId": 0, + "description": "Filter inputs to route inputs to appropriate actions.", + "join": [], + "note": "Filter inputs to route inputs to appropriate actions." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:user", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "user", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "playbook_inputs_filter", + "id": "14", + "type": "filter" + }, + "errors": {}, + "id": "14", + "type": "filter", + "warnings": { + "config": [ + "Reconfigure invalid datapath." + ] + }, + "x": 60, + "y": 148 + }, + "15": { + "data": { + "advanced": { + "customName": "user results filter", + "customNameId": 0, + "description": "Determine if a user was found from the preceding action", + "join": [], + "note": "Determine if a user was found from the preceding action" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "==", + "param": "get_user_attributes:action_result.status", + "value": "success" + } + ], + "conditionIndex": 0, + "customName": "user exists", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "user_results_filter", + "id": "15", + "type": "filter" + }, + "errors": {}, + "id": "15", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 506 + }, + "2": { + "data": { + "action": "list user attributes", + "actionType": "investigate", + "advanced": { + "customName": "get user attributes", + "customNameId": 0, + "description": "Query for the user attributes for filtered playbook inputs.", + "join": [], + "note": "Query for the user attributes for filtered playbook inputs." + }, + "connector": "Azure AD Graph", + "connectorConfigs": [ + "azure_ad_graph" + ], + "connectorId": "c6d3b801-5c26-4abd-9e89-6d8007e2778f", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_user_attributes", + "id": "2", + "parameters": { + "user_id": "filtered-data:playbook_inputs_filter:condition_1:playbook_input:user" + }, + "requiredParameters": [], + "type": "action" + }, + "errors": {}, + "id": "2", + "type": "action", + "warnings": {}, + "x": 0, + "y": 328 + }, + "3": { + "data": { + "advanced": { + "customName": "format user outputs", + "customNameId": 0, + "description": "Format a normalized output for each user.", + "join": [], + "note": "Format a normalized output for each user." + }, + "functionId": 1, + "functionName": "format_user_outputs", + "id": "3", + "inputParameters": [ + "filtered-data:user_results_filter:condition_1:get_user_attributes:action_result.data.0", + "filtered-data:user_results_filter:condition_1:get_user_attributes:action_result.parameter.user_id" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "3", + "type": "code", + "userCode": " \n format_user_outputs__observable_array = []\n \n # create normalized output dictionary\n for pb_input, user in zip(filtered_result_0_parameter_user_id, filtered_result_0_data_0):\n user_dict = {\n \"account_type\": \"Azure AD Account\",\n \"account_type_id\": 6,\n \"account_uid\": user['userPrincipalName'],\n \"domain\": user['userPrincipalName'].split('@')[1],\n \"email_addr\": user['mail'],\n \"full_name\": user['displayName'],\n \"name\": user['userPrincipalName'].split('@')[0],\n \"start_date\": user['createdDateTime'],\n \"type\": \"User\",\n \"type_id\": 1,\n \"uid\": user['objectId']\n }\n phones = [\n user['telephoneNumber'],\n user['facsimileTelephoneNumber']\n ]\n labels = [\n user['jobTitle'],\n user['department']\n ]\n \n \n # clean up phone numbers\n phones = [phone for phone in phones if phone]\n user_dict['phones'] = phones\n \n # clean up labels\n labels = [label for label in labels if label]\n user_dict['labels'] = labels\n \n final_output = {\n \"type\": \"user\",\n \"value\": pb_input,\n \"attributes\": user_dict,\n \"source\": \"Azure AD Graph\"\n }\n format_user_outputs__observable_array.append(final_output)\n \n # phantom.debug(format_user_outputs__observable_array)\n \n\n", + "warnings": {}, + "x": 0, + "y": 686 + } + }, + "notes": "Inputs: user, device\nInteractions: AD LDAP\nActions: get attributes, run query\nOutputs: report, observables" + }, + "input_spec": [ + { + "contains": [ + "user name" + ], + "description": "A user identity in Active Directory such as sAMAccountName, userPrincipalName, or distinguishedName", + "name": "user" + }, + { + "contains": [ + "host name" + ], + "description": "A device in Active Directory.", + "name": "device" + } + ], + "output_spec": [ + { + "contains": [], + "datapaths": [ + "format_user_outputs:custom_function:observable_array", + "format_device_outputs:custom_function:observable_array" + ], + "deduplicate": false, + "description": "An array of observable dictionaries ", + "metadata": {}, + "name": "observable" + } + ], + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-03-02T14:17:17.726698+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "attributes", + "user", + "device", + "azure_ad_graph" + ] +} \ No newline at end of file diff --git a/playbooks/Azure_AD_Graph_User_Attribute_Lookup.png b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.png new file mode 100644 index 0000000000000000000000000000000000000000..a08ffda9cef26171c8352e3211396ae7fe7938df GIT binary patch literal 30833 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 GzxXd_nj3`x literal 0 HcmV?d00001 diff --git a/playbooks/Azure_AD_Graph_User_Attribute_Lookup.py b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.py new file mode 100644 index 0000000000..5c6b930498 --- /dev/null +++ b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.py @@ -0,0 +1,209 @@ +""" +Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device. +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'playbook_inputs_filter' block + playbook_inputs_filter(container=container) + + return + +@phantom.playbook_block() +def get_user_attributes(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("get_user_attributes() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Query for the user attributes for filtered playbook inputs. + ################################################################################ + + filtered_input_0_user = phantom.collect2(container=container, datapath=["filtered-data:playbook_inputs_filter:condition_1:playbook_input:user"]) + + parameters = [] + + # build parameters list for 'get_user_attributes' call + for filtered_input_0_user_item in filtered_input_0_user: + parameters.append({ + "user_id": filtered_input_0_user_item[0], + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("list user attributes", parameters=parameters, name="get_user_attributes", assets=["azure_ad_graph"], callback=user_results_filter) + + return + + +@phantom.playbook_block() +def format_user_outputs(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_user_outputs() called") + + ################################################################################ + # Format a normalized output for each user. + ################################################################################ + + filtered_result_0_data_user_results_filter = phantom.collect2(container=container, datapath=["filtered-data:user_results_filter:condition_1:get_user_attributes:action_result.data.0","filtered-data:user_results_filter:condition_1:get_user_attributes:action_result.parameter.user_id"]) + + filtered_result_0_data_0 = [item[0] for item in filtered_result_0_data_user_results_filter] + filtered_result_0_parameter_user_id = [item[1] for item in filtered_result_0_data_user_results_filter] + + format_user_outputs__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + format_user_outputs__observable_array = [] + + # create normalized output dictionary + for pb_input, user in zip(filtered_result_0_parameter_user_id, filtered_result_0_data_0): + user_dict = { + "account_type": "Azure AD Account", + "account_type_id": 6, + "account_uid": user['userPrincipalName'], + "domain": user['userPrincipalName'].split('@')[1], + "email_addr": user['mail'], + "full_name": user['displayName'], + "name": user['userPrincipalName'].split('@')[0], + "start_date": user['createdDateTime'], + "type": "User", + "type_id": 1, + "uid": user['objectId'] + } + phones = [ + user['telephoneNumber'], + user['facsimileTelephoneNumber'] + ] + labels = [ + user['jobTitle'], + user['department'] + ] + + + # clean up phone numbers + phones = [phone for phone in phones if phone] + user_dict['phones'] = phones + + # clean up labels + labels = [label for label in labels if label] + user_dict['labels'] = labels + + final_output = { + "type": "user", + "value": pb_input, + "attributes": user_dict, + "source": "Azure AD Graph" + } + format_user_outputs__observable_array.append(final_output) + + # phantom.debug(format_user_outputs__observable_array) + + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="format_user_outputs:observable_array", value=json.dumps(format_user_outputs__observable_array)) + + return + + +@phantom.playbook_block() +def playbook_inputs_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("playbook_inputs_filter() called") + + ################################################################################ + # Filter inputs to route inputs to appropriate actions. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["playbook_input:user", "!=", None] + ], + name="playbook_inputs_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + get_user_attributes(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def user_results_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("user_results_filter() called") + + ################################################################################ + # Determine if a user was found from the preceding action + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["get_user_attributes:action_result.status", "==", "success"] + ], + name="user_results_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + format_user_outputs(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + format_user_outputs__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="format_user_outputs:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + format_device_outputs__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="format_device_outputs:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + observable_combined_value = phantom.concatenate(format_user_outputs__observable_array, format_device_outputs__observable_array) + + output = { + "observable": observable_combined_value, + } + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # This function is called after all actions are completed. + # summary of all the action and/or all details of actions + # can be collected here. + + # summary_json = phantom.get_summary() + # if 'result' in summary_json: + # for action_result in summary_json['result']: + # if 'action_run_id' in action_result: + # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False) + # phantom.debug(action_results) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_playbook_output_data(output=output) + + return \ No newline at end of file diff --git a/playbooks/Azure_AD_Graph_User_Attribute_Lookup.yml b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.yml new file mode 100644 index 0000000000..a5a3d4abfa --- /dev/null +++ b/playbooks/Azure_AD_Graph_User_Attribute_Lookup.yml @@ -0,0 +1,23 @@ +name: Azure AD Graph User Attribute Lookup +id: fc0edc96-aa2b-4cb0-7b4d-63da67e71d74 +version: 1 +date: '2023-01-11' +author: Kelby Shelton, Splunk +type: Investigation +description: "Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device." +playbook: Azure_AD_Graph_User_Attribute_Lookup +how_to_implement: This input playbook requires the Azure AD Graph connector to be configured. It is designed to work in conjunction with the Dynamic Attribute Lookup playbook or other playbooks in the same style. +references: [] +app_list: + - Azure AD Graph +tags: + platform_tags: + - attributes + - user + - device + - azure_ad_graph + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR \ No newline at end of file From a6b6dd148f5f4f364e6cda8183a1418f79380ed3 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Mon, 6 Mar 2023 10:57:59 -0600 Subject: [PATCH 3/4] Crowdstrike OAuth API Device Attribute Lookup playbook --- ...ike_OAuth_API_Device_Attribute_Lookup.json | 606 ++++++++++++++++++ ...rike_OAuth_API_Device_Attribute_Lookup.png | Bin 0 -> 67919 bytes ...trike_OAuth_API_Device_Attribute_Lookup.py | 464 ++++++++++++++ ...rike_OAuth_API_Device_Attribute_Lookup.yml | 25 + 4 files changed, 1095 insertions(+) create mode 100644 playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.json create mode 100644 playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.png create mode 100644 playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.py create mode 100644 playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.yml diff --git a/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.json b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.json new file mode 100644 index 0000000000..36d273e094 --- /dev/null +++ b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.json @@ -0,0 +1,606 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Attribute Lookup", + "coa": { + "data": { + "description": "Accepts device and looks up the most recent attributes for that hostname or IP. This playbook produces a normalized output for each device.", + "edges": [ + { + "id": "port_0_to_port_2", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "id": "port_17_to_port_1", + "sourceNode": "17", + "sourcePort": "17_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_18_to_port_11", + "sourceNode": "18", + "sourcePort": "18_out", + "targetNode": "11", + "targetPort": "11_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_2_to_port_19", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "19", + "targetPort": "19_in" + }, + { + "id": "port_19_to_port_20", + "sourceNode": "19", + "sourcePort": "19_out", + "targetNode": "20", + "targetPort": "20_in" + }, + { + "conditions": [ + { + "index": 1 + } + ], + "id": "port_20_to_port_18", + "sourceNode": "20", + "sourcePort": "20_out", + "targetNode": "18", + "targetPort": "18_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_20_to_port_21", + "sourceNode": "20", + "sourcePort": "20_out", + "targetNode": "21", + "targetPort": "21_in" + }, + { + "id": "port_21_to_port_22", + "sourceNode": "21", + "sourcePort": "21_out", + "targetNode": "22", + "targetPort": "22_in" + }, + { + "id": "port_24_to_port_1", + "sourceNode": "24", + "sourcePort": "24_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_11_to_port_25", + "sourceNode": "11", + "sourcePort": "11_out", + "targetNode": "25", + "targetPort": "25_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_25_to_port_17", + "sourceNode": "25", + "sourcePort": "25_out", + "targetNode": "17", + "targetPort": "17_in" + }, + { + "id": "port_22_to_port_26", + "sourceNode": "22", + "sourcePort": "22_out", + "targetNode": "26", + "targetPort": "26_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_26_to_port_24", + "sourceNode": "26", + "sourcePort": "26_out", + "targetNode": "24", + "targetPort": "24_in" + } + ], + "hash": "1c6c95ac6900f02a350245c2f84d9e5b4252dad1", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 190, + "y": -6.394884621840902e-14 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 190, + "y": 1416 + }, + "11": { + "data": { + "action": "query device", + "actionType": "investigate", + "advanced": { + "customName": "query hostname", + "customNameId": 0, + "description": "Search for devices that have the hostname given to playbook input.", + "join": [], + "note": "Search for devices that have the hostname given to playbook input." + }, + "connector": "CrowdStrike OAuth API", + "connectorConfigs": [ + "crowdstrike" + ], + "connectorId": "ae971ba5-3117-444a-8ac5-6ce779f3a232", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "query_hostname", + "id": "11", + "parameters": { + "filter": "format_hostname_filter:formatted_data.*", + "limit": "10" + }, + "requiredParameters": [ + { + "data_type": "numeric", + "default": 50, + "field": "limit" + } + ], + "type": "action" + }, + "errors": {}, + "id": "11", + "type": "action", + "warnings": {}, + "x": 0, + "y": 864 + }, + "17": { + "data": { + "advanced": { + "customName": "build hostname observables", + "customNameId": 0, + "description": "Generate an observable dictionary to output into the observables data path.", + "join": [], + "note": "Generate an observable dictionary to output into the observables data path." + }, + "functionId": 2, + "functionName": "build_hostname_observables", + "id": "17", + "inputParameters": [ + "filtered-data:filter_hostname_results:condition_1:query_hostname:action_result.data", + "filtered-data:filter_hostname_results:condition_1:query_hostname:action_result.parameter.filter" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "17", + "type": "code", + "userCode": " build_hostname_observables__observable_array = []\n device_type_dict = {\n 'server': 1,\n 'desktop': 2,\n 'laptop': 3,\n 'tablet': 4,\n 'mobile': 5,\n 'virtual': 6,\n 'iot': 7,\n 'browser': 8\n }\n for item, input_string in zip(filtered_result_0_data, filtered_result_0_parameter_filter):\n device = item[0]\n device_dict = {\n \"type\": \"host name\",\n \"value\": input_string.replace(\"hostname:\", \"\").replace('\"', \"\"),\n \"source\": \"Crowdstrike OAuth API\",\n \"attributes\": {\n \"desc\": f\"{device.get('system_product_name', 'No product name')} - {device.get('os_product_name', 'No os name')}\",\n \"groups\": device.get('groups'),\n \"hostname\": device.get('hostname'),\n \"ip\": device.get('connection_ip'),\n \"mac\": device.get('mac_address'),\n \"name\": device.get('hostname'),\n \"os\": device.get('os_version'),\n \"hw_info\": {\n \"bios_manufacturer\": device.get('bios_manufacturer'),\n \"bios_ver\": device.get('bios_version'),\n \"serial_number\": device.get('serial_number')\n },\n \"type\": \"Unknown\",\n \"type_id\": 0,\n \"uid\": device.get('device_id') \n }\n }\n if device.get('product_type_desc'):\n if device_type_dict.get(device['product_type_desc'].lower()):\n device_dict['attributes']['type'] = device['product_type_desc']\n device_dict['attributes']['type_id'] = device_type_dict[device['product_type_desc'].lower()]\n else:\n device_dict['attributes']['type'] = device['product_type_desc']\n device_dict['attributes']['type_id'] = 99\n\n build_hostname_observables__observable_array.append(device_dict)\n", + "warnings": {}, + "x": 0, + "y": 1222 + }, + "18": { + "data": { + "advanced": { + "customName": "format hostname filter", + "customNameId": 0, + "description": "Format a filter for the query device, while looping through playbook inputs.", + "join": [], + "note": "Format a filter for the query device, while looping through playbook inputs." + }, + "functionId": 3, + "functionName": "format_hostname_filter", + "id": "18", + "parameters": [ + "filtered-data:ip_filter:condition_2:extract_ipv4:custom_function_result.data.input_value" + ], + "template": "%%\nhostname:\"{0}\"\n%%", + "type": "format" + }, + "errors": {}, + "id": "18", + "type": "format", + "warnings": {}, + "x": 0, + "y": 686 + }, + "19": { + "data": { + "advanced": { + "customName": "extract ipv4", + "customNameId": 0, + "description": "Extract IP address from input device", + "join": [], + "note": "Extract IP address from input device" + }, + "customFunction": { + "draftMode": false, + "name": "regex_extract_ipv4", + "repoName": "community" + }, + "functionId": 1, + "functionName": "extract_ipv4", + "id": "19", + "selectMore": false, + "type": "utility", + "utilities": { + "regex_extract_ipv4": { + "description": "Takes a single input and extracts all IPv4 addresses from it using regex.", + "fields": [ + { + "dataTypes": [ + "*" + ], + "description": "An input string that may contain an arbitrary number of ipv4 addresses", + "inputType": "item", + "label": "input_string", + "name": "input_string", + "placeholder": "192.0.2.1", + "renderType": "datapath", + "required": false + } + ], + "label": "regex_extract_ipv4", + "name": "regex_extract_ipv4" + } + }, + "utilityType": "custom_function", + "values": { + "regex_extract_ipv4": { + "input_string": "filtered-data:device_id_input_filter:condition_1:playbook_input:device" + } + } + }, + "errors": {}, + "id": "19", + "type": "utility", + "warnings": {}, + "x": 170, + "y": 328 + }, + "2": { + "data": { + "advanced": { + "customName": "device id input filter", + "customNameId": 0, + "description": "Ensure that device input exists", + "join": [], + "note": "Ensure that device input exists" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:device", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "device_id", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "device_id_input_filter", + "id": "2", + "type": "filter" + }, + "errors": {}, + "id": "2", + "type": "filter", + "warnings": { + "config": [ + "Reconfigure invalid datapath." + ] + }, + "x": 230, + "y": 148 + }, + "20": { + "data": { + "advanced": { + "customName": "ip filter", + "customNameId": 0, + "description": "Determine which of the playbook inputs are devices or hostnames", + "join": [], + "note": "Determine which of the playbook inputs are devices or hostnames" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "extract_ipv4:custom_function_result.data.extracted_ipv4", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "ip exists", + "logic": "and" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "==", + "param": "extract_ipv4:custom_function_result.data.extracted_ipv4", + "value": "None" + } + ], + "conditionIndex": 1, + "customName": "ip does not exist", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "ip_filter", + "id": "20", + "type": "filter" + }, + "errors": {}, + "id": "20", + "type": "filter", + "warnings": {}, + "x": 230, + "y": 506 + }, + "21": { + "data": { + "advanced": { + "customName": "format ip filter", + "customNameId": 0, + "description": "Format a filter for the query device, while looping through playbook inputs.", + "join": [], + "note": "Format a filter for the query device, while looping through playbook inputs." + }, + "functionId": 1, + "functionName": "format_ip_filter", + "id": "21", + "parameters": [ + "filtered-data:ip_filter:condition_1:extract_ipv4:custom_function_result.data.extracted_ipv4" + ], + "template": "%%\nlocal_ip:\"{0}\",external_ip:\"{0}\"\n%%", + "type": "format" + }, + "errors": {}, + "id": "21", + "type": "format", + "warnings": {}, + "x": 340, + "y": 686 + }, + "22": { + "data": { + "action": "query device", + "actionType": "investigate", + "advanced": { + "customName": "query ip", + "customNameId": 0, + "description": "Search for devices that have the IP given to playbook input.", + "join": [], + "note": "Search for devices that have the IP given to playbook input." + }, + "connector": "CrowdStrike OAuth API", + "connectorConfigs": [ + "crowdstrike" + ], + "connectorId": "ae971ba5-3117-444a-8ac5-6ce779f3a232", + "connectorVersion": "v1", + "functionId": 2, + "functionName": "query_ip", + "id": "22", + "parameters": { + "filter": "format_ip_filter:formatted_data.*", + "limit": "10" + }, + "requiredParameters": [ + { + "data_type": "numeric", + "default": 50, + "field": "limit" + } + ], + "type": "action" + }, + "errors": {}, + "id": "22", + "type": "action", + "warnings": {}, + "x": 340, + "y": 864 + }, + "24": { + "data": { + "advanced": { + "customName": "build ip observables", + "customNameId": 0, + "description": "Generate an observable dictionary to output into the observables data path.", + "join": [], + "note": "Generate an observable dictionary to output into the observables data path." + }, + "functionId": 1, + "functionName": "build_ip_observables", + "id": "24", + "inputParameters": [ + "filtered-data:filter_ip_results:condition_1:query_ip:action_result.data", + "filtered-data:filter_ip_results:condition_1:query_ip:action_result.parameter.filter" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "24", + "type": "code", + "userCode": "\n build_ip_observables__observable_array = []\n device_type_dict = {\n 'server': 1,\n 'desktop': 2,\n 'laptop': 3,\n 'tablet': 4,\n 'mobile': 5,\n 'virtual': 6,\n 'iot': 7,\n 'browser': 8\n }\n for item, input_string in zip(filtered_result_0_data, filtered_result_0_parameter_filter):\n device = item[0]\n value = input_string.replace(\"local_ip:\", \"\").replace('external_ip', \"\").replace('\"',\"\")\n value = value.split(',')[0]\n device_dict = {\n \"type\": \"ip\",\n \"value\": value,\n \"source\": \"Crowdstrike OAuth API\",\n \"attributes\": {\n \"desc\": f\"{device.get('system_product_name', 'No product name')} - {device.get('os_product_name', 'No os name')}\",\n \"groups\": device.get('groups'),\n \"hostname\": device.get('hostname'),\n \"ip\": device.get('connection_ip'),\n \"mac\": device.get('mac_address'),\n \"name\": device.get('hostname'),\n \"os\": device.get('os_version'),\n \"hw_info\": {\n \"bios_manufacturer\": device.get('bios_manufacturer'),\n \"bios_ver\": device.get('bios_version'),\n \"serial_number\": device.get('serial_number')\n },\n \"type\": \"Unknown\",\n \"type_id\": 0,\n \"uid\": device.get('device_id') \n }\n }\n if device.get('product_type_desc'):\n if device_type_dict.get(device['product_type_desc'].lower()):\n device_dict['attributes']['type'] = device['product_type_desc']\n device_dict['attributes']['type_id'] = device_type_dict[device['product_type_desc'].lower()]\n else:\n device_dict['attributes']['type'] = device['product_type_desc']\n device_dict['attributes']['type_id'] = 99\n\n build_ip_observables__observable_array.append(device_dict)\n\n", + "warnings": {}, + "x": 340, + "y": 1230 + }, + "25": { + "data": { + "advanced": { + "customName": "filter hostname results", + "customNameId": 0, + "description": "Filter on hostnames that returned results.", + "join": [], + "note": "Filter on hostnames that returned results." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "query_hostname:action_result.summary.total_devices", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "hostname exists", + "logic": "and" + } + ], + "functionId": 3, + "functionName": "filter_hostname_results", + "id": "25", + "type": "filter" + }, + "errors": {}, + "id": "25", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 1042 + }, + "26": { + "data": { + "advanced": { + "customName": "filter ip results", + "customNameId": 0, + "description": "Filter on IPs that returned results.", + "join": [], + "note": "Filter on IPs that returned results." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "query_ip:action_result.summary.total_devices", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "ip exists", + "logic": "and" + } + ], + "functionId": 4, + "functionName": "filter_ip_results", + "id": "26", + "type": "filter" + }, + "errors": {}, + "id": "26", + "type": "filter", + "warnings": {}, + "x": 400, + "y": 1042 + } + }, + "notes": "Inputs: device\nInteractions: CrowdStrike OAuth API\nActions: query device\nOutputs: observables" + }, + "input_spec": [ + { + "contains": [ + "host name", + "ip" + ], + "description": "A hostname that has a Crowdstrike agent.", + "name": "device" + } + ], + "output_spec": [ + { + "contains": [], + "datapaths": [ + "build_ip_observables:custom_function:observable_array", + "build_hostname_observables:custom_function:observable_array" + ], + "deduplicate": false, + "description": "An array of observable dictionaries ", + "metadata": {}, + "name": "observable" + } + ], + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-03-02T13:59:05.442614+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "attributes", + "device", + "host name", + "ip", + "crowdstrike_oauth_api" + ] +} \ No newline at end of file diff --git a/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.png b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b602e91a3a72c5e3cd2f914ed69bfccb77f52e GIT binary patch literal 67919 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 F=RcNi4y*tG literal 0 HcmV?d00001 diff --git a/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.py b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.py new file mode 100644 index 0000000000..546de5c058 --- /dev/null +++ b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.py @@ -0,0 +1,464 @@ +""" +Accepts device and looks up the most recent attributes for that hostname or IP. This playbook produces a normalized output for each device. +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'device_id_input_filter' block + device_id_input_filter(container=container) + + return + +@phantom.playbook_block() +def device_id_input_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("device_id_input_filter() called") + + ################################################################################ + # Ensure that device input exists + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["playbook_input:device", "!=", None] + ], + name="device_id_input_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + extract_ipv4(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def query_hostname(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("query_hostname() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Search for devices that have the hostname given to playbook input. + ################################################################################ + + format_hostname_filter__as_list = phantom.get_format_data(name="format_hostname_filter__as_list") + + parameters = [] + + # build parameters list for 'query_hostname' call + for format_hostname_filter__item in format_hostname_filter__as_list: + parameters.append({ + "limit": 10, + "filter": format_hostname_filter__item, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("query device", parameters=parameters, name="query_hostname", assets=["crowdstrike"], callback=filter_hostname_results) + + return + + +@phantom.playbook_block() +def build_hostname_observables(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_hostname_observables() called") + + ################################################################################ + # Generate an observable dictionary to output into the observables data path. + ################################################################################ + + filtered_result_0_data_filter_hostname_results = phantom.collect2(container=container, datapath=["filtered-data:filter_hostname_results:condition_1:query_hostname:action_result.data","filtered-data:filter_hostname_results:condition_1:query_hostname:action_result.parameter.filter"]) + + filtered_result_0_data = [item[0] for item in filtered_result_0_data_filter_hostname_results] + filtered_result_0_parameter_filter = [item[1] for item in filtered_result_0_data_filter_hostname_results] + + build_hostname_observables__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + build_hostname_observables__observable_array = [] + device_type_dict = { + 'server': 1, + 'desktop': 2, + 'laptop': 3, + 'tablet': 4, + 'mobile': 5, + 'virtual': 6, + 'iot': 7, + 'browser': 8 + } + for item, input_string in zip(filtered_result_0_data, filtered_result_0_parameter_filter): + device = item[0] + device_dict = { + "type": "host name", + "value": input_string.replace("hostname:", "").replace('"', ""), + "source": "Crowdstrike OAuth API", + "attributes": { + "desc": f"{device.get('system_product_name', 'No product name')} - {device.get('os_product_name', 'No os name')}", + "groups": device.get('groups'), + "hostname": device.get('hostname'), + "ip": device.get('connection_ip'), + "mac": device.get('mac_address'), + "name": device.get('hostname'), + "os": device.get('os_version'), + "hw_info": { + "bios_manufacturer": device.get('bios_manufacturer'), + "bios_ver": device.get('bios_version'), + "serial_number": device.get('serial_number') + }, + "type": "Unknown", + "type_id": 0, + "uid": device.get('device_id') + } + } + if device.get('product_type_desc'): + if device_type_dict.get(device['product_type_desc'].lower()): + device_dict['attributes']['type'] = device['product_type_desc'] + device_dict['attributes']['type_id'] = device_type_dict[device['product_type_desc'].lower()] + else: + device_dict['attributes']['type'] = device['product_type_desc'] + device_dict['attributes']['type_id'] = 99 + + build_hostname_observables__observable_array.append(device_dict) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_hostname_observables:observable_array", value=json.dumps(build_hostname_observables__observable_array)) + + return + + +@phantom.playbook_block() +def format_hostname_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_hostname_filter() called") + + ################################################################################ + # Format a filter for the query device, while looping through playbook inputs. + ################################################################################ + + template = """%%\nhostname:\"{0}\"\n%%""" + + # parameter list for template variable replacement + parameters = [ + "filtered-data:ip_filter:condition_2:extract_ipv4:custom_function_result.data.input_value" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="format_hostname_filter") + + query_hostname(container=container) + + return + + +@phantom.playbook_block() +def extract_ipv4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("extract_ipv4() called") + + ################################################################################ + # Extract IP address from input device + ################################################################################ + + filtered_input_0_device = phantom.collect2(container=container, datapath=["filtered-data:device_id_input_filter:condition_1:playbook_input:device"]) + + parameters = [] + + # build parameters list for 'extract_ipv4' call + for filtered_input_0_device_item in filtered_input_0_device: + parameters.append({ + "input_string": filtered_input_0_device_item[0], + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.custom_function(custom_function="community/regex_extract_ipv4", parameters=parameters, name="extract_ipv4", callback=ip_filter) + + return + + +@phantom.playbook_block() +def ip_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("ip_filter() called") + + ################################################################################ + # Determine which of the playbook inputs are devices or hostnames + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["extract_ipv4:custom_function_result.data.extracted_ipv4", "!=", None] + ], + name="ip_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + format_ip_filter(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + # collect filtered artifact ids and results for 'if' condition 2 + matched_artifacts_2, matched_results_2 = phantom.condition( + container=container, + conditions=[ + ["extract_ipv4:custom_function_result.data.extracted_ipv4", "==", None] + ], + name="ip_filter:condition_2") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_2 or matched_results_2: + format_hostname_filter(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2) + + return + + +@phantom.playbook_block() +def format_ip_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_ip_filter() called") + + ################################################################################ + # Format a filter for the query device, while looping through playbook inputs. + ################################################################################ + + template = """%%\nlocal_ip:\"{0}\",external_ip:\"{0}\"\n%%""" + + # parameter list for template variable replacement + parameters = [ + "filtered-data:ip_filter:condition_1:extract_ipv4:custom_function_result.data.extracted_ipv4" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="format_ip_filter") + + query_ip(container=container) + + return + + +@phantom.playbook_block() +def query_ip(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("query_ip() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Search for devices that have the IP given to playbook input. + ################################################################################ + + format_ip_filter__as_list = phantom.get_format_data(name="format_ip_filter__as_list") + + parameters = [] + + # build parameters list for 'query_ip' call + for format_ip_filter__item in format_ip_filter__as_list: + parameters.append({ + "limit": 10, + "filter": format_ip_filter__item, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("query device", parameters=parameters, name="query_ip", assets=["crowdstrike"], callback=filter_ip_results) + + return + + +@phantom.playbook_block() +def build_ip_observables(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_ip_observables() called") + + ################################################################################ + # Generate an observable dictionary to output into the observables data path. + ################################################################################ + + filtered_result_0_data_filter_ip_results = phantom.collect2(container=container, datapath=["filtered-data:filter_ip_results:condition_1:query_ip:action_result.data","filtered-data:filter_ip_results:condition_1:query_ip:action_result.parameter.filter"]) + + filtered_result_0_data = [item[0] for item in filtered_result_0_data_filter_ip_results] + filtered_result_0_parameter_filter = [item[1] for item in filtered_result_0_data_filter_ip_results] + + build_ip_observables__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + build_ip_observables__observable_array = [] + device_type_dict = { + 'server': 1, + 'desktop': 2, + 'laptop': 3, + 'tablet': 4, + 'mobile': 5, + 'virtual': 6, + 'iot': 7, + 'browser': 8 + } + for item, input_string in zip(filtered_result_0_data, filtered_result_0_parameter_filter): + device = item[0] + value = input_string.replace("local_ip:", "").replace('external_ip', "").replace('"',"") + value = value.split(',')[0] + device_dict = { + "type": "ip", + "value": value, + "source": "Crowdstrike OAuth API", + "attributes": { + "desc": f"{device.get('system_product_name', 'No product name')} - {device.get('os_product_name', 'No os name')}", + "groups": device.get('groups'), + "hostname": device.get('hostname'), + "ip": device.get('connection_ip'), + "mac": device.get('mac_address'), + "name": device.get('hostname'), + "os": device.get('os_version'), + "hw_info": { + "bios_manufacturer": device.get('bios_manufacturer'), + "bios_ver": device.get('bios_version'), + "serial_number": device.get('serial_number') + }, + "type": "Unknown", + "type_id": 0, + "uid": device.get('device_id') + } + } + if device.get('product_type_desc'): + if device_type_dict.get(device['product_type_desc'].lower()): + device_dict['attributes']['type'] = device['product_type_desc'] + device_dict['attributes']['type_id'] = device_type_dict[device['product_type_desc'].lower()] + else: + device_dict['attributes']['type'] = device['product_type_desc'] + device_dict['attributes']['type_id'] = 99 + + build_ip_observables__observable_array.append(device_dict) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_ip_observables:observable_array", value=json.dumps(build_ip_observables__observable_array)) + + return + + +@phantom.playbook_block() +def filter_hostname_results(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_hostname_results() called") + + ################################################################################ + # Filter on hostnames that returned results. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["query_hostname:action_result.summary.total_devices", ">", 0] + ], + name="filter_hostname_results:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + build_hostname_observables(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def filter_ip_results(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_ip_results() called") + + ################################################################################ + # Filter on IPs that returned results. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["query_ip:action_result.summary.total_devices", ">", 0] + ], + name="filter_ip_results:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + build_ip_observables(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + build_ip_observables__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_ip_observables:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + build_hostname_observables__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_hostname_observables:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + observable_combined_value = phantom.concatenate(build_ip_observables__observable_array, build_hostname_observables__observable_array) + + output = { + "observable": observable_combined_value, + } + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_playbook_output_data(output=output) + + return \ No newline at end of file diff --git a/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.yml b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.yml new file mode 100644 index 0000000000..6cbad29ae4 --- /dev/null +++ b/playbooks/CrowdStrike_OAuth_API_Device_Attribute_Lookup.yml @@ -0,0 +1,25 @@ +name: Crowdstrike OAuth API Device Attribute Lookup +id: fc0eac01-af2b-4cb0-7b4d-63da67d3fe74 +version: 1 +date: '2023-01-11' +author: Teoderick Contreras, Splunk +type: Investigation +description: "Accepts a user or device and looks up the most recent attributes and groups for that user or device. This playbook produces a normalized output for each user and device." +playbook: Crowdstrike_OAuth_API_Device_Attribute_Lookup +how_to_implement: This input playbook requires the Crowdstrike OAuth API connector to be configured. It is designed to work in conjunction with the Dynamic Attribute Lookup playbook or other playbooks in the same style. +references: [] +app_list: + - Crowdstrike OAuth API +tags: + platform_tags: + - attributes + - user + - device + - host name + - ip + - crowdstrike_oauth_api + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR \ No newline at end of file From dc5e5ed50ac36b7cb00ff4fe7524d604154bce0e Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Mon, 6 Mar 2023 10:58:24 -0600 Subject: [PATCH 4/4] Dynamic Attribute Lookup playbook --- playbooks/Dynamic_Attribute_Lookup.json | 791 ++++++++++++++++++++++++ playbooks/Dynamic_Attribute_Lookup.png | Bin 0 -> 69158 bytes playbooks/Dynamic_Attribute_Lookup.py | 304 +++++++++ playbooks/Dynamic_Attribute_Lookup.yml | 18 + 4 files changed, 1113 insertions(+) create mode 100644 playbooks/Dynamic_Attribute_Lookup.json create mode 100644 playbooks/Dynamic_Attribute_Lookup.png create mode 100644 playbooks/Dynamic_Attribute_Lookup.py create mode 100644 playbooks/Dynamic_Attribute_Lookup.yml diff --git a/playbooks/Dynamic_Attribute_Lookup.json b/playbooks/Dynamic_Attribute_Lookup.json new file mode 100644 index 0000000000..0e8492709f --- /dev/null +++ b/playbooks/Dynamic_Attribute_Lookup.json @@ -0,0 +1,791 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Attribute Lookup", + "coa": { + "data": { + "description": "Detects available entities and routes them to attribute lookup playbooks. The output of the playbooks will create new artifacts for any technologies that returned information.", + "edges": [ + { + "id": "port_0_to_port_2", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_2_to_port_3", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "3", + "targetPort": "3_in" + }, + { + "conditions": [ + { + "index": 1 + } + ], + "id": "port_2_to_port_4", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "4", + "targetPort": "4_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_3_to_port_5", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "5", + "targetPort": "5_in" + }, + { + "id": "port_5_to_port_7", + "sourceNode": "5", + "sourcePort": "5_out", + "targetNode": "7", + "targetPort": "7_in" + }, + { + "conditions": [ + { + "index": 1 + } + ], + "id": "port_7_to_port_8", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "8", + "targetPort": "8_in" + }, + { + "id": "port_6_to_port_9", + "sourceNode": "6", + "sourcePort": "6_out", + "targetNode": "9", + "targetPort": "9_in" + }, + { + "id": "port_9_to_port_1", + "sourceNode": "9", + "sourcePort": "9_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_7_to_port_10", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "10", + "targetPort": "10_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_10_to_port_6", + "sourceNode": "10", + "sourcePort": "10_out", + "targetNode": "6", + "targetPort": "6_in" + } + ], + "hash": "da5ffd389f3e278ac939229d65f40ab122d422fe", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 300, + "y": -6.394884621840902e-14 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 300, + "y": 1536 + }, + "10": { + "data": { + "advanced": { + "customName": "observable filter", + "customNameId": 0, + "description": "Exclude Null playbook outputs", + "join": [], + "note": "Exclude Null playbook outputs" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "dispatch_attribute_lookup:playbook_output:observable", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "observable not none", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "observable_filter", + "id": "10", + "type": "filter" + }, + "errors": {}, + "id": "10", + "type": "filter", + "warnings": {}, + "x": 340, + "y": 852 + }, + "2": { + "data": { + "advanced": { + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "artifact:*.id", + "value": "" + } + ], + "conditionIndex": 0, + "customName": "artifact exists", + "display": "If", + "logic": "and", + "type": "if" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "==", + "param": "", + "value": "" + } + ], + "conditionIndex": 1, + "customName": "artifact does not exist", + "display": "Else", + "logic": "and", + "type": "else" + } + ], + "functionId": 1, + "functionName": "decision_1", + "id": "2", + "type": "decision" + }, + "errors": {}, + "id": "2", + "type": "decision", + "warnings": {}, + "x": 360, + "y": 148 + }, + "3": { + "data": { + "advanced": { + "customName": "new artifact filter", + "customNameId": 0, + "description": "Only include new artifacts", + "join": [], + "note": "Only include new artifacts" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "artifact:*.id", + "value": "" + } + ], + "conditionIndex": 0, + "customName": "artifacts", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "new_artifact_filter", + "id": "3", + "type": "filter" + }, + "errors": {}, + "id": "3", + "type": "filter", + "warnings": {}, + "x": 200, + "y": 328 + }, + "4": { + "data": { + "advanced": { + "description": "Leave a comment indicating no new artifacts were found", + "join": [], + "note": "Leave a comment indicating no new artifacts were found" + }, + "functionId": 1, + "functionName": "add_comment_1", + "id": "4", + "selectMore": false, + "tab": "apis", + "type": "utility", + "utilities": { + "comment": { + "description": "", + "fields": [ + { + "description": "", + "label": "comment", + "name": "comment", + "placeholder": "Enter a comment", + "renderType": "datapath", + "required": true + }, + { + "hidden": true, + "name": "container", + "required": false + }, + { + "hidden": true, + "name": "author", + "required": false + }, + { + "hidden": true, + "name": "trace", + "required": false + } + ], + "label": "add comment", + "name": "comment" + } + }, + "utilityType": "api", + "values": { + "comment": { + "_internal": [ + "container", + "author", + "trace" + ], + "comment": "No new artifacts found." + } + } + }, + "errors": {}, + "id": "4", + "type": "utility", + "warnings": {}, + "x": 420, + "y": 329 + }, + "5": { + "data": { + "advanced": { + "customName": "Dispatch Attribute Lookup", + "customNameId": 0, + "join": [] + }, + "functionId": 1, + "functionName": "dispatch_attribute_lookup", + "id": "5", + "inputs": { + "artifact_ids_include": { + "datapaths": [ + "filtered-data:new_artifact_filter:condition_1:artifact:*.id" + ], + "deduplicate": false + }, + "indicator_tags_exclude": { + "datapaths": [], + "deduplicate": false + }, + "indicator_tags_include": { + "datapaths": [], + "deduplicate": false + }, + "playbook_repo": { + "datapaths": [ + "" + ], + "deduplicate": false + }, + "playbook_tags": { + "datapaths": [ + "attributes" + ], + "deduplicate": false + } + }, + "playbookName": "dispatch_input_playbooks", + "playbookRepo": 3, + "playbookRepoName": "community", + "playbookType": "data", + "synchronous": true, + "type": "playbook" + }, + "errors": {}, + "id": "5", + "type": "playbook", + "userCode": "\n # Write your custom code here...\n\n", + "warnings": {}, + "x": 140, + "y": 508 + }, + "6": { + "customCode": null, + "data": { + "advanced": { + "customName": "create entity artifact", + "customNameId": 0, + "description": "Create new artifacts with the outputs of the dispatch lookup (Contains custom code)", + "join": [], + "note": "Create new artifacts with the outputs of the dispatch lookup (Contains custom code)" + }, + "customFunction": { + "draftMode": false, + "name": "artifact_create", + "repoName": "community" + }, + "functionId": 2, + "functionName": "create_entity_artifact", + "id": "6", + "selectMore": false, + "tab": "customFunctions", + "type": "utility", + "utilities": { + "artifact_create": { + "description": "Create a new artifact with the specified attributes. Supports all fields available in /rest/artifact. Add any unlisted inputs as dictionary keys in input_json. Unsupported keys will automatically be dropped.", + "fields": [ + { + "dataTypes": [ + "phantom container id" + ], + "description": "Container which the artifact will be added to.", + "inputType": "item", + "label": "container", + "name": "container", + "placeholder": "container:id", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "The name of the new artifact, which is optional and defaults to \"artifact\".", + "inputType": "item", + "label": "name", + "name": "name", + "placeholder": "artifact", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "The label of the new artifact, which is optional and defaults to \"events\"", + "inputType": "item", + "label": "label", + "name": "label", + "placeholder": "events", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "" + ], + "description": "The severity of the new artifact, which is optional and defaults to \"Medium\". Typically this is either \"High\", \"Medium\", or \"Low\".", + "inputType": "item", + "label": "severity", + "name": "severity", + "placeholder": "Medium", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "The name of the CEF field to populate in the artifact, such as \"destinationAddress\" or \"sourceDnsDomain\". Required only if cef_value is provided.", + "inputType": "item", + "label": "cef_field", + "name": "cef_field", + "placeholder": "destinationAddress", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "*" + ], + "description": "The value of the CEF field to populate in the artifact, such as the IP address, domain name, or file hash. Required only if cef_field is provided.", + "inputType": "item", + "label": "cef_value", + "name": "cef_value", + "placeholder": "192.0.2.192", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "The CEF data type of the data in cef_value. For example, this could be \"ip\", \"hash\", or \"domain\". Optional.", + "inputType": "item", + "label": "cef_data_type", + "name": "cef_data_type", + "placeholder": "ip", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "A comma-separated list of tags to apply to the created artifact, which is optional.", + "inputType": "item", + "label": "tags", + "name": "tags", + "placeholder": "tag1, tag2, tag3", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "Either \"true\" or \"false\", depending on whether or not the new artifact should trigger the execution of any playbooks that are set to active on the label of the container the artifact will be added to. Optional and defaults to \"false\".", + "inputType": "item", + "label": "run_automation", + "name": "run_automation", + "placeholder": "false", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [], + "description": "Optional parameter to modify any extra attributes of the artifact. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.", + "inputType": "item", + "label": "input_json", + "name": "input_json", + "placeholder": "{\"source_data_identifier\": \"1234\", \"data\": \"5678\"}", + "renderType": "datapath", + "required": false + } + ], + "label": "artifact_create", + "name": "artifact_create" + } + }, + "utilityType": "custom_function", + "values": { + "artifact_create": { + "cef_data_type": null, + "cef_field": null, + "cef_value": null, + "container": "container:id", + "input_json": "", + "label": "attribute_lookup", + "name": "filtered-data:observable_filter:condition_1:dispatch_attribute_lookup:playbook_output:observable", + "run_automation": null, + "severity": null, + "tags": null + } + } + }, + "errors": {}, + "id": "6", + "type": "utility", + "userCode": "\n parameters = []\n \n for filtered_output_0_dispatch_attribute_lookup_output_observable_item in filtered_output_0_dispatch_attribute_lookup_output_observable:\n name = (\n f\"{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['type'].capitalize()} \"\n f\"\\'{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['value']}\\' \"\n f\"details from \"\n f\"{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['source']}\"\n )\n cef_dict = {\n \"cef\": filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['attributes']\n }\n parameters.append({\n \"name\": name,\n \"tags\": None,\n \"label\": \"attribute_lookup\",\n \"severity\": None,\n \"cef_field\": None,\n \"cef_value\": None,\n \"container\": id_value,\n \"input_json\": json.dumps(cef_dict),\n \"cef_data_type\": None,\n \"run_automation\": None,\n })\n", + "warnings": {}, + "x": 280, + "y": 1220 + }, + "7": { + "data": { + "advanced": { + "customName": "observable decision", + "customNameId": 0, + "description": "Determine if there are any results from the dispatch playbook", + "join": [], + "note": "Determine if there are any results from the dispatch playbook" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "dispatch_attribute_lookup:playbook_output:observable", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "observables exist", + "display": "If", + "logic": "and", + "type": "if" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "==", + "param": "", + "value": "" + } + ], + "conditionIndex": 1, + "customName": "observables do not exist", + "display": "Else", + "logic": "and", + "type": "else" + } + ], + "functionId": 2, + "functionName": "observable_decision", + "id": "7", + "type": "decision" + }, + "errors": {}, + "id": "7", + "type": "decision", + "warnings": {}, + "x": 220, + "y": 672 + }, + "8": { + "data": { + "advanced": { + "description": "Leave a comment indicating the playbooks did not have results.", + "join": [], + "note": "Leave a comment indicating the playbooks did not have results." + }, + "functionId": 3, + "functionName": "add_comment_3", + "id": "8", + "selectMore": false, + "tab": "apis", + "type": "utility", + "utilities": { + "comment": { + "description": "", + "fields": [ + { + "description": "", + "label": "comment", + "name": "comment", + "placeholder": "Enter a comment", + "renderType": "datapath", + "required": true + }, + { + "hidden": true, + "name": "container", + "required": false + }, + { + "hidden": true, + "name": "author", + "required": false + }, + { + "hidden": true, + "name": "trace", + "required": false + } + ], + "label": "add comment", + "name": "comment" + } + }, + "utilityType": "api", + "values": { + "comment": { + "_internal": [ + "container", + "author", + "trace" + ], + "comment": "No observable data found." + } + } + }, + "errors": {}, + "id": "8", + "type": "utility", + "warnings": {}, + "x": 0, + "y": 853 + }, + "9": { + "data": { + "advanced": { + "join": [] + }, + "customFunction": { + "draftMode": false, + "name": "workbook_task_update", + "repoName": "community" + }, + "functionId": 4, + "functionName": "workbook_task_update_4", + "id": "9", + "selectMore": false, + "tab": "customFunctions", + "type": "utility", + "utilities": { + "workbook_task_update": { + "description": "Update a workbook task by task name", + "fields": [ + { + "dataTypes": [ + "*" + ], + "description": "Name of a workbook task (Required)", + "inputType": "item", + "label": "task_name", + "name": "task_name", + "placeholder": "my_task", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "*" + ], + "description": "Note title goes here (Optional)", + "inputType": "item", + "label": "note_title", + "name": "note_title", + "placeholder": "My Title", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "*" + ], + "description": "Body of note goes here (Optional)", + "inputType": "item", + "label": "note_content", + "name": "note_content", + "placeholder": "My notes", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "*" + ], + "description": "One of: incomplete, in_progress, complete (Optional)", + "inputType": "item", + "label": "status", + "name": "status", + "placeholder": "in_progress", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "*" + ], + "description": "Assigns task to provided owner. Accepts keyword 'current\" to assign task to currently running playbook user. (Optional)", + "inputType": "item", + "label": "owner", + "name": "owner", + "placeholder": "username", + "renderType": "datapath", + "required": false + }, + { + "dataTypes": [ + "phantom container id" + ], + "description": "ID of Phantom Container (Required)", + "inputType": "item", + "label": "container", + "name": "container", + "placeholder": "container:id", + "renderType": "datapath", + "required": false + } + ], + "label": "workbook_task_update", + "name": "workbook_task_update" + } + }, + "utilityType": "custom_function", + "values": { + "workbook_task_update": { + "container": "container:id", + "note_content": null, + "note_title": null, + "owner": null, + "status": "complete", + "task_name": "playbook" + } + } + }, + "errors": {}, + "id": "9", + "type": "utility", + "warnings": {}, + "x": 280, + "y": 1388 + } + }, + "notes": "Outputs: \n- Creates artifacts for attribute details\n- Concludes task" + }, + "input_spec": null, + "output_spec": null, + "playbook_type": "automation", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-03-02T14:39:31.825576+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [] +} \ No newline at end of file diff --git a/playbooks/Dynamic_Attribute_Lookup.png b/playbooks/Dynamic_Attribute_Lookup.png new file mode 100644 index 0000000000000000000000000000000000000000..245b94ad6b3579a05648eaabd214d95e02ef946a GIT binary patch literal 69158 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 TGBnW?;73zc?{d{8o5+6v@Aewu literal 0 HcmV?d00001 diff --git a/playbooks/Dynamic_Attribute_Lookup.py b/playbooks/Dynamic_Attribute_Lookup.py new file mode 100644 index 0000000000..56e69e5734 --- /dev/null +++ b/playbooks/Dynamic_Attribute_Lookup.py @@ -0,0 +1,304 @@ +""" +Detects available entities and routes them to attribute lookup playbooks. The output of the playbooks will create new artifacts for any technologies that returned information. +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'decision_1' block + decision_1(container=container) + + return + +@phantom.playbook_block() +def decision_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("decision_1() called") + + # check for 'if' condition 1 + found_match_1 = phantom.decision( + container=container, + conditions=[ + ["artifact:*.id", "!=", ""] + ]) + + # call connected blocks if condition 1 matched + if found_match_1: + new_artifact_filter(action=action, success=success, container=container, results=results, handle=handle) + return + + # check for 'else' condition 2 + add_comment_1(action=action, success=success, container=container, results=results, handle=handle) + + return + + +@phantom.playbook_block() +def new_artifact_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("new_artifact_filter() called") + + ################################################################################ + # Only include new artifacts + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["artifact:*.id", "!=", ""] + ], + name="new_artifact_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + dispatch_attribute_lookup(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def add_comment_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("add_comment_1() called") + + ################################################################################ + # Leave a comment indicating no new artifacts were found + ################################################################################ + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.comment(container=container, comment="No new artifacts found.") + + return + + +@phantom.playbook_block() +def dispatch_attribute_lookup(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("dispatch_attribute_lookup() called") + + filtered_artifact_0_data_new_artifact_filter = phantom.collect2(container=container, datapath=["filtered-data:new_artifact_filter:condition_1:artifact:*.id"]) + + filtered_artifact_0__id = [item[0] for item in filtered_artifact_0_data_new_artifact_filter] + + inputs = { + "playbook_tags": ["attributes"], + "playbook_repo": [""], + "indicator_tags_include": [], + "indicator_tags_exclude": [], + "artifact_ids_include": filtered_artifact_0__id, + } + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + # call playbook "community/dispatch_input_playbooks", returns the playbook_run_id + playbook_run_id = phantom.playbook("community/dispatch_input_playbooks", container=container, name="dispatch_attribute_lookup", callback=observable_decision, inputs=inputs) + + return + + +@phantom.playbook_block() +def create_entity_artifact(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("create_entity_artifact() called") + + ################################################################################ + # Create new artifacts with the outputs of the dispatch lookup (Contains custom + # code) + ################################################################################ + + id_value = container.get("id", None) + filtered_output_0_dispatch_attribute_lookup_output_observable = phantom.collect2(container=container, datapath=["filtered-data:observable_filter:condition_1:dispatch_attribute_lookup:playbook_output:observable"]) + + parameters = [] + + # build parameters list for 'create_entity_artifact' call + for filtered_output_0_dispatch_attribute_lookup_output_observable_item in filtered_output_0_dispatch_attribute_lookup_output_observable: + parameters.append({ + "name": filtered_output_0_dispatch_attribute_lookup_output_observable_item[0], + "tags": None, + "label": "attribute_lookup", + "severity": None, + "cef_field": None, + "cef_value": None, + "container": id_value, + "input_json": None, + "cef_data_type": None, + "run_automation": None, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + parameters = [] + + for filtered_output_0_dispatch_attribute_lookup_output_observable_item in filtered_output_0_dispatch_attribute_lookup_output_observable: + name = ( + f"{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['type'].capitalize()} " + f"\'{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['value']}\' " + f"details from " + f"{filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['source']}" + ) + cef_dict = { + "cef": filtered_output_0_dispatch_attribute_lookup_output_observable_item[0]['attributes'] + } + parameters.append({ + "name": name, + "tags": None, + "label": "attribute_lookup", + "severity": None, + "cef_field": None, + "cef_value": None, + "container": id_value, + "input_json": json.dumps(cef_dict), + "cef_data_type": None, + "run_automation": None, + }) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.custom_function(custom_function="community/artifact_create", parameters=parameters, name="create_entity_artifact", callback=workbook_task_update_4) + + return + + +@phantom.playbook_block() +def observable_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("observable_decision() called") + + ################################################################################ + # Determine if there are any results from the dispatch playbook + ################################################################################ + + # check for 'if' condition 1 + found_match_1 = phantom.decision( + container=container, + conditions=[ + ["dispatch_attribute_lookup:playbook_output:observable", "!=", None] + ]) + + # call connected blocks if condition 1 matched + if found_match_1: + observable_filter(action=action, success=success, container=container, results=results, handle=handle) + return + + # check for 'else' condition 2 + add_comment_3(action=action, success=success, container=container, results=results, handle=handle) + + return + + +@phantom.playbook_block() +def add_comment_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("add_comment_3() called") + + ################################################################################ + # Leave a comment indicating the playbooks did not have results. + ################################################################################ + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.comment(container=container, comment="No observable data found.") + + return + + +@phantom.playbook_block() +def workbook_task_update_4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("workbook_task_update_4() called") + + id_value = container.get("id", None) + + parameters = [] + + parameters.append({ + "owner": None, + "status": "complete", + "container": id_value, + "task_name": "playbook", + "note_title": None, + "note_content": None, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.custom_function(custom_function="community/workbook_task_update", parameters=parameters, name="workbook_task_update_4") + + return + + +@phantom.playbook_block() +def observable_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("observable_filter() called") + + ################################################################################ + # Exclude Null playbook outputs + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["dispatch_attribute_lookup:playbook_output:observable", "!=", None] + ], + name="observable_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + create_entity_artifact(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + return \ No newline at end of file diff --git a/playbooks/Dynamic_Attribute_Lookup.yml b/playbooks/Dynamic_Attribute_Lookup.yml new file mode 100644 index 0000000000..b7832662c5 --- /dev/null +++ b/playbooks/Dynamic_Attribute_Lookup.yml @@ -0,0 +1,18 @@ +name: Dynamic Attribute Lookup +id: fc0edc96-ff2b-68d0-9a4d-63da6783fd64 +version: 1 +date: '2023-03-06' +author: Lou Stella, Splunk +type: Investigation +description: "Detects available entities and routes them to attribute lookup playbooks. The output of the playbooks will create new artifacts for any technologies that returned information." +playbook: Dynamic_Attribute_Lookup +how_to_implement: This playbook looks for artifacts and then dispatches the community Attribute Lookup playbooks. This playbook takes the output of those playbooks and nicely formats them into new artifacts with their results. +references: [] +app_list: [] +tags: + platform_tags: [] + playbook_type: Automation + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR