mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Merge pull request #2595 from splunk/TR-2903
Windows Defender ATP Identifier Activity Analysis
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
{
|
||||
"blockly": false,
|
||||
"blockly_xml": "<xml></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": "3f512c247b205931a7a6421cc52b3085a65e5430",
|
||||
"nodes": {
|
||||
"0": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"join": []
|
||||
},
|
||||
"functionName": "on_start",
|
||||
"id": "0",
|
||||
"type": "start"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "0",
|
||||
"type": "start",
|
||||
"warnings": {},
|
||||
"x": 190,
|
||||
"y": -1.2789769243681803e-13
|
||||
},
|
||||
"1": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"join": []
|
||||
},
|
||||
"functionName": "on_finish",
|
||||
"id": "1",
|
||||
"type": "end"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "1",
|
||||
"type": "end",
|
||||
"warnings": {},
|
||||
"x": 190,
|
||||
"y": 1042
|
||||
},
|
||||
"10": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "build domain output",
|
||||
"customNameId": 0,
|
||||
"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",
|
||||
"id": "10",
|
||||
"inputParameters": [
|
||||
"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"
|
||||
],
|
||||
"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 \"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": 864
|
||||
},
|
||||
"2": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "routing_artifacts",
|
||||
"customNameId": 0,
|
||||
"description": "Route SHA1 file hashes and domains respectively",
|
||||
"join": [],
|
||||
"note": "Route SHA1 file hashes and domains respectively"
|
||||
},
|
||||
"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": "routing_artifacts",
|
||||
"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": [],
|
||||
"note": "\"get file devices\" action which returns a list of devices that have seen the file queried for"
|
||||
},
|
||||
"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:routing_artifacts:condition_1:playbook_input:file_hash"
|
||||
},
|
||||
"requiredParameters": [
|
||||
{
|
||||
"data_type": "string",
|
||||
"field": "file_hash"
|
||||
}
|
||||
],
|
||||
"type": "action"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "3",
|
||||
"type": "action",
|
||||
"warnings": {},
|
||||
"x": 0,
|
||||
"y": 320
|
||||
},
|
||||
"4": {
|
||||
"data": {
|
||||
"action": "get domain devices",
|
||||
"actionType": "investigate",
|
||||
"advanced": {
|
||||
"customName": "get domain devices",
|
||||
"customNameId": 0,
|
||||
"join": [],
|
||||
"note": "\"get domain devices\" action which returns a list of devices that have seen the domain queried for"
|
||||
},
|
||||
"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:routing_artifacts:condition_2:playbook_input:domain"
|
||||
},
|
||||
"requiredParameters": [
|
||||
{
|
||||
"data_type": "string",
|
||||
"field": "domain"
|
||||
}
|
||||
],
|
||||
"type": "action"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "4",
|
||||
"type": "action",
|
||||
"warnings": {},
|
||||
"x": 340,
|
||||
"y": 320
|
||||
},
|
||||
"5": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "filter_file_response",
|
||||
"customNameId": 0,
|
||||
"join": [],
|
||||
"note": "Esnure there are results for get_file_devices"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"comparisons": [
|
||||
{
|
||||
"conditionIndex": 0,
|
||||
"op": ">",
|
||||
"param": "get_file_devices:action_result.summary.{summaryVar}",
|
||||
"value": "0"
|
||||
}
|
||||
],
|
||||
"conditionIndex": 0,
|
||||
"customName": "devices found",
|
||||
"logic": "and"
|
||||
}
|
||||
],
|
||||
"functionId": 2,
|
||||
"functionName": "filter_file_response",
|
||||
"id": "5",
|
||||
"type": "filter"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "5",
|
||||
"type": "filter",
|
||||
"warnings": {},
|
||||
"x": 60,
|
||||
"y": 506
|
||||
},
|
||||
"6": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "filter_domain_response",
|
||||
"customNameId": 0,
|
||||
"join": [],
|
||||
"note": "Esnure there are results for get_domain_devices"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"comparisons": [
|
||||
{
|
||||
"conditionIndex": 0,
|
||||
"op": ">",
|
||||
"param": "get_domain_devices:action_result.summary.{summaryVar}",
|
||||
"value": "0"
|
||||
}
|
||||
],
|
||||
"conditionIndex": 0,
|
||||
"customName": "devices found",
|
||||
"logic": "and"
|
||||
}
|
||||
],
|
||||
"functionId": 3,
|
||||
"functionName": "filter_domain_response",
|
||||
"id": "6",
|
||||
"type": "filter"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "6",
|
||||
"type": "filter",
|
||||
"warnings": {},
|
||||
"x": 400,
|
||||
"y": 506
|
||||
},
|
||||
"7": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "format report file",
|
||||
"customNameId": 0,
|
||||
"join": [],
|
||||
"note": "Markdown Report creation"
|
||||
},
|
||||
"functionId": 1,
|
||||
"functionName": "format_report_file",
|
||||
"id": "7",
|
||||
"parameters": [
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "7",
|
||||
"type": "format",
|
||||
"warnings": {},
|
||||
"x": 0,
|
||||
"y": 686
|
||||
},
|
||||
"8": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "format report domain",
|
||||
"customNameId": 0,
|
||||
"join": [],
|
||||
"note": "Markdown Report creation"
|
||||
},
|
||||
"functionId": 2,
|
||||
"functionName": "format_report_domain",
|
||||
"id": "8",
|
||||
"parameters": [
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"errors": {},
|
||||
"id": "8",
|
||||
"type": "format",
|
||||
"warnings": {},
|
||||
"x": 340,
|
||||
"y": 686
|
||||
},
|
||||
"9": {
|
||||
"data": {
|
||||
"advanced": {
|
||||
"customName": "build file output",
|
||||
"customNameId": 0,
|
||||
"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",
|
||||
"id": "9",
|
||||
"inputParameters": [
|
||||
"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"
|
||||
],
|
||||
"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 \"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": 864
|
||||
}
|
||||
},
|
||||
"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": "A SHA1 file hash to search for in your Windows Defender ATP protected environment.",
|
||||
"name": "file_hash"
|
||||
},
|
||||
{
|
||||
"contains": [
|
||||
"domain"
|
||||
],
|
||||
"description": "A domain name to search for in your Windows Defender ATP protected environment.",
|
||||
"name": "domain"
|
||||
}
|
||||
],
|
||||
"output_spec": [
|
||||
{
|
||||
"contains": [],
|
||||
"datapaths": [
|
||||
"build_file_output:custom_function:observable_array",
|
||||
"build_domain_output:custom_function:observable_array"
|
||||
],
|
||||
"deduplicate": false,
|
||||
"description": "An array of observable dictionaries ",
|
||||
"metadata": {},
|
||||
"name": "observable"
|
||||
},
|
||||
{
|
||||
"contains": [],
|
||||
"datapaths": [
|
||||
"format_report_file:formatted_data",
|
||||
"format_report_domain:formatted_data"
|
||||
],
|
||||
"deduplicate": false,
|
||||
"description": "An array of markdown reports",
|
||||
"metadata": {},
|
||||
"name": "markdown_report"
|
||||
}
|
||||
],
|
||||
"playbook_type": "data",
|
||||
"python_version": "3",
|
||||
"schema": "5.0.9",
|
||||
"version": "6.0.0.114895"
|
||||
},
|
||||
"create_time": "2023-05-04T19:16:35.185480+00:00",
|
||||
"draft_mode": false,
|
||||
"labels": [
|
||||
"*"
|
||||
],
|
||||
"tags": [
|
||||
"identifier_activity",
|
||||
"file_hash",
|
||||
"domain",
|
||||
"windows_defender_atp",
|
||||
"D3-IAA"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,370 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
|
||||
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 'routing_artifacts' block
|
||||
routing_artifacts(container=container)
|
||||
|
||||
return
|
||||
|
||||
@phantom.playbook_block()
|
||||
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(
|
||||
container=container,
|
||||
conditions=[
|
||||
["playbook_input:file_hash", "!=", None]
|
||||
],
|
||||
name="routing_artifacts:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
get_file_devices(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:domain", "!=", None]
|
||||
],
|
||||
name="routing_artifacts:condition_2")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_2 or matched_results_2:
|
||||
get_domain_devices(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 get_file_devices(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug("get_file_devices() called")
|
||||
|
||||
# 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:routing_artifacts:condition_1:playbook_input:file_hash"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'get_file_devices' call
|
||||
for filtered_input_0_file_hash_item in filtered_input_0_file_hash:
|
||||
if filtered_input_0_file_hash_item[0] is not None:
|
||||
parameters.append({
|
||||
"file_hash": filtered_input_0_file_hash_item[0],
|
||||
})
|
||||
|
||||
################################################################################
|
||||
## Custom Code Start
|
||||
################################################################################
|
||||
|
||||
# Write your custom code here...
|
||||
|
||||
################################################################################
|
||||
## Custom Code End
|
||||
################################################################################
|
||||
|
||||
phantom.act("get file devices", parameters=parameters, name="get_file_devices", assets=["windows_defender_atp"], callback=filter_file_response)
|
||||
|
||||
return
|
||||
|
||||
|
||||
@phantom.playbook_block()
|
||||
def get_domain_devices(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug("get_domain_devices() called")
|
||||
|
||||
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
filtered_input_0_domain = phantom.collect2(container=container, datapath=["filtered-data:routing_artifacts:condition_2:playbook_input:domain"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'get_domain_devices' call
|
||||
for filtered_input_0_domain_item in filtered_input_0_domain:
|
||||
if filtered_input_0_domain_item[0] is not None:
|
||||
parameters.append({
|
||||
"domain": filtered_input_0_domain_item[0],
|
||||
})
|
||||
|
||||
################################################################################
|
||||
## Custom Code Start
|
||||
################################################################################
|
||||
|
||||
# Write your custom code here...
|
||||
|
||||
################################################################################
|
||||
## Custom Code End
|
||||
################################################################################
|
||||
|
||||
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_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.{summaryVar}", ">", 0]
|
||||
],
|
||||
name="filter_file_response: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_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.{summaryVar}", ">", 0]
|
||||
],
|
||||
name="filter_domain_response: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 = [
|
||||
"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",
|
||||
"filtered-data:filter_file_response:condition_1: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 = [
|
||||
"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",
|
||||
"filtered-data:filter_domain_response:condition_1: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")
|
||||
|
||||
################################################################################
|
||||
# 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_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_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
|
||||
|
||||
################################################################################
|
||||
## 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 = {
|
||||
"value": indicator,
|
||||
"type": "file_hash",
|
||||
"total_count": count,
|
||||
"source": "Defender ATP",
|
||||
"identifier_activity": 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")
|
||||
|
||||
################################################################################
|
||||
# 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_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_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
|
||||
|
||||
################################################################################
|
||||
## 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 = {
|
||||
"value": indicator,
|
||||
"type": "domain",
|
||||
"total_count": count,
|
||||
"source": "Defender ATP",
|
||||
"identifier_activity": 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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user