mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
598 lines
33 KiB
JSON
598 lines
33 KiB
JSON
{
|
|
"blockly": false,
|
|
"blockly_xml": "<xml></xml>",
|
|
"category": "Threat Response",
|
|
"coa": {
|
|
"data": {
|
|
"description": "Published in response to CVE-2021-44228, this playbook is meant to be launched by log4j_investigate. In this playbook, the risk from an exploited host can be mitigated by optionally deleting malicious files from the hosts, blocking outbound network connections from the hosts, and/or shutting down the hosts.",
|
|
"edges": [
|
|
{
|
|
"id": "port_0_to_port_2",
|
|
"sourceNode": "0",
|
|
"sourcePort": "0_out",
|
|
"targetNode": "2",
|
|
"targetPort": "2_in"
|
|
},
|
|
{
|
|
"id": "port_2_to_port_3",
|
|
"sourceNode": "2",
|
|
"sourcePort": "2_out",
|
|
"targetNode": "3",
|
|
"targetPort": "3_in"
|
|
},
|
|
{
|
|
"id": "port_3_to_port_7",
|
|
"sourceNode": "3",
|
|
"sourcePort": "3_out",
|
|
"targetNode": "7",
|
|
"targetPort": "7_in"
|
|
},
|
|
{
|
|
"conditions": [
|
|
{
|
|
"index": 0
|
|
}
|
|
],
|
|
"id": "port_7_to_port_8",
|
|
"sourceNode": "7",
|
|
"sourcePort": "7_out",
|
|
"targetNode": "8",
|
|
"targetPort": "8_in"
|
|
},
|
|
{
|
|
"conditions": [
|
|
{
|
|
"index": 1
|
|
}
|
|
],
|
|
"id": "port_7_to_port_9",
|
|
"sourceNode": "7",
|
|
"sourcePort": "7_out",
|
|
"targetNode": "9",
|
|
"targetPort": "9_in"
|
|
},
|
|
{
|
|
"id": "port_8_to_port_1",
|
|
"sourceNode": "8",
|
|
"sourcePort": "8_out",
|
|
"targetNode": "1",
|
|
"targetPort": "1_in"
|
|
},
|
|
{
|
|
"id": "port_9_to_port_1",
|
|
"sourceNode": "9",
|
|
"sourcePort": "9_out",
|
|
"targetNode": "1",
|
|
"targetPort": "1_in"
|
|
}
|
|
],
|
|
"hash": "9a3b34f19ae7ca8907f49ee4c143f0e0e9d04caf",
|
|
"nodes": {
|
|
"0": {
|
|
"data": {
|
|
"advanced": {
|
|
"join": []
|
|
},
|
|
"functionName": "on_start",
|
|
"id": "0",
|
|
"type": "start"
|
|
},
|
|
"errors": {},
|
|
"id": "0",
|
|
"type": "start",
|
|
"x": 200,
|
|
"y": 40
|
|
},
|
|
"1": {
|
|
"data": {
|
|
"advanced": {
|
|
"join": []
|
|
},
|
|
"functionId": 1,
|
|
"functionName": "on_finish",
|
|
"id": "1",
|
|
"type": "end"
|
|
},
|
|
"errors": {},
|
|
"id": "1",
|
|
"type": "end",
|
|
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
|
|
"x": 200,
|
|
"y": 640
|
|
},
|
|
"2": {
|
|
"data": {
|
|
"advanced": {
|
|
"customName": "enumerate files to delete",
|
|
"customNameId": 0,
|
|
"join": []
|
|
},
|
|
"customFunction": {
|
|
"draftMode": false,
|
|
"name": "passthrough",
|
|
"repoName": "community"
|
|
},
|
|
"functionId": 1,
|
|
"functionName": "enumerate_files_to_delete",
|
|
"id": "2",
|
|
"selectMore": false,
|
|
"type": "utility",
|
|
"utilities": {
|
|
"passthrough": {
|
|
"description": "Return the inputs as outputs. This is useful for publishing pieces of data for other blocks in the playbook to use.",
|
|
"fields": [
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_1",
|
|
"name": "input_1",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_2",
|
|
"name": "input_2",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_3",
|
|
"name": "input_3",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_4",
|
|
"name": "input_4",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_5",
|
|
"name": "input_5",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_6",
|
|
"name": "input_6",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_7",
|
|
"name": "input_7",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_8",
|
|
"name": "input_8",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_9",
|
|
"name": "input_9",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "",
|
|
"inputType": "list",
|
|
"label": "input_10",
|
|
"name": "input_10",
|
|
"placeholder": "",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
}
|
|
],
|
|
"label": "passthrough",
|
|
"name": "passthrough"
|
|
}
|
|
},
|
|
"utilityType": "custom_function",
|
|
"values": {
|
|
"passthrough": {
|
|
"input_1": "log4j_hosts_and_files",
|
|
"input_10": null,
|
|
"input_2": null,
|
|
"input_3": null,
|
|
"input_4": null,
|
|
"input_5": null,
|
|
"input_6": null,
|
|
"input_7": null,
|
|
"input_8": null,
|
|
"input_9": null
|
|
}
|
|
}
|
|
},
|
|
"errors": {},
|
|
"id": "2",
|
|
"type": "utility",
|
|
"userCode": "\n # use custom code to read a custom list of potential log4j files to delete\n # and make a json to create an artifact for each one.\n # the expected format of the custom list is:\n # hostname1 | unix | /full/path/to/delete/on/hostname_1\n # 1.1.1.1 | windows | C:\\\\Full\\Path\\To\\Delete\\On\\1_1_1_1\n #\n # the list can either have all rows with files or no rows with files. some rows with files and some without will not work\n\n custom_list_name = parameters[0]['input_1']\n \n success, message, rows = phantom.get_list(list_name=custom_list_name)\n \n # return early if the list is not found\n if not success:\n phantom.debug(\"Failed to find the custom list, so only existing artifacts will be used\")\n phantom.custom_function(custom_function=\"community/passthrough\", parameters=[], name=\"enumerate_files_to_delete\", callback=create_file_artifacts)\n return\n \n # loop through the rows and create a list of artifact jsons to add\n # the three columns are expected to be the ip_or_hostname, the operating system family, and the full path to the file to delete\n parameters = []\n unix_hosts = []\n windows_hosts = []\n unknown_hosts = []\n has_files = False\n if rows[0][2] and ('/' in rows[0][2] or '\\\\' in rows[0][2]):\n has_files = True\n for row in rows:\n # hostname and operating system are required, but file path is optional. files will not be deleted if file path is missing\n if row[0] and row[1]:\n # only windows and unix are supported, and operating system family is required\n if row[1] == 'unix' or row[1] == 'windows':\n artifact_dict = {\n 'cef_data': {\n 'deviceHostname': row[0],\n 'operatingSystemFamily': row[1],\n 'filePath': row[2]},\n 'field_mapping': {\n 'deviceHostname': ['host name', 'ip'],\n 'filePath': ['file path']}}\n # full paths should have at least one slash somewhere in them\n if row[2] and ('/' in row[2] or '\\\\' in row[2]):\n if has_files:\n artifact_dict['cef_data']['filePath'] = row[2]\n artifact_dict['field_mapping']['filePath'] = ['file path']\n else:\n phantom.debug(\"skipping host {} with file {} because other rows did not have files\".format(row[0], row[2]))\n else:\n if has_files:\n phantom.error(\"host {} is missing a file; playbook will be discontinued\".format(row[0]))\n phantom.discontinue()\n parameters.append({'input_1': artifact_dict})\n\n",
|
|
"x": 180,
|
|
"y": 160
|
|
},
|
|
"3": {
|
|
"data": {
|
|
"advanced": {
|
|
"customName": "create file artifacts",
|
|
"customNameId": 0,
|
|
"join": []
|
|
},
|
|
"customFunction": {
|
|
"draftMode": false,
|
|
"name": "artifact_create",
|
|
"repoName": "community"
|
|
},
|
|
"functionId": 2,
|
|
"functionName": "create_file_artifacts",
|
|
"id": "3",
|
|
"selectMore": false,
|
|
"tab": "customFunctions",
|
|
"type": "utility",
|
|
"utilities": {
|
|
"artifact_create": {
|
|
"description": "Create a new artifact with the specified attributes.",
|
|
"fields": [
|
|
{
|
|
"dataTypes": [
|
|
"phantom container id"
|
|
],
|
|
"description": "Container which the artifact will be added to.",
|
|
"inputType": "item",
|
|
"label": "container",
|
|
"name": "container",
|
|
"placeholder": "container:id",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "The name of the new artifact, which is optional and defaults to \"artifact\".",
|
|
"inputType": "item",
|
|
"label": "name",
|
|
"name": "name",
|
|
"placeholder": "artifact",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "The label of the new artifact, which is optional and defaults to \"events\"",
|
|
"inputType": "item",
|
|
"label": "label",
|
|
"name": "label",
|
|
"placeholder": "events",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
""
|
|
],
|
|
"description": "The severity of the new artifact, which is optional and defaults to \"Medium\". Typically this is either \"High\", \"Medium\", or \"Low\".",
|
|
"inputType": "item",
|
|
"label": "severity",
|
|
"name": "severity",
|
|
"placeholder": "Medium",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "The name of the CEF field to populate in the artifact, such as \"destinationAddress\" or \"sourceDnsDomain\". Required only if cef_value is provided.",
|
|
"inputType": "item",
|
|
"label": "cef_field",
|
|
"name": "cef_field",
|
|
"placeholder": "destinationAddress",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [
|
|
"*"
|
|
],
|
|
"description": "The value of the CEF field to populate in the artifact, such as the IP address, domain name, or file hash. Required only if cef_field is provided.",
|
|
"inputType": "item",
|
|
"label": "cef_value",
|
|
"name": "cef_value",
|
|
"placeholder": "192.0.2.192",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "The CEF data type of the data in cef_value. For example, this could be \"ip\", \"hash\", or \"domain\". Optional.",
|
|
"inputType": "item",
|
|
"label": "cef_data_type",
|
|
"name": "cef_data_type",
|
|
"placeholder": "ip",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "A comma-separated list of tags to apply to the created artifact, which is optional.",
|
|
"inputType": "item",
|
|
"label": "tags",
|
|
"name": "tags",
|
|
"placeholder": "tag1, tag2, tag3",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "Either \"true\" or \"false\", depending on whether or not the new artifact should trigger the execution of any playbooks that are set to active on the label of the container the artifact will be added to. Optional and defaults to \"false\".",
|
|
"inputType": "item",
|
|
"label": "run_automation",
|
|
"name": "run_automation",
|
|
"placeholder": "false",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
},
|
|
{
|
|
"dataTypes": [],
|
|
"description": "Optional parameter to modify any extra attributes of the artifact. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.",
|
|
"inputType": "item",
|
|
"label": "input_json",
|
|
"name": "input_json",
|
|
"placeholder": "{\"source_data_identifier\": \"1234\", \"data\": \"5678\"}",
|
|
"renderType": "datapath",
|
|
"required": false
|
|
}
|
|
],
|
|
"label": "artifact_create",
|
|
"name": "artifact_create"
|
|
}
|
|
},
|
|
"utilityType": "custom_function",
|
|
"values": {
|
|
"artifact_create": {
|
|
"cef_data_type": null,
|
|
"cef_field": null,
|
|
"cef_value": null,
|
|
"container": "container:id",
|
|
"input_json": "enumerate_files_to_delete:custom_function_result.data.*.item",
|
|
"label": null,
|
|
"name": "potential log4j file",
|
|
"run_automation": null,
|
|
"severity": "high",
|
|
"tags": null
|
|
}
|
|
}
|
|
},
|
|
"errors": {},
|
|
"id": "3",
|
|
"type": "utility",
|
|
"x": 180,
|
|
"y": 280
|
|
},
|
|
"7": {
|
|
"data": {
|
|
"advanced": {
|
|
"customName": "if hosts exist",
|
|
"customNameId": 0,
|
|
"join": [],
|
|
"scope": "all"
|
|
},
|
|
"conditions": [
|
|
{
|
|
"comparisons": [
|
|
{
|
|
"conditionIndex": 0,
|
|
"op": "!=",
|
|
"param": "artifact:*.cef.deviceHostname",
|
|
"value": ""
|
|
},
|
|
{
|
|
"conditionIndex": 0,
|
|
"op": "==",
|
|
"param": "artifact:*.cef.operatingSystemFamily",
|
|
"value": "unix"
|
|
},
|
|
{
|
|
"conditionIndex": 0,
|
|
"op": "==",
|
|
"param": "artifact:*.name",
|
|
"value": "potential log4j file"
|
|
}
|
|
],
|
|
"conditionIndex": 0,
|
|
"customName": "unix",
|
|
"logic": "and"
|
|
},
|
|
{
|
|
"comparisons": [
|
|
{
|
|
"conditionIndex": 1,
|
|
"op": "!=",
|
|
"param": "artifact:*.cef.deviceHostname",
|
|
"value": ""
|
|
},
|
|
{
|
|
"conditionIndex": 1,
|
|
"op": "==",
|
|
"param": "artifact:*.cef.operatingSystemFamily",
|
|
"value": "windows"
|
|
},
|
|
{
|
|
"conditionIndex": 1,
|
|
"op": "==",
|
|
"param": "artifact:*.name",
|
|
"value": "potential log4j file"
|
|
}
|
|
],
|
|
"conditionIndex": 1,
|
|
"customName": "windows",
|
|
"logic": "and"
|
|
}
|
|
],
|
|
"customDatapaths": {
|
|
"artifacts": {
|
|
"artifact:*.cef.operatingSystemFamily": {
|
|
"contains": [],
|
|
"isCustomDatapath": true,
|
|
"label": "artifact:*.cef.operatingSystemFamily",
|
|
"value": "artifact:*.cef.operatingSystemFamily"
|
|
}
|
|
}
|
|
},
|
|
"functionId": 1,
|
|
"functionName": "if_hosts_exist",
|
|
"id": "7",
|
|
"type": "filter"
|
|
},
|
|
"errors": {},
|
|
"id": "7",
|
|
"type": "filter",
|
|
"x": 240,
|
|
"y": 380
|
|
},
|
|
"8": {
|
|
"data": {
|
|
"advanced": {
|
|
"join": [],
|
|
"scope": "all"
|
|
},
|
|
"functionId": 2,
|
|
"functionName": "playbook_internal_host_ssh_log4j_respond_2",
|
|
"id": "8",
|
|
"inputs": {
|
|
"filePath": {
|
|
"datapaths": [
|
|
"filtered-data:if_hosts_exist:condition_1:artifact:*.cef.filePath"
|
|
],
|
|
"deduplicate": false
|
|
},
|
|
"ip_or_hostname": {
|
|
"datapaths": [
|
|
"filtered-data:if_hosts_exist:condition_1:artifact:*.cef.deviceHostname"
|
|
],
|
|
"deduplicate": false
|
|
}
|
|
},
|
|
"playbookName": "internal_host_ssh_log4j_respond",
|
|
"playbookRepo": 1,
|
|
"playbookRepoName": "community",
|
|
"playbookType": "data",
|
|
"synchronous": false,
|
|
"type": "playbook"
|
|
},
|
|
"errors": {},
|
|
"id": "8",
|
|
"type": "playbook",
|
|
"x": 40,
|
|
"y": 520
|
|
},
|
|
"9": {
|
|
"data": {
|
|
"advanced": {
|
|
"join": []
|
|
},
|
|
"functionId": 2,
|
|
"functionName": "playbook_internal_host_winrm_log4j_respond_2",
|
|
"id": "9",
|
|
"inputs": {
|
|
"filePath": {
|
|
"datapaths": [
|
|
"filtered-data:if_hosts_exist:condition_2:artifact:*.cef.filePath"
|
|
],
|
|
"deduplicate": false
|
|
},
|
|
"ip_or_hostname": {
|
|
"datapaths": [
|
|
"filtered-data:if_hosts_exist:condition_2:artifact:*.cef.deviceHostname"
|
|
],
|
|
"deduplicate": false
|
|
}
|
|
},
|
|
"playbookName": "internal_host_winrm_log4j_respond",
|
|
"playbookRepo": 1,
|
|
"playbookRepoName": "community",
|
|
"playbookType": "data",
|
|
"synchronous": false,
|
|
"type": "playbook"
|
|
},
|
|
"errors": {},
|
|
"id": "9",
|
|
"type": "playbook",
|
|
"x": 320,
|
|
"y": 520
|
|
}
|
|
},
|
|
"notes": "* To use this playbook, create a custom list called \"log4j_hosts_and_files\" with a format like:\n\n hostname1 | unix | /full/path/to/delete/on/hostname_1\n 1.1.1.1 | windows | C:\\\\Full\\Path\\To\\Delete\\On\\1_1_1_1\n\n* In other words, the first column should be an IP or hostname of a potentially affected log4j host, the second should be the operating system family (either unix or windows), and the third should be a full path to a file to delete if there are any. The first two are mandatory and the file is optional.\n\n* In the block called \"enumerate_files_to_delete\", change the custom list name from \"log4j_hosts_and_files\" if needed \n* If ssh and/or winrm are not the preferred endpoint management methods, these playbooks could be ported to use Google's GRR, osquery, CrowdStrike's RTR, Carbon Black's EDR API, or similar tools.\n* The artifact scope \"all\" is used throughout this playbook because the artifact list can be added to as the playbook progresses."
|
|
},
|
|
"input_spec": null,
|
|
"output_spec": null,
|
|
"playbook_type": "automation",
|
|
"python_version": "3.13",
|
|
"schema": "5.0.4",
|
|
"version": "5.1.0.70187"
|
|
},
|
|
"create_time": "2021-12-15T22:02:08.116265+00:00",
|
|
"draft_mode": false,
|
|
"labels": [
|
|
"events"
|
|
],
|
|
"tags": [
|
|
"log4j",
|
|
"respond"
|
|
]
|
|
} |