From a102421a6b703a0644db12dc202567d4e585fbff Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Thu, 30 Mar 2023 18:12:05 -0500 Subject: [PATCH 1/5] Initial Commit - Windows Defender ATP Identifier Activity Analysis --- ...nder_ATP_Identifier_Activity_Analysis.json | 495 ++++++++++++++++++ ...ender_ATP_Identifier_Activity_Analysis.png | Bin 0 -> 65967 bytes ...fender_ATP_Identifier_Activity_Analysis.py | 354 +++++++++++++ ...ender_ATP_Identifier_Activity_Analysis.yml | 22 + 4 files changed, 871 insertions(+) create mode 100644 playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json create mode 100644 playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.png create mode 100644 playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py create mode 100644 playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.yml diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json new file mode 100644 index 0000000000..46255745bf --- /dev/null +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json @@ -0,0 +1,495 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Identifier Activity Analysis", + "coa": { + "data": { + "description": "Accepts a file_hash or domain name, and asks Windows Defender ATP for a list of devices that have interacted with each. It then produces a normalized output and summary table.", + "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" + }, + { + "id": "port_3_to_port_5", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "5", + "targetPort": "5_in" + }, + { + "id": "port_4_to_port_6", + "sourceNode": "4", + "sourcePort": "4_out", + "targetNode": "6", + "targetPort": "6_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_5_to_port_7", + "sourceNode": "5", + "sourcePort": "5_out", + "targetNode": "7", + "targetPort": "7_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_6_to_port_8", + "sourceNode": "6", + "sourcePort": "6_out", + "targetNode": "8", + "targetPort": "8_in" + }, + { + "id": "port_7_to_port_9", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "9", + "targetPort": "9_in" + }, + { + "id": "port_8_to_port_10", + "sourceNode": "8", + "sourcePort": "8_out", + "targetNode": "10", + "targetPort": "10_in" + }, + { + "id": "port_9_to_port_1", + "sourceNode": "9", + "sourcePort": "9_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_10_to_port_1", + "sourceNode": "10", + "sourcePort": "10_out", + "targetNode": "1", + "targetPort": "1_in" + } + ], + "hash": "2da22b0256f06b4130bc597d0d103ef7edff9825", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 190, + "y": -1.9184653865522705e-13 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 200, + "y": 960 + }, + "10": { + "data": { + "advanced": { + "customName": "build domain output", + "customNameId": 0, + "join": [] + }, + "functionId": 2, + "functionName": "build_domain_output", + "id": "10", + "inputParameters": [ + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.parameter.domain", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.summary.total_devices" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "10", + "type": "code", + "userCode": "\n build_domain_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_domain[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"domain\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"devices\": device_list\n }\n \n build_domain_output__observable_array.append(observable_array)\n\n", + "warnings": {}, + "x": 340, + "y": 804 + }, + "2": { + "data": { + "advanced": { + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:file_hash", + "value": "None" + } + ], + "conditionIndex": 0, + "customName": "file_hash", + "logic": "and" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "!=", + "param": "playbook_input:domain", + "value": "None" + } + ], + "conditionIndex": 1, + "customName": "domain", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "filter_1", + "id": "2", + "type": "filter" + }, + "errors": {}, + "id": "2", + "type": "filter", + "warnings": { + "config": [ + "Reconfigure invalid datapath." + ] + }, + "x": 230, + "y": 148 + }, + "3": { + "data": { + "action": "get file devices", + "actionType": "investigate", + "advanced": { + "customName": "get file devices", + "customNameId": 0, + "join": [] + }, + "connector": "Windows Defender ATP", + "connectorConfigs": [ + "windows_defender_atp" + ], + "connectorId": "e85407b7-91f0-4019-8fa4-0d29bca741d5", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_file_devices", + "id": "3", + "parameters": { + "file_hash": "filtered-data:filter_1:condition_1:playbook_input:file_hash" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "file_hash" + } + ], + "type": "action" + }, + "errors": {}, + "id": "3", + "type": "action", + "warnings": {}, + "x": 0, + "y": 328 + }, + "4": { + "data": { + "action": "get domain devices", + "actionType": "investigate", + "advanced": { + "customName": "get domain devices", + "customNameId": 0, + "join": [] + }, + "connector": "Windows Defender ATP", + "connectorConfigs": [ + "windows_defender_atp" + ], + "connectorId": "e85407b7-91f0-4019-8fa4-0d29bca741d5", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_domain_devices", + "id": "4", + "parameters": { + "domain": "filtered-data:filter_1:condition_2:playbook_input:domain" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "domain" + } + ], + "type": "action" + }, + "errors": {}, + "id": "4", + "type": "action", + "warnings": {}, + "x": 340, + "y": 328 + }, + "5": { + "data": { + "advanced": { + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "get_file_devices:action_result.summary.total_devices", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "devices found", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "filter_2", + "id": "5", + "type": "filter" + }, + "errors": {}, + "id": "5", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 476 + }, + "6": { + "data": { + "advanced": { + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": ">", + "param": "get_domain_devices:action_result.summary.total_devices", + "value": "0" + } + ], + "conditionIndex": 0, + "customName": "devices found", + "logic": "and" + } + ], + "functionId": 3, + "functionName": "filter_3", + "id": "6", + "type": "filter" + }, + "errors": {}, + "id": "6", + "type": "filter", + "warnings": {}, + "x": 400, + "y": 480 + }, + "7": { + "data": { + "advanced": { + "customName": "format report file", + "customNameId": 0, + "join": [] + }, + "functionId": 1, + "functionName": "format_report_file", + "id": "7", + "parameters": [ + "get_file_devices:action_result.parameter.file_hash", + "get_file_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.osPlatform", + "get_file_devices:action_result.data.*.id" + ], + "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| File | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%\n", + "type": "format" + }, + "errors": {}, + "id": "7", + "type": "format", + "warnings": {}, + "x": 0, + "y": 660 + }, + "8": { + "data": { + "advanced": { + "customName": "format report domain", + "customNameId": 0, + "join": [] + }, + "functionId": 2, + "functionName": "format_report_domain", + "id": "8", + "parameters": [ + "get_domain_devices:action_result.parameter.domain", + "get_domain_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.osPlatform", + "get_domain_devices:action_result.data.*.id" + ], + "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| Domain | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%", + "type": "format" + }, + "errors": {}, + "id": "8", + "type": "format", + "warnings": {}, + "x": 340, + "y": 660 + }, + "9": { + "data": { + "advanced": { + "customName": "build file output", + "customNameId": 0, + "join": [] + }, + "functionId": 1, + "functionName": "build_file_output", + "id": "9", + "inputParameters": [ + "filtered-data:filter_2:condition_1:get_file_devices:action_result.parameter.file_hash", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.data", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.summary.total_devices" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "9", + "type": "code", + "userCode": "\n build_file_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_file_hash[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"file_hash\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"devices\": device_list\n }\n \n build_file_output__observable_array.append(observable_array)\n\n", + "warnings": {}, + "x": 0, + "y": 800 + } + }, + "notes": "Inputs: file_hash, domain\nInteractions: Windows Defender ATP\nActions: get file devices, get domain devices\nOutputs: observable, markdown report" + }, + "input_spec": [ + { + "contains": [ + "sha1" + ], + "description": "", + "name": "file_hash" + }, + { + "contains": [ + "domain" + ], + "description": "", + "name": "domain" + } + ], + "output_spec": [ + { + "contains": [], + "datapaths": [ + "build_file_output:custom_function:observable_array", + "build_domain_output:custom_function:observable_array" + ], + "deduplicate": false, + "description": "", + "metadata": {}, + "name": "observable" + }, + { + "contains": [], + "datapaths": [ + "format_report_file:formatted_data", + "format_report_domain:formatted_data" + ], + "deduplicate": false, + "description": "", + "metadata": {}, + "name": "markdown_report" + } + ], + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-03-30T23:04:33.691605+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "identifier_activity", + "file_hash", + "domain", + "windows_defender_atp" + ] +} \ No newline at end of file diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.png b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.png new file mode 100644 index 0000000000000000000000000000000000000000..28d51b9eda5a578b5fa852d3c8e5e92e4b77f7c2 GIT binary patch literal 65967 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%0D=-n?HZ%d5X3~ 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 dXVb}_v", 0] + ], + name="filter_2:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + format_report_file(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_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_3() called") + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["get_domain_devices:action_result.summary.total_devices", ">", 0] + ], + name="filter_3:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + format_report_domain(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_report_file(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_report_file() called") + + template = """SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| File | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%\n""" + + # parameter list for template variable replacement + parameters = [ + "get_file_devices:action_result.parameter.file_hash", + "get_file_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.osPlatform", + "get_file_devices:action_result.data.*.id" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="format_report_file") + + build_file_output(container=container) + + return + + +@phantom.playbook_block() +def format_report_domain(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("format_report_domain() called") + + template = """SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| Domain | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%""" + + # parameter list for template variable replacement + parameters = [ + "get_domain_devices:action_result.parameter.domain", + "get_domain_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.osPlatform", + "get_domain_devices:action_result.data.*.id" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="format_report_domain") + + build_domain_output(container=container) + + return + + +@phantom.playbook_block() +def build_file_output(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_file_output() called") + + filtered_result_0_data_filter_2 = phantom.collect2(container=container, datapath=["filtered-data:filter_2:condition_1:get_file_devices:action_result.parameter.file_hash","filtered-data:filter_2:condition_1:get_file_devices:action_result.data","filtered-data:filter_2:condition_1:get_file_devices:action_result.summary.total_devices"]) + + filtered_result_0_parameter_file_hash = [item[0] for item in filtered_result_0_data_filter_2] + filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_2] + filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_2] + + build_file_output__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + build_file_output__observable_array = [] + device_list = [] + indicator = filtered_result_0_parameter_file_hash[0] + count = filtered_result_0_summary_total_devices[0] + + # Build list of device objects + + for item in filtered_result_0_data: + device = item[0] + device_filtered = { + "name": device['computerDnsName'], + "id": device['id'], + "ip_address": device['lastIpAddress'], + "operating_system": device['osPlatform'] + } + device_list.append(device_filtered) + + # Build observable object + + observable_array = { + "indicator": indicator, + "type": "file_hash", + "total_count": count, + "source": "Defender ATP", + "devices": device_list + } + + build_file_output__observable_array.append(observable_array) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_file_output:observable_array", value=json.dumps(build_file_output__observable_array)) + + return + + +@phantom.playbook_block() +def build_domain_output(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_domain_output() called") + + filtered_result_0_data_filter_3 = phantom.collect2(container=container, datapath=["filtered-data:filter_3:condition_1:get_domain_devices:action_result.parameter.domain","filtered-data:filter_3:condition_1:get_domain_devices:action_result.data","filtered-data:filter_3:condition_1:get_domain_devices:action_result.summary.total_devices"]) + + filtered_result_0_parameter_domain = [item[0] for item in filtered_result_0_data_filter_3] + filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_3] + filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_3] + + build_domain_output__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + build_domain_output__observable_array = [] + device_list = [] + indicator = filtered_result_0_parameter_domain[0] + count = filtered_result_0_summary_total_devices[0] + + # Build list of device objects + + for item in filtered_result_0_data: + device = item[0] + device_filtered = { + "name": device['computerDnsName'], + "id": device['id'], + "ip_address": device['lastIpAddress'], + "operating_system": device['osPlatform'] + } + device_list.append(device_filtered) + + # Build observable object + + observable_array = { + "indicator": indicator, + "type": "domain", + "total_count": count, + "source": "Defender ATP", + "devices": device_list + } + + build_domain_output__observable_array.append(observable_array) + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_domain_output:observable_array", value=json.dumps(build_domain_output__observable_array)) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + format_report_file = phantom.get_format_data(name="format_report_file") + format_report_domain = phantom.get_format_data(name="format_report_domain") + build_file_output__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_file_output:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + build_domain_output__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_domain_output:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + observable_combined_value = phantom.concatenate(build_file_output__observable_array, build_domain_output__observable_array) + markdown_report_combined_value = phantom.concatenate(format_report_file, format_report_domain) + + output = { + "observable": observable_combined_value, + "markdown_report": markdown_report_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/Windows_Defender_ATP_Identifier_Activity_Analysis.yml b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.yml new file mode 100644 index 0000000000..dba4325b67 --- /dev/null +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.yml @@ -0,0 +1,22 @@ +name: Windows Defender ATP Identifier Activity Analysis +id: 5299d9dc-e9c4-46fa-da42-92ace0ff816d +version: 1 +date: '2023-03-30' +author: Lou Stella, Splunk +type: Investigation +description: "Accepts a file_hash or domain name, and asks Windows Defender ATP for a list of devices that have interacted with each. It then produces a normalized output and summary table." +playbook: Windows_Defender_ATP_Identifier_Activity_Analysis +how_to_implement: This input playbook requires the Windows Defender ATP connector to be configured. It is designed to work in conjunction with the Dynamic Identifier Activity Analysis playbook or other playbooks in the same style. +references: [] +app_list: + - Windows Defender ATP +tags: + platform_tags: + - identifier_activity + - domain + - file_hash + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR From 5d57cb992eb128b08a3fcefce7151461f0d37715 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Sat, 1 Apr 2023 16:08:19 -0500 Subject: [PATCH 2/5] updated observable output formatting --- ...dows_Defender_ATP_Identifier_Activity_Analysis.json | 10 +++++----- ...indows_Defender_ATP_Identifier_Activity_Analysis.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json index 46255745bf..58ab9868b9 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json @@ -104,7 +104,7 @@ "targetPort": "1_in" } ], - "hash": "2da22b0256f06b4130bc597d0d103ef7edff9825", + "hash": "ae16e22f1f383596069ab316dfbead6553de9a2e", "nodes": { "0": { "data": { @@ -120,7 +120,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": -1.9184653865522705e-13 + "y": -2.5579538487363607e-13 }, "1": { "data": { @@ -161,7 +161,7 @@ "errors": {}, "id": "10", "type": "code", - "userCode": "\n build_domain_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_domain[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"domain\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"devices\": device_list\n }\n \n build_domain_output__observable_array.append(observable_array)\n\n", + "userCode": "\n build_domain_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_domain[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"domain\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_domain_output__observable_array.append(observable_array)\n\n", "warnings": {}, "x": 340, "y": 804 @@ -428,7 +428,7 @@ "errors": {}, "id": "9", "type": "code", - "userCode": "\n build_file_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_file_hash[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"file_hash\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"devices\": device_list\n }\n \n build_file_output__observable_array.append(observable_array)\n\n", + "userCode": "\n build_file_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_file_hash[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"file_hash\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_file_output__observable_array.append(observable_array)\n\n", "warnings": {}, "x": 0, "y": 800 @@ -481,7 +481,7 @@ "schema": "5.0.9", "version": "6.0.0.114895" }, - "create_time": "2023-03-30T23:04:33.691605+00:00", + "create_time": "2023-04-01T21:05:50.161069+00:00", "draft_mode": false, "labels": [ "*" diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py index 05ca28290c..5d7a815063 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py @@ -254,7 +254,7 @@ def build_file_output(action=None, success=None, container=None, results=None, h "type": "file_hash", "total_count": count, "source": "Defender ATP", - "devices": device_list + "identifier_activity": device_list } build_file_output__observable_array.append(observable_array) @@ -308,7 +308,7 @@ def build_domain_output(action=None, success=None, container=None, results=None, "type": "domain", "total_count": count, "source": "Defender ATP", - "devices": device_list + "identifier_activity": device_list } build_domain_output__observable_array.append(observable_array) From 634ce1e66463a985c1ac7e5cf8f7c73896cf79a8 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Wed, 5 Apr 2023 12:55:11 -0500 Subject: [PATCH 3/5] Added tooltips + adjusted output fields --- ...nder_ATP_Identifier_Activity_Analysis.json | 46 +++++++++++-------- ...fender_ATP_Identifier_Activity_Analysis.py | 16 ++++++- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json index 58ab9868b9..ef471167c4 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json @@ -104,7 +104,7 @@ "targetPort": "1_in" } ], - "hash": "ae16e22f1f383596069ab316dfbead6553de9a2e", + "hash": "c6ea021941332995785c2f27e13e40fdfe568a18", "nodes": { "0": { "data": { @@ -120,7 +120,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": -2.5579538487363607e-13 + "y": 0 }, "1": { "data": { @@ -135,15 +135,17 @@ "id": "1", "type": "end", "warnings": {}, - "x": 200, - "y": 960 + "x": 190, + "y": 1042 }, "10": { "data": { "advanced": { "customName": "build domain output", "customNameId": 0, - "join": [] + "description": "Iterates through the objects returned by previous actions to create a list of devices, which is then appended to the rest of the Observable object that contains the context for that list", + "join": [], + "note": "Observable object creation" }, "functionId": 2, "functionName": "build_domain_output", @@ -161,10 +163,10 @@ "errors": {}, "id": "10", "type": "code", - "userCode": "\n build_domain_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_domain[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"domain\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_domain_output__observable_array.append(observable_array)\n\n", + "userCode": "\n build_domain_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_domain[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"value\": indicator,\n \"type\": \"domain\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_domain_output__observable_array.append(observable_array)\n\n", "warnings": {}, "x": 340, - "y": 804 + "y": 864 }, "2": { "data": { @@ -222,7 +224,8 @@ "advanced": { "customName": "get file devices", "customNameId": 0, - "join": [] + "join": [], + "note": "\"get file devices\" action which returns a list of devices that have seen the file queried for" }, "connector": "Windows Defender ATP", "connectorConfigs": [ @@ -258,7 +261,8 @@ "advanced": { "customName": "get domain devices", "customNameId": 0, - "join": [] + "join": [], + "note": "\"get domain devices\" action which returns a list of devices that have seen the domain queried for" }, "connector": "Windows Defender ATP", "connectorConfigs": [ @@ -317,7 +321,7 @@ "type": "filter", "warnings": {}, "x": 60, - "y": 476 + "y": 506 }, "6": { "data": { @@ -349,14 +353,15 @@ "type": "filter", "warnings": {}, "x": 400, - "y": 480 + "y": 506 }, "7": { "data": { "advanced": { "customName": "format report file", "customNameId": 0, - "join": [] + "join": [], + "note": "Markdown Report creation" }, "functionId": 1, "functionName": "format_report_file", @@ -376,14 +381,15 @@ "type": "format", "warnings": {}, "x": 0, - "y": 660 + "y": 686 }, "8": { "data": { "advanced": { "customName": "format report domain", "customNameId": 0, - "join": [] + "join": [], + "note": "Markdown Report creation" }, "functionId": 2, "functionName": "format_report_domain", @@ -403,14 +409,16 @@ "type": "format", "warnings": {}, "x": 340, - "y": 660 + "y": 686 }, "9": { "data": { "advanced": { "customName": "build file output", "customNameId": 0, - "join": [] + "description": "Iterates through the objects returned by previous actions to create a list of devices, which is then appended to the rest of the Observable object that contains the context for that list", + "join": [], + "note": "Observable object creation" }, "functionId": 1, "functionName": "build_file_output", @@ -428,10 +436,10 @@ "errors": {}, "id": "9", "type": "code", - "userCode": "\n build_file_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_file_hash[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"indicator\": indicator,\n \"type\": \"file_hash\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_file_output__observable_array.append(observable_array)\n\n", + "userCode": "\n build_file_output__observable_array = []\n device_list = []\n indicator = filtered_result_0_parameter_file_hash[0]\n count = filtered_result_0_summary_total_devices[0]\n \n # Build list of device objects\n \n for item in filtered_result_0_data:\n device = item[0]\n device_filtered = {\n \"name\": device['computerDnsName'],\n \"id\": device['id'],\n \"ip_address\": device['lastIpAddress'],\n \"operating_system\": device['osPlatform']\n }\n device_list.append(device_filtered)\n \n # Build observable object\n \n observable_array = {\n \"value\": indicator,\n \"type\": \"file_hash\",\n \"total_count\": count,\n \"source\": \"Defender ATP\",\n \"identifier_activity\": device_list\n }\n \n build_file_output__observable_array.append(observable_array)\n\n", "warnings": {}, "x": 0, - "y": 800 + "y": 864 } }, "notes": "Inputs: file_hash, domain\nInteractions: Windows Defender ATP\nActions: get file devices, get domain devices\nOutputs: observable, markdown report" @@ -481,7 +489,7 @@ "schema": "5.0.9", "version": "6.0.0.114895" }, - "create_time": "2023-04-01T21:05:50.161069+00:00", + "create_time": "2023-04-05T17:52:46.216500+00:00", "draft_mode": false, "labels": [ "*" diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py index 5d7a815063..e184abfc4e 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py @@ -218,6 +218,12 @@ def format_report_domain(action=None, success=None, container=None, results=None def build_file_output(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): phantom.debug("build_file_output() called") + ################################################################################ + # Iterates through the objects returned by previous actions to create a list of + # devices, which is then appended to the rest of the Observable object that contains + # the context for that list + ################################################################################ + filtered_result_0_data_filter_2 = phantom.collect2(container=container, datapath=["filtered-data:filter_2:condition_1:get_file_devices:action_result.parameter.file_hash","filtered-data:filter_2:condition_1:get_file_devices:action_result.data","filtered-data:filter_2:condition_1:get_file_devices:action_result.summary.total_devices"]) filtered_result_0_parameter_file_hash = [item[0] for item in filtered_result_0_data_filter_2] @@ -250,7 +256,7 @@ def build_file_output(action=None, success=None, container=None, results=None, h # Build observable object observable_array = { - "indicator": indicator, + "value": indicator, "type": "file_hash", "total_count": count, "source": "Defender ATP", @@ -272,6 +278,12 @@ def build_file_output(action=None, success=None, container=None, results=None, h def build_domain_output(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): phantom.debug("build_domain_output() called") + ################################################################################ + # Iterates through the objects returned by previous actions to create a list of + # devices, which is then appended to the rest of the Observable object that contains + # the context for that list + ################################################################################ + filtered_result_0_data_filter_3 = phantom.collect2(container=container, datapath=["filtered-data:filter_3:condition_1:get_domain_devices:action_result.parameter.domain","filtered-data:filter_3:condition_1:get_domain_devices:action_result.data","filtered-data:filter_3:condition_1:get_domain_devices:action_result.summary.total_devices"]) filtered_result_0_parameter_domain = [item[0] for item in filtered_result_0_data_filter_3] @@ -304,7 +316,7 @@ def build_domain_output(action=None, success=None, container=None, results=None, # Build observable object observable_array = { - "indicator": indicator, + "value": indicator, "type": "domain", "total_count": count, "source": "Defender ATP", From d50398ac3f549bdd03c59c7f07b118f91f79c747 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Fri, 14 Apr 2023 09:49:51 -0500 Subject: [PATCH 4/5] More tooltips, descriptions, naming --- ...nder_ATP_Identifier_Activity_Analysis.json | 60 +++++++++-------- ...fender_ATP_Identifier_Activity_Analysis.py | 64 ++++++++++--------- 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json index ef471167c4..dd20267b86 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json @@ -104,7 +104,7 @@ "targetPort": "1_in" } ], - "hash": "c6ea021941332995785c2f27e13e40fdfe568a18", + "hash": "b09360d8f57025be3b7987bb0e945bdc0c881598", "nodes": { "0": { "data": { @@ -120,7 +120,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": 0 + "y": -6.394884621840902e-14 }, "1": { "data": { @@ -151,9 +151,9 @@ "functionName": "build_domain_output", "id": "10", "inputParameters": [ - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.parameter.domain", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.summary.total_devices" + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.parameter.domain", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.summary.total_devices" ], "outputVariables": [ "observable_array" @@ -171,7 +171,11 @@ "2": { "data": { "advanced": { - "join": [] + "customName": "routing_artifacts", + "customNameId": 0, + "description": "Route SHA1 file hashes and domains respectively", + "join": [], + "note": "Route SHA1 file hashes and domains respectively" }, "conditions": [ { @@ -202,7 +206,7 @@ } ], "functionId": 1, - "functionName": "filter_1", + "functionName": "routing_artifacts", "id": "2", "type": "filter" }, @@ -237,7 +241,7 @@ "functionName": "get_file_devices", "id": "3", "parameters": { - "file_hash": "filtered-data:filter_1:condition_1:playbook_input:file_hash" + "file_hash": "filtered-data:routing_artifacts:condition_1:playbook_input:file_hash" }, "requiredParameters": [ { @@ -252,7 +256,7 @@ "type": "action", "warnings": {}, "x": 0, - "y": 328 + "y": 320 }, "4": { "data": { @@ -274,7 +278,7 @@ "functionName": "get_domain_devices", "id": "4", "parameters": { - "domain": "filtered-data:filter_1:condition_2:playbook_input:domain" + "domain": "filtered-data:routing_artifacts:condition_2:playbook_input:domain" }, "requiredParameters": [ { @@ -289,12 +293,15 @@ "type": "action", "warnings": {}, "x": 340, - "y": 328 + "y": 320 }, "5": { "data": { "advanced": { - "join": [] + "customName": "filter_file_response", + "customNameId": 0, + "join": [], + "note": "Esnure there are results for get_file_devices" }, "conditions": [ { @@ -302,7 +309,7 @@ { "conditionIndex": 0, "op": ">", - "param": "get_file_devices:action_result.summary.total_devices", + "param": "get_file_devices:action_result.summary.{summaryVar}", "value": "0" } ], @@ -312,7 +319,7 @@ } ], "functionId": 2, - "functionName": "filter_2", + "functionName": "filter_file_response", "id": "5", "type": "filter" }, @@ -326,7 +333,10 @@ "6": { "data": { "advanced": { - "join": [] + "customName": "filter_domain_response", + "customNameId": 0, + "join": [], + "note": "Esnure there are results for get_domain_devices" }, "conditions": [ { @@ -334,7 +344,7 @@ { "conditionIndex": 0, "op": ">", - "param": "get_domain_devices:action_result.summary.total_devices", + "param": "get_domain_devices:action_result.summary.{summaryVar}", "value": "0" } ], @@ -344,7 +354,7 @@ } ], "functionId": 3, - "functionName": "filter_3", + "functionName": "filter_domain_response", "id": "6", "type": "filter" }, @@ -369,8 +379,8 @@ "parameters": [ "get_file_devices:action_result.parameter.file_hash", "get_file_devices:action_result.data.*.computerDnsName", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.lastIpAddress", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.osPlatform", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.osPlatform", "get_file_devices:action_result.data.*.id" ], "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| File | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%\n", @@ -397,8 +407,8 @@ "parameters": [ "get_domain_devices:action_result.parameter.domain", "get_domain_devices:action_result.data.*.computerDnsName", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.osPlatform", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.osPlatform", "get_domain_devices:action_result.data.*.id" ], "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| Domain | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%", @@ -424,9 +434,9 @@ "functionName": "build_file_output", "id": "9", "inputParameters": [ - "filtered-data:filter_2:condition_1:get_file_devices:action_result.parameter.file_hash", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.data", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.summary.total_devices" + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.parameter.file_hash", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.summary.total_devices" ], "outputVariables": [ "observable_array" @@ -489,7 +499,7 @@ "schema": "5.0.9", "version": "6.0.0.114895" }, - "create_time": "2023-04-05T17:52:46.216500+00:00", + "create_time": "2023-04-14T14:48:13.695855+00:00", "draft_mode": false, "labels": [ "*" diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py index e184abfc4e..810a09b859 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py @@ -12,14 +12,18 @@ from datetime import datetime, timedelta def on_start(container): phantom.debug('on_start() called') - # call 'filter_1' block - filter_1(container=container) + # call 'routing_artifacts' block + routing_artifacts(container=container) return @phantom.playbook_block() -def filter_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("filter_1() called") +def routing_artifacts(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("routing_artifacts() called") + + ################################################################################ + # Route SHA1 file hashes and domains respectively + ################################################################################ # collect filtered artifact ids and results for 'if' condition 1 matched_artifacts_1, matched_results_1 = phantom.condition( @@ -27,7 +31,7 @@ def filter_1(action=None, success=None, container=None, results=None, handle=Non conditions=[ ["playbook_input:file_hash", "!=", None] ], - name="filter_1:condition_1") + name="routing_artifacts:condition_1") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: @@ -39,7 +43,7 @@ def filter_1(action=None, success=None, container=None, results=None, handle=Non conditions=[ ["playbook_input:domain", "!=", None] ], - name="filter_1:condition_2") + name="routing_artifacts:condition_2") # call connected blocks if filtered artifacts or results if matched_artifacts_2 or matched_results_2: @@ -54,7 +58,7 @@ def get_file_devices(action=None, success=None, container=None, results=None, ha # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) - filtered_input_0_file_hash = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_1:playbook_input:file_hash"]) + filtered_input_0_file_hash = phantom.collect2(container=container, datapath=["filtered-data:routing_artifacts:condition_1:playbook_input:file_hash"]) parameters = [] @@ -75,7 +79,7 @@ def get_file_devices(action=None, success=None, container=None, results=None, ha ## Custom Code End ################################################################################ - phantom.act("get file devices", parameters=parameters, name="get_file_devices", assets=["windows_defender_atp"], callback=filter_2) + phantom.act("get file devices", parameters=parameters, name="get_file_devices", assets=["windows_defender_atp"], callback=filter_file_response) return @@ -86,7 +90,7 @@ def get_domain_devices(action=None, success=None, container=None, results=None, # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) - filtered_input_0_domain = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_2:playbook_input:domain"]) + filtered_input_0_domain = phantom.collect2(container=container, datapath=["filtered-data:routing_artifacts:condition_2:playbook_input:domain"]) parameters = [] @@ -107,22 +111,22 @@ def get_domain_devices(action=None, success=None, container=None, results=None, ## Custom Code End ################################################################################ - phantom.act("get domain devices", parameters=parameters, name="get_domain_devices", assets=["windows_defender_atp"], callback=filter_3) + phantom.act("get domain devices", parameters=parameters, name="get_domain_devices", assets=["windows_defender_atp"], callback=filter_domain_response) return @phantom.playbook_block() -def filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("filter_2() called") +def filter_file_response(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_file_response() called") # collect filtered artifact ids and results for 'if' condition 1 matched_artifacts_1, matched_results_1 = phantom.condition( container=container, conditions=[ - ["get_file_devices:action_result.summary.total_devices", ">", 0] + ["get_file_devices:action_result.summary.{summaryVar}", ">", 0] ], - name="filter_2:condition_1") + name="filter_file_response:condition_1") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: @@ -132,16 +136,16 @@ def filter_2(action=None, success=None, container=None, results=None, handle=Non @phantom.playbook_block() -def filter_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("filter_3() called") +def filter_domain_response(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_domain_response() called") # collect filtered artifact ids and results for 'if' condition 1 matched_artifacts_1, matched_results_1 = phantom.condition( container=container, conditions=[ - ["get_domain_devices:action_result.summary.total_devices", ">", 0] + ["get_domain_devices:action_result.summary.{summaryVar}", ">", 0] ], - name="filter_3:condition_1") + name="filter_domain_response:condition_1") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: @@ -160,8 +164,8 @@ def format_report_file(action=None, success=None, container=None, results=None, parameters = [ "get_file_devices:action_result.parameter.file_hash", "get_file_devices:action_result.data.*.computerDnsName", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.lastIpAddress", - "filtered-data:filter_2:condition_1:get_file_devices:action_result.data.*.osPlatform", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.osPlatform", "get_file_devices:action_result.data.*.id" ] @@ -192,8 +196,8 @@ def format_report_domain(action=None, success=None, container=None, results=None parameters = [ "get_domain_devices:action_result.parameter.domain", "get_domain_devices:action_result.data.*.computerDnsName", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", - "filtered-data:filter_3:condition_1:get_domain_devices:action_result.data.*.osPlatform", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.osPlatform", "get_domain_devices:action_result.data.*.id" ] @@ -224,11 +228,11 @@ def build_file_output(action=None, success=None, container=None, results=None, h # the context for that list ################################################################################ - filtered_result_0_data_filter_2 = phantom.collect2(container=container, datapath=["filtered-data:filter_2:condition_1:get_file_devices:action_result.parameter.file_hash","filtered-data:filter_2:condition_1:get_file_devices:action_result.data","filtered-data:filter_2:condition_1:get_file_devices:action_result.summary.total_devices"]) + filtered_result_0_data_filter_file_response = phantom.collect2(container=container, datapath=["filtered-data:filter_file_response:condition_1:get_file_devices:action_result.parameter.file_hash","filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data","filtered-data:filter_file_response:condition_1:get_file_devices:action_result.summary.total_devices"]) - filtered_result_0_parameter_file_hash = [item[0] for item in filtered_result_0_data_filter_2] - filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_2] - filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_2] + filtered_result_0_parameter_file_hash = [item[0] for item in filtered_result_0_data_filter_file_response] + filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_file_response] + filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_file_response] build_file_output__observable_array = None @@ -284,11 +288,11 @@ def build_domain_output(action=None, success=None, container=None, results=None, # the context for that list ################################################################################ - filtered_result_0_data_filter_3 = phantom.collect2(container=container, datapath=["filtered-data:filter_3:condition_1:get_domain_devices:action_result.parameter.domain","filtered-data:filter_3:condition_1:get_domain_devices:action_result.data","filtered-data:filter_3:condition_1:get_domain_devices:action_result.summary.total_devices"]) + filtered_result_0_data_filter_domain_response = phantom.collect2(container=container, datapath=["filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.parameter.domain","filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data","filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.summary.total_devices"]) - filtered_result_0_parameter_domain = [item[0] for item in filtered_result_0_data_filter_3] - filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_3] - filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_3] + filtered_result_0_parameter_domain = [item[0] for item in filtered_result_0_data_filter_domain_response] + filtered_result_0_data = [item[1] for item in filtered_result_0_data_filter_domain_response] + filtered_result_0_summary_total_devices = [item[2] for item in filtered_result_0_data_filter_domain_response] build_domain_output__observable_array = None From d220cf41a5b47d328cd49a5d06ab25e302c75723 Mon Sep 17 00:00:00 2001 From: Lou Stella Date: Thu, 4 May 2023 14:17:57 -0500 Subject: [PATCH 5/5] Addressed Kelby's Findings --- ...nder_ATP_Identifier_Activity_Analysis.json | 29 ++++++++++--------- ...fender_ATP_Identifier_Activity_Analysis.py | 12 ++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json index dd20267b86..d65ce167f7 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.json @@ -104,7 +104,7 @@ "targetPort": "1_in" } ], - "hash": "b09360d8f57025be3b7987bb0e945bdc0c881598", + "hash": "3f512c247b205931a7a6421cc52b3085a65e5430", "nodes": { "0": { "data": { @@ -120,7 +120,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": -6.394884621840902e-14 + "y": -1.2789769243681803e-13 }, "1": { "data": { @@ -377,11 +377,11 @@ "functionName": "format_report_file", "id": "7", "parameters": [ - "get_file_devices:action_result.parameter.file_hash", - "get_file_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.parameter.file_hash", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.computerDnsName", "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.lastIpAddress", "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.osPlatform", - "get_file_devices:action_result.data.*.id" + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.id" ], "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| File | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%\n", "type": "format" @@ -405,11 +405,11 @@ "functionName": "format_report_domain", "id": "8", "parameters": [ - "get_domain_devices:action_result.parameter.domain", - "get_domain_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.parameter.domain", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.computerDnsName", "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.osPlatform", - "get_domain_devices:action_result.data.*.id" + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.id" ], "template": "SOAR searched for occurrences of `{0}` within your environment using Windows Defender ATP. The table below shows a summary of the information gathered.\n\n| Domain | Computer | Last IP Address | OS | Defender ATP ID | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | Defender ATP |\n%%", "type": "format" @@ -459,14 +459,14 @@ "contains": [ "sha1" ], - "description": "", + "description": "A SHA1 file hash to search for in your Windows Defender ATP protected environment.", "name": "file_hash" }, { "contains": [ "domain" ], - "description": "", + "description": "A domain name to search for in your Windows Defender ATP protected environment.", "name": "domain" } ], @@ -478,7 +478,7 @@ "build_domain_output:custom_function:observable_array" ], "deduplicate": false, - "description": "", + "description": "An array of observable dictionaries ", "metadata": {}, "name": "observable" }, @@ -489,7 +489,7 @@ "format_report_domain:formatted_data" ], "deduplicate": false, - "description": "", + "description": "An array of markdown reports", "metadata": {}, "name": "markdown_report" } @@ -499,7 +499,7 @@ "schema": "5.0.9", "version": "6.0.0.114895" }, - "create_time": "2023-04-14T14:48:13.695855+00:00", + "create_time": "2023-05-04T19:16:35.185480+00:00", "draft_mode": false, "labels": [ "*" @@ -508,6 +508,7 @@ "identifier_activity", "file_hash", "domain", - "windows_defender_atp" + "windows_defender_atp", + "D3-IAA" ] } \ No newline at end of file diff --git a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py index 810a09b859..2dfcf90af7 100644 --- a/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py +++ b/playbooks/Windows_Defender_ATP_Identifier_Activity_Analysis.py @@ -162,11 +162,11 @@ def format_report_file(action=None, success=None, container=None, results=None, # parameter list for template variable replacement parameters = [ - "get_file_devices:action_result.parameter.file_hash", - "get_file_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.parameter.file_hash", + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.computerDnsName", "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.lastIpAddress", "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.osPlatform", - "get_file_devices:action_result.data.*.id" + "filtered-data:filter_file_response:condition_1:get_file_devices:action_result.data.*.id" ] ################################################################################ @@ -194,11 +194,11 @@ def format_report_domain(action=None, success=None, container=None, results=None # parameter list for template variable replacement parameters = [ - "get_domain_devices:action_result.parameter.domain", - "get_domain_devices:action_result.data.*.computerDnsName", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.parameter.domain", + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.computerDnsName", "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.lastIpAddress", "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.osPlatform", - "get_domain_devices:action_result.data.*.id" + "filtered-data:filter_domain_response:condition_1:get_domain_devices:action_result.data.*.id" ] ################################################################################