Branch was auto-updated.

This commit is contained in:
srv-rr-gh-researchbt
2023-08-02 07:08:44 -07:00
committed by GitHub
8 changed files with 1541 additions and 0 deletions
@@ -0,0 +1,268 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "DNS Denylisting",
"coa": {
"data": {
"description": "Accepts a domain or list of domains as input. Blocks the given domains in Cisco Umbrella.\n\nhttps://d3fend.mitre.org/technique/d3f:DNSDenylisting/",
"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"
},
{
"id": "port_5_to_port_1",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_3_to_port_6",
"sourceNode": "3",
"sourcePort": "3_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_6_to_port_5",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "5",
"targetPort": "5_in"
}
],
"hash": "3ef6e0e09a728ad1f2aea6b5c89f41b9f5671f50",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"warnings": {},
"x": 1000,
"y": 419.99999999999955
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"warnings": {},
"x": 1000,
"y": 1200
},
"2": {
"data": {
"advanced": {
"customName": "domain input filter",
"customNameId": 0,
"description": "Determine branches based on provided inputs.",
"join": [],
"note": "Determine branches based on provided inputs."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "playbook_input:domain",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "input_url",
"logic": "and"
}
],
"functionId": 1,
"functionName": "domain_input_filter",
"id": "2",
"type": "filter"
},
"errors": {},
"id": "2",
"type": "filter",
"warnings": {},
"x": 1040,
"y": 540
},
"3": {
"data": {
"action": "block domain",
"actionType": "contain",
"advanced": {
"customName": "block domain",
"customNameId": 0,
"description": "Block domains in Cisco Umbrella based on given domains. ",
"join": [],
"note": "Block domains in Cisco Umbrella based on given domains. "
},
"connector": "Cisco Umbrella",
"connectorConfigs": [
"cisco_umbrella"
],
"connectorId": "96f3e021-5396-42d0-97f4-4fab683e9adb",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "block_domain",
"id": "3",
"parameters": {
"domain": "playbook_input:domain"
},
"requiredParameters": [
{
"data_type": "string",
"field": "domain"
}
],
"type": "action"
},
"errors": {},
"id": "3",
"type": "action",
"warnings": {},
"x": 980,
"y": 740
},
"5": {
"data": {
"advanced": {
"customName": "build observable",
"customNameId": 0,
"description": "This block uses custom code to generate an observable dictionary to output into the observables data path.",
"join": [],
"note": "This block uses custom code to generate an observable dictionary to output into the observables data path."
},
"functionId": 1,
"functionName": "build_observable",
"id": "5",
"inputParameters": [
"filtered-data:success_filter:condition_1:block_domain:action_result.parameter.domain",
"filtered-data:success_filter:condition_1:block_domain:action_result.status"
],
"outputVariables": [
"observable_array"
],
"type": "code"
},
"errors": {},
"id": "5",
"type": "code",
"userCode": "\n build_observable__observable_array = list()\n for status, domain in zip(filtered_result_0_status, filtered_result_0_parameter_domain):\n if status == \"success\":\n observable = {\n \"type\": \"domain\",\n \"value\": domain,\n \"source\": \"Cisco Umbrella\",\n \"status\": \"blocked\"\n }\n \n build_observable__observable_array.append(observable)\n\n",
"warnings": {},
"x": 980,
"y": 1060
},
"6": {
"data": {
"advanced": {
"customName": "success filter",
"customNameId": 0,
"description": "Determine if the block domain was successful.",
"join": [],
"note": "Determine if the block domain was successful."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "==",
"param": "block_domain:action_result.status",
"value": "success"
}
],
"conditionIndex": 0,
"customName": "success",
"logic": "and"
}
],
"functionId": 2,
"functionName": "success_filter",
"id": "6",
"type": "filter"
},
"errors": {},
"id": "6",
"type": "filter",
"warnings": {},
"x": 1040,
"y": 880
}
},
"notes": "Inputs: domain\nInteractions: Cisco Umbrella\nActions: block domain\nOutputs: observables"
},
"input_spec": [
{
"contains": [
"domain"
],
"description": "Accepts domain and block them",
"name": "domain"
}
],
"output_spec": [
{
"contains": [],
"datapaths": [
"build_observable:custom_function:observable_array"
],
"deduplicate": false,
"description": "An array of observable dictionaries with value, type and information about the blocked domains.",
"metadata": {},
"name": "observable"
}
],
"playbook_type": "data",
"python_version": "3",
"schema": "5.0.10",
"version": "6.1.0.131"
},
"create_time": "2023-08-02T11:29:36.835550+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"Cisco Umbrella",
"denylist",
"D3-DNSDL",
"domain"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+167
View File
@@ -0,0 +1,167 @@
"""
Accepts a domain or list of domains as input. Blocks the given domains in Cisco Umbrella.\n\nhttps://d3fend.mitre.org/technique/d3f:DNSDenylisting/
"""
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 'domain_input_filter' block
domain_input_filter(container=container)
return
@phantom.playbook_block()
def domain_input_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("domain_input_filter() called")
################################################################################
# Determine branches based on provided inputs.
################################################################################
# collect filtered artifact ids and results for 'if' condition 1
matched_artifacts_1, matched_results_1 = phantom.condition(
container=container,
conditions=[
["playbook_input:domain", "!=", None]
],
name="domain_input_filter:condition_1",
delimiter=None)
# call connected blocks if filtered artifacts or results
if matched_artifacts_1 or matched_results_1:
block_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 block_domain(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("block_domain() called")
# phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
################################################################################
# Block domains in Cisco Umbrella based on given domains.
################################################################################
playbook_input_domain = phantom.collect2(container=container, datapath=["playbook_input:domain"])
parameters = []
# build parameters list for 'block_domain' call
for playbook_input_domain_item in playbook_input_domain:
if playbook_input_domain_item[0] is not None:
parameters.append({
"domain": playbook_input_domain_item[0],
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.act("block domain", parameters=parameters, name="block_domain", assets=["cisco_umbrella"], callback=success_filter)
return
@phantom.playbook_block()
def build_observable(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("build_observable() called")
################################################################################
# This block uses custom code to generate an observable dictionary to output into
# the observables data path.
################################################################################
filtered_result_0_data_success_filter = phantom.collect2(container=container, datapath=["filtered-data:success_filter:condition_1:block_domain:action_result.parameter.domain","filtered-data:success_filter:condition_1:block_domain:action_result.status"])
filtered_result_0_parameter_domain = [item[0] for item in filtered_result_0_data_success_filter]
filtered_result_0_status = [item[1] for item in filtered_result_0_data_success_filter]
build_observable__observable_array = None
################################################################################
## Custom Code Start
################################################################################
build_observable__observable_array = list()
for status, domain in zip(filtered_result_0_status, filtered_result_0_parameter_domain):
if status == "success":
observable = {
"type": "domain",
"value": domain,
"source": "Cisco Umbrella",
"status": "blocked"
}
build_observable__observable_array.append(observable)
################################################################################
## Custom Code End
################################################################################
phantom.save_run_data(key="build_observable:observable_array", value=json.dumps(build_observable__observable_array))
return
@phantom.playbook_block()
def success_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("success_filter() called")
################################################################################
# Determine if the block domain was successful.
################################################################################
# collect filtered artifact ids and results for 'if' condition 1
matched_artifacts_1, matched_results_1 = phantom.condition(
container=container,
conditions=[
["block_domain:action_result.status", "==", "success"]
],
name="success_filter:condition_1",
delimiter=None)
# call connected blocks if filtered artifacts or results
if matched_artifacts_1 or matched_results_1:
build_observable(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
return
@phantom.playbook_block()
def on_finish(container, summary):
phantom.debug("on_finish() called")
build_observable__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_observable:observable_array")) != "" else "null") # pylint: disable=used-before-assignment
output = {
"observable": build_observable__observable_array,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.save_playbook_output_data(output=output)
return
@@ -0,0 +1,24 @@
name: Cisco Umbrella DNS Denylisting
id: 3705f371-f355-46d7-979a-3bc4c26e2208
version: 1
date: '2023-07-14'
author: Patrick Bareiss, Splunk
type: Response
description: Accepts a domain or list of domains and block them in Cisco Umbrella. Generates a list of observables with the blocked domains.
playbook: Cisco_Umbrella_DNS_Denylisting
how_to_implement: This input playbook requires the Cisco Umbrella connector to be configured.
It is designed to work in conjunction with the DNS Denylisting Dispatch playbook or other playbooks in the same style.
references: []
app_list:
- Cisco Umbrella
tags:
platform_tags:
- url
- D3-DNSDL
- Cisco Umbrella
- denylist
playbook_type: Input
vpe_type: Modern
playbook_fields: []
product:
- Splunk SOAR
+750
View File
@@ -0,0 +1,750 @@
{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "DNS Denylisting",
"coa": {
"data": {
"description": "Detects available indicators and routes them to dispatch DNS denylisting playbooks. These playbooks will block the given domains. The output of the analysis will update any artifacts, tasks, and indicator tags.\n\nhttps://d3fend.mitre.org/technique/d3f:DNSDenylisting/",
"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_5",
"sourceNode": "2",
"sourcePort": "2_out",
"targetNode": "5",
"targetPort": "5_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_3_to_port_6",
"sourceNode": "3",
"sourcePort": "3_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_6_to_port_7",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "7",
"targetPort": "7_in"
},
{
"id": "port_8_to_port_9",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "9",
"targetPort": "9_in"
},
{
"id": "port_9_to_port_10",
"sourceNode": "9",
"sourcePort": "9_out",
"targetNode": "10",
"targetPort": "10_in"
},
{
"id": "port_10_to_port_1",
"sourceNode": "10",
"sourcePort": "10_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_7_to_port_12",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "12",
"targetPort": "12_in"
},
{
"conditions": [
{
"index": 1
}
],
"id": "port_7_to_port_11",
"sourceNode": "7",
"sourcePort": "7_out",
"targetNode": "11",
"targetPort": "11_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_12_to_port_8",
"sourceNode": "12",
"sourcePort": "12_out",
"targetNode": "8",
"targetPort": "8_in"
}
],
"hash": "0c7323b8609eddecd1ded1e9217bafb54dfe2d84",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"warnings": {},
"x": 1000,
"y": 279.9999999999998
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"warnings": {},
"x": 1060,
"y": 1440
},
"10": {
"data": {
"advanced": {
"customName": "update isolation task",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "workbook_task_update",
"repoName": "community"
},
"functionId": 4,
"functionName": "update_isolation_task",
"id": "10",
"selectMore": false,
"type": "utility",
"utilities": {
"workbook_task_update": {
"description": "Update a workbook task by task name or the task where the currently running playbook appears. Requires a task_name, container_id, and a note_title, note_content, owner, or status.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "Name of a workbook task or keyword 'playbook' to update the task where the currently running playbook appears. (Required)",
"inputType": "item",
"label": "task_name",
"name": "task_name",
"placeholder": "my_task",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "Note title. (Optional)",
"inputType": "item",
"label": "note_title",
"name": "note_title",
"placeholder": "My Title",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "Note content. (Optional)",
"inputType": "item",
"label": "note_content",
"name": "note_content",
"placeholder": "My notes",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "Accepts 'incomplete', 'in_progress, or 'complete'. (Optional)",
"inputType": "item",
"label": "status",
"name": "status",
"placeholder": "in_progress",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "A user to assign as the task owner or keyword 'current\" to assign the task to the user that launched the playbook. (Optional)",
"inputType": "item",
"label": "owner",
"name": "owner",
"placeholder": "username",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"phantom container id"
],
"description": "The ID of a SOAR Container. (Required)",
"inputType": "item",
"label": "container",
"name": "container",
"placeholder": "container:id",
"renderType": "datapath",
"required": false
}
],
"label": "workbook_task_update",
"name": "workbook_task_update"
}
},
"utilityType": "custom_function",
"values": {
"workbook_task_update": {
"container": "container:id",
"note_content": "format_note:formatted_data",
"note_title": "DNS Denylisting Dispatch Report",
"owner": null,
"status": "complete",
"task_name": "playbook"
}
}
},
"errors": {},
"id": "10",
"type": "utility",
"warnings": {},
"x": 1040,
"y": 1340
},
"11": {
"data": {
"advanced": {
"customName": "comment no observables",
"customNameId": 0,
"description": "Add comment when no observables were generated.",
"join": [],
"note": "Add comment when no observables were generated."
},
"functionId": 5,
"functionName": "comment_no_observables",
"id": "11",
"selectMore": false,
"tab": "apis",
"type": "utility",
"utilities": {
"comment": {
"description": "",
"fields": [
{
"description": "",
"label": "comment",
"name": "comment",
"placeholder": "Enter a comment",
"renderType": "datapath",
"required": true
},
{
"hidden": true,
"name": "container",
"required": false
},
{
"hidden": true,
"name": "author",
"required": false
},
{
"hidden": true,
"name": "trace",
"required": false
}
],
"label": "add comment",
"name": "comment"
}
},
"utilityType": "api",
"values": {
"comment": {
"_internal": [
"container",
"author",
"trace"
],
"comment": "No observable data found from dispatched playbooks."
}
}
},
"errors": {},
"id": "11",
"type": "utility",
"warnings": {},
"x": 680,
"y": 960
},
"12": {
"data": {
"advanced": {
"customName": "output filter",
"customNameId": 0,
"description": "Determine if the observable is not None.",
"join": [],
"note": "Determine if the observable is not None."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "dispatch_dns_denylisting_playbooks:playbook_output:observable",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "output exists",
"logic": "and"
}
],
"functionId": 2,
"functionName": "output_filter",
"id": "12",
"type": "filter"
},
"errors": {},
"id": "12",
"type": "filter",
"warnings": {},
"x": 1100,
"y": 960
},
"2": {
"data": {
"advanced": {
"customName": "artifact_exists",
"customNameId": 0,
"description": "Checks if a artifact exists",
"join": [],
"note": "Checks if a artifact exists"
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "artifact:*.id",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "artifact exists",
"display": "If",
"logic": "and",
"type": "if"
},
{
"comparisons": [
{
"conditionIndex": 1,
"op": "==",
"param": "",
"value": ""
}
],
"conditionIndex": 1,
"customName": "artifact does not exist",
"display": "Else",
"logic": "and",
"type": "else"
}
],
"functionId": 1,
"functionName": "artifact_exists",
"id": "2",
"type": "decision"
},
"errors": {},
"id": "2",
"type": "decision",
"warnings": {},
"x": 1060,
"y": 400
},
"3": {
"data": {
"advanced": {
"customName": "filter_new_artifacts",
"customNameId": 0,
"description": "Only dispatch playbooks against new artifacts.",
"join": [],
"note": "Only dispatch playbooks against new artifacts."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "artifact:*.id",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "artifact exists",
"logic": "and"
}
],
"functionId": 1,
"functionName": "filter_new_artifacts",
"id": "3",
"type": "filter"
},
"errors": {},
"id": "3",
"type": "filter",
"warnings": {},
"x": 900,
"y": 540
},
"5": {
"data": {
"advanced": {
"customName": "comment no new artifacts",
"customNameId": 0,
"description": "Add comment when no new artifacts exists.",
"join": [],
"note": "Add comment when no new artifacts exists."
},
"functionId": 2,
"functionName": "comment_no_new_artifacts",
"id": "5",
"selectMore": false,
"tab": "apis",
"type": "utility",
"utilities": {
"comment": {
"description": "",
"fields": [
{
"description": "",
"label": "comment",
"name": "comment",
"placeholder": "Enter a comment",
"renderType": "datapath",
"required": true
},
{
"hidden": true,
"name": "container",
"required": false
},
{
"hidden": true,
"name": "author",
"required": false
},
{
"hidden": true,
"name": "trace",
"required": false
}
],
"label": "add comment",
"name": "comment"
}
},
"utilityType": "api",
"values": {
"comment": {
"_internal": [
"container",
"author",
"trace"
],
"comment": "No new artifacts found."
}
}
},
"errors": {},
"id": "5",
"type": "utility",
"warnings": {},
"x": 1180,
"y": 540
},
"6": {
"data": {
"advanced": {
"customName": "dispatch dns denylisting playbooks",
"customNameId": 0,
"join": []
},
"functionId": 1,
"functionName": "dispatch_dns_denylisting_playbooks",
"id": "6",
"inputs": {
"artifact_ids_include": {
"datapaths": [
"artifact:*.id"
],
"deduplicate": false
},
"indicator_tags_exclude": {
"datapaths": [],
"deduplicate": false
},
"indicator_tags_include": {
"datapaths": [],
"deduplicate": false
},
"playbook_repo": {
"datapaths": [],
"deduplicate": false
},
"playbook_tags": {
"datapaths": [
"denylist"
],
"deduplicate": false
}
},
"playbookName": "dispatch_input_playbooks",
"playbookRepo": 1,
"playbookRepoName": "community",
"playbookType": "data",
"synchronous": true,
"type": "playbook"
},
"errors": {},
"id": "6",
"type": "playbook",
"warnings": {},
"x": 840,
"y": 700
},
"7": {
"data": {
"advanced": {
"customName": "outputs decision",
"customNameId": 0,
"description": "Determine if outputs exist.",
"join": [],
"note": "Determine if outputs exist."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "dispatch_dns_denylisting_playbooks:playbook_output:observable",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "observable exists",
"display": "If",
"logic": "and",
"type": "if"
},
{
"comparisons": [
{
"conditionIndex": 1,
"op": "==",
"param": "",
"value": ""
}
],
"conditionIndex": 1,
"customName": "observable does not exist",
"display": "Else",
"logic": "and",
"type": "else"
}
],
"functionId": 2,
"functionName": "outputs_decision",
"id": "7",
"type": "decision"
},
"errors": {},
"id": "7",
"type": "decision",
"warnings": {},
"x": 920,
"y": 820
},
"8": {
"data": {
"advanced": {
"customName": "tag indicators",
"customNameId": 0,
"join": []
},
"customFunction": {
"draftMode": false,
"name": "indicator_tag",
"repoName": "community"
},
"functionId": 3,
"functionName": "tag_indicators",
"id": "8",
"selectMore": false,
"tab": "customFunctions",
"type": "utility",
"utilities": {
"indicator_tag": {
"description": "Tag an existing indicator record. Tags can be overwritten or appended.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "Specifies the indicator which the tag will be added to. Supports a string indicator value or an indicator id.",
"inputType": "item",
"label": "indicator",
"name": "indicator",
"placeholder": "my_indicator",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
"*"
],
"description": "Comma separated list of tags. Tags should only contain characters Aa-Zz, 0-9, '-', and '_'.",
"inputType": "item",
"label": "tags",
"name": "tags",
"placeholder": "tag1,tag2,...,tagk",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "Either True or False with default as False. If set to True, existing tags on the indicator record will be replaced by the provided input. If set to False, the new tags will be appended to the existing indicator tags.",
"inputType": "item",
"label": "overwrite",
"name": "overwrite",
"placeholder": "False",
"renderType": "datapath",
"required": false
}
],
"label": "indicator_tag",
"name": "indicator_tag"
}
},
"utilityType": "custom_function",
"values": {
"indicator_tag": {
"indicator": "filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.value",
"overwrite": null,
"tags": "blocked"
}
}
},
"errors": {},
"id": "8",
"type": "utility",
"warnings": {},
"x": 1040,
"y": 1120
},
"9": {
"data": {
"advanced": {
"customName": "format note",
"customNameId": 0,
"description": "Format a note that merges together normalized data. ",
"join": [],
"note": "Format a note that merges together normalized data. "
},
"functionId": 1,
"functionName": "format_note",
"id": "9",
"parameters": [
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.value",
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.status",
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.source"
],
"template": "Splunk SOAR blocked the following domains:\n\n| domain | status | source |\n| --- | --- | --- |\n%%\n| {0} | {1} | {2} |\n%%\n",
"type": "format"
},
"errors": {},
"id": "9",
"type": "format",
"warnings": {},
"x": 1040,
"y": 1220
}
},
"notes": "Outputs: \n- Concludes task\n- tags indicators"
},
"input_spec": null,
"output_spec": null,
"playbook_type": "automation",
"python_version": "3",
"schema": "5.0.10",
"version": "6.1.0.131"
},
"create_time": "2023-08-02T12:03:29.640344+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"D3-DNSDLL"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+312
View File
@@ -0,0 +1,312 @@
"""
Detects available indicators and routes them to dispatch DNS denylisting playbooks. These playbooks will block the given domains. The output of the analysis will update any artifacts, tasks, and indicator tags.\n\nhttps://d3fend.mitre.org/technique/d3f:DNSDenylisting/
"""
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 'artifact_exists' block
artifact_exists(container=container)
return
@phantom.playbook_block()
def artifact_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("artifact_exists() called")
################################################################################
# Checks if a artifact exists
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["artifact:*.id", "!=", None]
],
delimiter=None)
# call connected blocks if condition 1 matched
if found_match_1:
filter_new_artifacts(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
comment_no_new_artifacts(action=action, success=success, container=container, results=results, handle=handle)
return
@phantom.playbook_block()
def filter_new_artifacts(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("filter_new_artifacts() called")
################################################################################
# Only dispatch playbooks against new artifacts.
################################################################################
# collect filtered artifact ids and results for 'if' condition 1
matched_artifacts_1, matched_results_1 = phantom.condition(
container=container,
conditions=[
["artifact:*.id", "!=", None]
],
name="filter_new_artifacts:condition_1",
delimiter=None)
# call connected blocks if filtered artifacts or results
if matched_artifacts_1 or matched_results_1:
dispatch_dns_denylisting_playbooks(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 comment_no_new_artifacts(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("comment_no_new_artifacts() called")
################################################################################
# Add comment when no new artifacts exists.
################################################################################
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.comment(container=container, comment="No new artifacts found.")
return
@phantom.playbook_block()
def dispatch_dns_denylisting_playbooks(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("dispatch_dns_denylisting_playbooks() called")
container_artifact_data = phantom.collect2(container=container, datapath=["artifact:*.id"])
container_artifact_header_item_0 = [item[0] for item in container_artifact_data]
inputs = {
"playbook_tags": ["denylist"],
"playbook_repo": [],
"indicator_tags_include": [],
"indicator_tags_exclude": [],
"artifact_ids_include": container_artifact_header_item_0,
}
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
# call playbook "community/dispatch_input_playbooks", returns the playbook_run_id
playbook_run_id = phantom.playbook("community/dispatch_input_playbooks", container=container, name="dispatch_dns_denylisting_playbooks", callback=outputs_decision, inputs=inputs)
return
@phantom.playbook_block()
def outputs_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("outputs_decision() called")
################################################################################
# Determine if outputs exist.
################################################################################
# check for 'if' condition 1
found_match_1 = phantom.decision(
container=container,
conditions=[
["dispatch_dns_denylisting_playbooks:playbook_output:observable", "!=", None]
],
delimiter=None)
# call connected blocks if condition 1 matched
if found_match_1:
output_filter(action=action, success=success, container=container, results=results, handle=handle)
return
# check for 'else' condition 2
comment_no_observables(action=action, success=success, container=container, results=results, handle=handle)
return
@phantom.playbook_block()
def tag_indicators(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("tag_indicators() called")
filtered_output_0_dispatch_dns_denylisting_playbooks_output_observable = phantom.collect2(container=container, datapath=["filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.value"])
parameters = []
# build parameters list for 'tag_indicators' call
for filtered_output_0_dispatch_dns_denylisting_playbooks_output_observable_item in filtered_output_0_dispatch_dns_denylisting_playbooks_output_observable:
parameters.append({
"tags": "blocked",
"indicator": filtered_output_0_dispatch_dns_denylisting_playbooks_output_observable_item[0],
"overwrite": None,
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/indicator_tag", parameters=parameters, name="tag_indicators", callback=format_note)
return
@phantom.playbook_block()
def format_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("format_note() called")
################################################################################
# Format a note that merges together normalized data.
################################################################################
template = """Splunk SOAR blocked the following domains:\n\n| domain | status | source |\n| --- | --- | --- |\n%%\n| {0} | {1} | {2} |\n%%\n"""
# parameter list for template variable replacement
parameters = [
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.value",
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.status",
"filtered-data:output_filter:condition_1:dispatch_dns_denylisting_playbooks:playbook_output:observable.source"
]
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.format(container=container, template=template, parameters=parameters, name="format_note")
update_isolation_task(container=container)
return
@phantom.playbook_block()
def update_isolation_task(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("update_isolation_task() called")
id_value = container.get("id", None)
format_note = phantom.get_format_data(name="format_note")
parameters = []
parameters.append({
"owner": None,
"status": "complete",
"container": id_value,
"task_name": "playbook",
"note_title": "DNS Denylisting Dispatch Report",
"note_content": format_note,
})
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.custom_function(custom_function="community/workbook_task_update", parameters=parameters, name="update_isolation_task")
return
@phantom.playbook_block()
def comment_no_observables(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("comment_no_observables() called")
################################################################################
# Add comment when no observables were generated.
################################################################################
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
phantom.comment(container=container, comment="No observable data found from dispatched playbooks.")
return
@phantom.playbook_block()
def output_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
phantom.debug("output_filter() called")
################################################################################
# Determine if the observable is not None.
################################################################################
# collect filtered artifact ids and results for 'if' condition 1
matched_artifacts_1, matched_results_1 = phantom.condition(
container=container,
conditions=[
["dispatch_dns_denylisting_playbooks:playbook_output:observable", "!=", None]
],
name="output_filter:condition_1",
delimiter=None)
# call connected blocks if filtered artifacts or results
if matched_artifacts_1 or matched_results_1:
tag_indicators(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
return
@phantom.playbook_block()
def on_finish(container, summary):
phantom.debug("on_finish() called")
################################################################################
## Custom Code Start
################################################################################
# Write your custom code here...
################################################################################
## Custom Code End
################################################################################
return
+20
View File
@@ -0,0 +1,20 @@
name: DNS Denylisting Dispatch
id: 7fd9a82f-517a-4d86-bf24-4d4158719dc1
version: 1
date: '2023-07-14'
author: Patrick Bareiss, Splunk
type: Response
description: Accepts a list of domains and blocks them. Generates a global report and list of observables.
playbook: DNS_Denylisting_Dispatch
how_to_implement: This playbook looks for artifacts and then dispatches the community denylisting playbooks. This playbook takes the output of those playbooks and nicely formats them into notes and tags indicators with their results.
references:
- https://d3fend.mitre.org/technique/d3f:DNSDenylisting/
app_list: []
tags:
platform_tags:
- D3-DNSDL
playbook_type: Automation
vpe_type: Modern
playbook_fields: []
product:
- Splunk SOAR