diff --git a/playbooks/activedirectory_reset_password.json b/playbooks/activedirectory_reset_password.json
new file mode 100644
index 0000000000..2a5f022a36
--- /dev/null
+++ b/playbooks/activedirectory_reset_password.json
@@ -0,0 +1,2329 @@
+{
+ "blockly": false,
+ "blockly_xml": "",
+ "category": "Use Cases",
+ "coa": {
+ "data": {
+ "clean": true,
+ "code_block": "from random import randint\nfrom random import shuffle",
+ "description": "This playbook resets the password of a potentially compromised user account. First, an analyst is prompted to evaluate the situation and choose whether to reset the account. If they approve, a strong password is generated and the password is reset.",
+ "joint": {
+ "cells": [
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "27ea0953-b4ce-4902-8ece-63e24eae1d1e",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "23da15dd-a900-4675-80fc-8278f452b007",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "3ba40b74-3829-4cf7-8a11-6df171d3f874",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 14
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "6dd2b606-b2ce-4ffb-8131-c0acc1a1ffe0",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "3ba40b74-3829-4cf7-8a11-6df171d3f874",
+ "port": "out-1",
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "7cecdc7c-0289-4151-be2f-87a24bd0b1da",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 16
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "197ac0dd-c42a-43a2-a97c-8ee3120d9a6f",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "7cecdc7c-0289-4151-be2f-87a24bd0b1da",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "398259e5-8720-484b-a46b-ebe664b02687",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 17
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "c11890e9-62ac-43d6-9cef-8f2ed68f88b2",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "398259e5-8720-484b-a46b-ebe664b02687",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "fb2817ec-55f2-4baf-a578-4ea49fdae81a",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 19
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "f1b0583c-1735-4c91-a6af-146682766127",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "7cecdc7c-0289-4151-be2f-87a24bd0b1da",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "5210febc-fbbb-4879-b338-c8f349c0a9c0",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 22
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "10428cae-be4e-46dc-99c8-88724df2b0e9",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "5210febc-fbbb-4879-b338-c8f349c0a9c0",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "10cc4157-7f8e-4dc0-91eb-22e60ff84c02",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 24
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "54d586c2-b91a-47ca-8638-ae343466c5d2",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "10cc4157-7f8e-4dc0-91eb-22e60ff84c02",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "fb2817ec-55f2-4baf-a578-4ea49fdae81a",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 25
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "84ef3f58-73e1-47b9-b331-04926d73c00e",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "3ba40b74-3829-4cf7-8a11-6df171d3f874",
+ "port": "out-2",
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "456dd1f4-e8be-4f08-93e4-53340f34c3f5",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 27
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "dceb1651-6554-4b0a-90a5-366e0dae1c79",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "456dd1f4-e8be-4f08-93e4-53340f34c3f5",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "bf0b85aa-0086-4b5d-a690-281f55555dd3",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 29
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "760bf213-d7a5-41e9-a385-e8927d27fc93",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "bf0b85aa-0086-4b5d-a690-281f55555dd3",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "fb2817ec-55f2-4baf-a578-4ea49fdae81a",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 31
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "20b16b2c-253c-41e7-8a12-9d4f83285c17",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "83d4f311-84e7-42df-bca6-0fcb9ba484d7",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "23da15dd-a900-4675-80fc-8278f452b007",
+ "port": null,
+ "selector": "g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 58
+ },
+ {
+ "0": "S",
+ "1": "T",
+ "2": "A",
+ "3": "R",
+ "4": "T",
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "ref-x": 33,
+ "ref-y": 8,
+ "text": "START"
+ },
+ "g.code image": {
+ "xlink:href": "/inc/coa/img/block_icon_code_dark_on.svg"
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "ref-x": 13,
+ "xlink:href": "/inc/coa/img/block_icon_start.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ }
+ },
+ "block_code": "def on_start(container):\n phantom.debug('on_start() called')\n \n # call 'decision_2' block\n decision_2(container=container)\n\n return",
+ "callback_code": "# read-only block view not available",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "def on_start(container):\n phantom.debug('on_start() called')\n\n reset_password(container=container)\n\n return",
+ "custom_join": "",
+ "custom_name": "",
+ "description": "",
+ "has_custom": true,
+ "has_custom_block": true,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "83d4f311-84e7-42df-bca6-0fcb9ba484d7",
+ "inPorts": [],
+ "join_code": "# read-only block view not available",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 24,
+ "line_start": 17,
+ "name": "",
+ "notes": "",
+ "number": 0,
+ "order": 1,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 80,
+ "y": 100
+ },
+ "previous_function": "",
+ "previous_name": "",
+ "show_number": true,
+ "size": {
+ "height": 54,
+ "width": 80
+ },
+ "status": "",
+ "title": "START",
+ "type": "coa.StartEnd",
+ "warn": false,
+ "z": 120
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 1
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def reset_option(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('reset_option() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"reset_password:action_result.summary.responses.0\", \"==\", \"Yes\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n generate_password(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 2\n format_decline_msg(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "reset option",
+ "description": "",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "3ba40b74-3829-4cf7-8a11-6df171d3f874",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 113,
+ "line_start": 92,
+ "name": "decision",
+ "notes": "Follow direction of the prompt for resetting the user's password\n\nGREEN: Proceed with reset\nPURPLE: Proceed to end (with notes)",
+ "number": 1,
+ "order": 4,
+ "outPorts": [
+ "out-1",
+ "out-2"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "reset_password:action_result.summary.responses.0",
+ "value": "Yes"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 380,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "reset_option",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 122
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format decline msg"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_decline_msg(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_decline_msg() called')\n \n template = \"\"\"Analyst declined to reset password for user: {0}\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"artifact:*.cef.compromisedUserName\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_decline_msg\")\n\n add_comment_no_reset(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format decline msg",
+ "description": "Formats a message stating the user declined to reset the password",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "456dd1f4-e8be-4f08-93e4-53340f34c3f5",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 189,
+ "line_start": 173,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Formats a message stating the user declined to reset the password",
+ "number": 2,
+ "order": 8,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "artifact:*.cef.compromisedUserName"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 520,
+ "y": 220
+ },
+ "previous_function": "",
+ "previous_name": "format_decline_msg",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "Analyst declined to reset password for user: {0}",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 127
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "add comment no reset"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def add_comment_no_reset(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('add_comment_no_reset() called')\n\n formatted_data_1 = phantom.get_format_data(name='format_decline_msg')\n\n phantom.comment(container=container, comment=formatted_data_1)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "format_decline_msg:formatted_data",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "add comment no reset",
+ "description": "Add the comment notifying the reader that the password reset was declined",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "bf0b85aa-0086-4b5d-a690-281f55555dd3",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 201,
+ "line_start": 192,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "Add the comment notifying the reader that the password reset was declined",
+ "number": 3,
+ "order": 9,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1000,
+ "y": 220
+ },
+ "previous_function": "",
+ "previous_name": "add_comment_no_reset",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 130
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format pwd message"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_pwd_message(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_pwd_message() called')\n \n template = \"\"\"Reset user {0} password to {1}\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"artifact:*.cef.compromisedUserName\",\n \"generate_password:custom_function:strong_password\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_pwd_message\")\n\n add_comment_pwd_reset(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format pwd message",
+ "description": "Formats a message about the password reset to provide in the comments",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "5210febc-fbbb-4879-b338-c8f349c0a9c0",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 170,
+ "line_start": 153,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Formats a message about the password reset to provide in the comments",
+ "number": 1,
+ "order": 7,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "artifact:*.cef.compromisedUserName"
+ },
+ {
+ "position": 1,
+ "type": "",
+ "value": "generate_password:custom_function:strong_password"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 760,
+ "y": -60
+ },
+ "previous_function": "",
+ "previous_name": "format_pwd_message",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "Reset user {0} password to {1}",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 132
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "add comment pwd reset"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def add_comment_pwd_reset(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('add_comment_pwd_reset() called')\n\n formatted_data_1 = phantom.get_format_data(name='format_pwd_message')\n\n phantom.comment(container=container, comment=formatted_data_1)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "format_pwd_message:formatted_data",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "add comment pwd reset",
+ "description": "",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "10cc4157-7f8e-4dc0-91eb-22e60ff84c02",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 150,
+ "line_start": 141,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "This block adds a comment to the Activities pane stating which user had their password reset and the new password",
+ "number": 2,
+ "order": 6,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1000,
+ "y": -60
+ },
+ "previous_function": "",
+ "previous_name": "add_comment_pwd_reset",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 135
+ },
+ {
+ "0": "E",
+ "1": "N",
+ "2": "D",
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".title": {
+ "text": "END"
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_end.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ }
+ },
+ "block_code": "def on_finish(container, summary):\n phantom.debug('on_finish() called')\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 return",
+ "callback_code": "# read-only block view not available",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "reset ad password, reset password, reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "description": "",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "fb2817ec-55f2-4baf-a578-4ea49fdae81a",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "# read-only block view not available",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 214,
+ "line_start": 201,
+ "name": "",
+ "notes": "",
+ "number": 0,
+ "order": 10,
+ "outPorts": [],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1240,
+ "y": 180
+ },
+ "previous_function": "",
+ "previous_name": "",
+ "show_number": true,
+ "size": {
+ "height": 54,
+ "width": 80
+ },
+ "status": "",
+ "title": "END",
+ "type": "coa.StartEnd",
+ "warn": false,
+ "z": 137
+ },
+ {
+ "action": "set password",
+ "action_type": "contain",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "new_password": "generate_password:custom_function:strong_password",
+ "username": "artifact:*.cef.compromisedUserName"
+ },
+ "angle": 0,
+ "app": "",
+ "appid": "",
+ "approver": "",
+ "assets": [
+ {
+ "action": "set password",
+ "actions": [
+ "run query",
+ "list users",
+ "get system info",
+ "list services",
+ "get users",
+ "reset password",
+ "set password",
+ "get system attributes",
+ "get user attributes",
+ "set system attribute",
+ "change system ou",
+ "list user groups",
+ "enable user",
+ "disable user",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "LDAP",
+ "app_version": "1.2.40",
+ "appid": "84110F27-6602-4DC8-A6F2-0311B1720BF8",
+ "asset_name": "active directory",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "new_password": "generate_password:custom_function:strong_password",
+ "username": "artifact:*.cef.compromisedUserName"
+ },
+ "has_app": true,
+ "id": 22,
+ "loaded": false,
+ "missing": false,
+ "name": "active directory",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.new_password",
+ "data_type": "string",
+ "example_values": [
+ "abc@123"
+ ]
+ },
+ {
+ "column_name": "Username",
+ "column_order": 0,
+ "contains": [
+ "user name",
+ "ldap distinguished name"
+ ],
+ "data_path": "action_result.parameter.username",
+ "data_type": "string",
+ "example_values": [
+ "test_user3"
+ ]
+ },
+ {
+ "data_path": "action_result.data",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.summary",
+ "data_type": "string"
+ },
+ {
+ "column_name": "Message",
+ "column_order": 1,
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "User password changed"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "new_password": {
+ "data_type": "string",
+ "default": null,
+ "description": "Password string to set",
+ "key": "new_password",
+ "order": 1,
+ "required": true
+ },
+ "username": {
+ "contains": [
+ "user name",
+ "ldap distinguished name"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Username to change password of",
+ "key": "username",
+ "order": 0,
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "Windows Server",
+ "product_vendor": "Microsoft",
+ "targets": "22",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "reset ad password"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Contain"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_contain.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def reset_ad_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('reset_ad_password() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n generate_password__strong_password = json.loads(phantom.get_run_data(key='generate_password:strong_password'))\n # collect data for 'reset_ad_password' call\n container_data = phantom.collect2(container=container, datapath=['artifact:*.cef.compromisedUserName', 'artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'reset_ad_password' call\n for container_item in container_data:\n if container_item[0]:\n parameters.append({\n 'username': container_item[0],\n 'new_password': generate_password__strong_password,\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': container_item[1]},\n })\n\n phantom.act(action=\"set password\", parameters=parameters, assets=['active directory'], name=\"reset_ad_password\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "reset ad password",
+ "delay": 0,
+ "description": "Reset the Active Directory password of the user to the generated password",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "398259e5-8720-484b-a46b-ebe664b02687",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 141,
+ "line_start": 116,
+ "message": "Configuring now",
+ "name": "set password",
+ "notes": "Reset the Active Directory password of the user to the generated password",
+ "number": 1,
+ "order": 5,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1000,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "reset_ad_password",
+ "required_params": {
+ "new_password": true,
+ "username": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "action_assets",
+ "status": "",
+ "title": "Contain",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 138
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "approver": "admin",
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 1
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def reset_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('reset_password() called')\n \n # set user and message variables for phantom.prompt call\n user = \"admin\"\n message = \"\"\"Found the account \\\"{0}\\\" has a compromised credential! Would you like to automatically reset the password?\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"artifact:*.cef.compromisedUserName\",\n ]\n\n #responses:\n response_types = [\n {\n \"prompt\": \"\",\n \"options\": {\n \"type\": \"list\",\n \"choices\": [\n \"Yes\",\n \"No\",\n ]\n },\n },\n ]\n\n phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name=\"reset_password\", parameters=parameters, response_types=response_types, callback=reset_option)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "reset password",
+ "description": "",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "23da15dd-a900-4675-80fc-8278f452b007",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 92,
+ "line_start": 62,
+ "message": "Found the account \"{0}\" has a compromised credential! Would you like to automatically reset the password?",
+ "name": "prompt",
+ "notes": "Prompts the user if they'd like to reset the password in Active Directory",
+ "number": 1,
+ "order": 3,
+ "outPorts": [
+ "out"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "artifact:*.cef.compromisedUserName"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 240,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "reset_password",
+ "respond_in": "30",
+ "response_key": "Message",
+ "response_options": [],
+ "response_type": "list",
+ "responses": [
+ {
+ "response_key": "Yes/No",
+ "response_options": [
+ "Yes",
+ "No"
+ ],
+ "response_prompt": "",
+ "response_type": "list"
+ }
+ ],
+ "show_number": true,
+ "size": {
+ "height": 80,
+ "width": 80
+ },
+ "state": "prompt",
+ "status": "",
+ "type": "coa.Prompt",
+ "warn": false,
+ "z": 139
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".functionBlock": {
+ "text": "generate password"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "custom function"
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 1
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn_grey.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def generate_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('generate_password() called')\n \n input_parameter_0 = \"\"\n\n generate_password__strong_password = None\n\n ################################################################################\n ## Custom Code Start\n ################################################################################\n\n alpha = 'abcdefghijklmnopqrstuvwxyz'\n num = '0123456789'\n special = '!@#$%^&*('\n \n pwd = ''\n for i in range(5):\n pwd += alpha[randint(0, len(alpha)-1)]\n pwd += (alpha[randint(0, len(alpha)-1)]).upper()\n pwd += num[randint(0, len(num)-1)]\n pwd += special[randint(0, len(special)-1)]\n r = list(pwd)\n shuffle(r)\n generate_password__strong_password = ''.join(r)\n\n ################################################################################\n ## Custom Code End\n ################################################################################\n\n phantom.save_run_data(key='generate_password:strong_password', value=json.dumps(generate_password__strong_password))\n reset_ad_password(container=container)\n format_pwd_message(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "reset password",
+ "connection_type": "action",
+ "customCodeEndLineOffset": 8,
+ "customCodeStartLine": 10,
+ "custom_callback": "",
+ "custom_code": "def generate_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None):\n phantom.debug('custom_function_1() called')\n input_parameter_0 = \"\"\n\n generate_password__strong_password = None\n\n ################################################################################\n ## Custom Code Start\n ################################################################################\n\n alpha = 'abcdefghijklmnopqrstuvwxyz'\n num = '0123456789'\n special = '!@#$%^&*('\n \n pwd = ''\n for i in range(5):\n pwd += alpha[randint(0, len(alpha)-1)]\n pwd += (alpha[randint(0, len(alpha)-1)]).upper()\n pwd += num[randint(0, len(num)-1)]\n pwd += special[randint(0, len(special)-1)]\n r = list(pwd)\n shuffle(r)\n generate_password__strong_password = ''.join(r)\n\n ################################################################################\n ## Custom Code End\n ################################################################################\n\n phantom.save_run_data(key='custom_function_1:strong_password', value=json.dumps(generate_password__strong_password))\n\n return",
+ "custom_join": "",
+ "custom_name": "generate password",
+ "description": "Custom code block that generates a strong random password",
+ "functionBlock": "custom function",
+ "has_custom": true,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "7cecdc7c-0289-4151-be2f-87a24bd0b1da",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "legacy": true,
+ "line_end": 62,
+ "line_start": 27,
+ "message": "Configuring now",
+ "name": "custom function",
+ "notes": "Custom code block that generates a strong random password",
+ "number": 1,
+ "order": 2,
+ "outPorts": [
+ "out"
+ ],
+ "outputVariables": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "strong_password"
+ }
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": ""
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 520,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "generate_password",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "custom function",
+ "status": "deprecating",
+ "title": "custom function",
+ "type": "coa.FunctionBlock",
+ "userGeneratedCode": "\n alpha = 'abcdefghijklmnopqrstuvwxyz'\n num = '0123456789'\n special = '!@#$%^&*('\n \n pwd = ''\n for i in range(5):\n pwd += alpha[randint(0, len(alpha)-1)]\n pwd += (alpha[randint(0, len(alpha)-1)]).upper()\n pwd += num[randint(0, len(num)-1)]\n pwd += special[randint(0, len(special)-1)]\n r = list(pwd)\n shuffle(r)\n generate_password__strong_password = ''.join(r)\n",
+ "warn": false,
+ "z": 140
+ }
+ ]
+ },
+ "notes": "This playbook uses the following Apps:\n - LDAP (set password) - reset the password of a user\n\nDeployment Notes:\n - This playbook works on artifacts with artifact:*.cef.compromisedUserName which can be created as shown in the playbook \"recorded_future_handle_leaked_credentials\"\n - The prompt is hard-coded to use \"admin\" as the user, so change it to the correct user or role"
+ },
+ "python_version": "3",
+ "schema": 4,
+ "version": "4.10.0.40677"
+ },
+ "create_time": "2020-12-08T16:37:21.322527+00:00",
+ "draft_mode": false,
+ "labels": [
+ "events"
+ ],
+ "tags": [],
+ "misc": {
+ "apps_list": [
+ "LDAP"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/playbooks/activedirectory_reset_password.png b/playbooks/activedirectory_reset_password.png
new file mode 100644
index 0000000000..c9fa8f115c
Binary files /dev/null and b/playbooks/activedirectory_reset_password.png differ
diff --git a/playbooks/activedirectory_reset_password.py b/playbooks/activedirectory_reset_password.py
new file mode 100644
index 0000000000..0a009524c1
--- /dev/null
+++ b/playbooks/activedirectory_reset_password.py
@@ -0,0 +1,214 @@
+"""
+This playbook resets the password of a potentially compromised user account. First, an analyst is prompted to evaluate the situation and choose whether to reset the account. If they approve, a strong password is generated and the password is reset.
+"""
+
+import phantom.rules as phantom
+import json
+from datetime import datetime, timedelta
+##############################
+# Start - Global Code Block
+
+from random import randint
+from random import shuffle
+
+# End - Global Code block
+##############################
+
+def on_start(container):
+ phantom.debug('on_start() called')
+
+ reset_password(container=container)
+
+ return
+
+"""
+Custom code block that generates a strong random password
+"""
+def generate_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('generate_password() called')
+
+ input_parameter_0 = ""
+
+ generate_password__strong_password = None
+
+ ################################################################################
+ ## Custom Code Start
+ ################################################################################
+
+ alpha = 'abcdefghijklmnopqrstuvwxyz'
+ num = '0123456789'
+ special = '!@#$%^&*('
+
+ pwd = ''
+ for i in range(5):
+ pwd += alpha[randint(0, len(alpha)-1)]
+ pwd += (alpha[randint(0, len(alpha)-1)]).upper()
+ pwd += num[randint(0, len(num)-1)]
+ pwd += special[randint(0, len(special)-1)]
+ r = list(pwd)
+ shuffle(r)
+ generate_password__strong_password = ''.join(r)
+
+ ################################################################################
+ ## Custom Code End
+ ################################################################################
+
+ phantom.save_run_data(key='generate_password:strong_password', value=json.dumps(generate_password__strong_password))
+ reset_ad_password(container=container)
+ format_pwd_message(container=container)
+
+ return
+
+def reset_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('reset_password() called')
+
+ # set user and message variables for phantom.prompt call
+ user = "admin"
+ message = """Found the account \"{0}\" has a compromised credential! Would you like to automatically reset the password?"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "artifact:*.cef.compromisedUserName",
+ ]
+
+ #responses:
+ response_types = [
+ {
+ "prompt": "",
+ "options": {
+ "type": "list",
+ "choices": [
+ "Yes",
+ "No",
+ ]
+ },
+ },
+ ]
+
+ phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="reset_password", parameters=parameters, response_types=response_types, callback=reset_option)
+
+ return
+
+def reset_option(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('reset_option() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["reset_password:action_result.summary.responses.0", "==", "Yes"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ generate_password(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 2
+ format_decline_msg(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+Reset the Active Directory password of the user to the generated password
+"""
+def reset_ad_password(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('reset_ad_password() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ generate_password__strong_password = json.loads(phantom.get_run_data(key='generate_password:strong_password'))
+ # collect data for 'reset_ad_password' call
+ container_data = phantom.collect2(container=container, datapath=['artifact:*.cef.compromisedUserName', 'artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'reset_ad_password' call
+ for container_item in container_data:
+ if container_item[0]:
+ parameters.append({
+ 'username': container_item[0],
+ 'new_password': generate_password__strong_password,
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': container_item[1]},
+ })
+
+ phantom.act(action="set password", parameters=parameters, assets=['active directory'], name="reset_ad_password")
+
+ return
+
+def add_comment_pwd_reset(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('add_comment_pwd_reset() called')
+
+ formatted_data_1 = phantom.get_format_data(name='format_pwd_message')
+
+ phantom.comment(container=container, comment=formatted_data_1)
+
+ return
+
+"""
+Formats a message about the password reset to provide in the comments
+"""
+def format_pwd_message(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_pwd_message() called')
+
+ template = """Reset user {0} password to {1}"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "artifact:*.cef.compromisedUserName",
+ "generate_password:custom_function:strong_password",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_pwd_message")
+
+ add_comment_pwd_reset(container=container)
+
+ return
+
+"""
+Formats a message stating the user declined to reset the password
+"""
+def format_decline_msg(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_decline_msg() called')
+
+ template = """Analyst declined to reset password for user: {0}"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "artifact:*.cef.compromisedUserName",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_decline_msg")
+
+ add_comment_no_reset(container=container)
+
+ return
+
+"""
+Add the comment notifying the reader that the password reset was declined
+"""
+def add_comment_no_reset(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('add_comment_no_reset() called')
+
+ formatted_data_1 = phantom.get_format_data(name='format_decline_msg')
+
+ phantom.comment(container=container, comment=formatted_data_1)
+
+ return
+
+def on_finish(container, summary):
+ phantom.debug('on_finish() called')
+ # This function is called after all actions are completed.
+ # summary of all the action and/or all details of actions
+ # can be collected here.
+
+ # summary_json = phantom.get_summary()
+ # if 'result' in summary_json:
+ # for action_result in summary_json['result']:
+ # if 'action_run_id' in action_result:
+ # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
+ # phantom.debug(action_results)
+
+ return
\ No newline at end of file
diff --git a/playbooks/activedirectory_reset_password.yml b/playbooks/activedirectory_reset_password.yml
new file mode 100644
index 0000000000..103fee5823
--- /dev/null
+++ b/playbooks/activedirectory_reset_password.yml
@@ -0,0 +1,19 @@
+name: Active Directory Reset password
+id: fc0edc96-ff2b-48b0-9f6f-63da6783fd63
+version: 1
+date: '2020-12-08'
+author: Philip Royer, Splunk
+type: Response
+description: This playbook resets the password of a potentially compromised user account. First, an analyst is prompted to evaluate the situation and choose whether to reset the account. If they approve, a strong password is generated and the password is reset.
+playbook: activedirectory_reset_password
+how_to_implement: This playbook works on artifacts with artifact:*.cef.compromisedUserName which can be created as shown in the playbook "recorded_future_handle_leaked_credentials" - The prompt is hard-coded to use "admin" as the user, so change it to the correct user or role
+references: []
+app_list:
+- "LDAP"
+tags:
+ platform_tags:
+ - Response
+ playbook_fields:
+ - compromisedUserName
+ product:
+ - Splunk SOAR
\ No newline at end of file
diff --git a/playbooks/crowdstrike_malware_triage.json b/playbooks/crowdstrike_malware_triage.json
new file mode 100644
index 0000000000..588879e265
--- /dev/null
+++ b/playbooks/crowdstrike_malware_triage.json
@@ -0,0 +1,9686 @@
+{
+ "blockly": false,
+ "blockly_xml": "",
+ "category": "Use Cases",
+ "misc": { "apps_list": ["CrowdStrike OAuth API"] },
+ "coa": {
+ "data": {
+ "clean": true,
+ "code_block": "",
+ "description": "Enrich and respond to a CrowdStrike Falcon detection involving a potentially malicious executable on an endpoint. Check for previous sightings of the same executable, hunt across other endpoints for the file, gather details about all processes associated with the file, and collect all the gathered information into a prompt for an analyst to review. Based on the analyst's choice, the file can be added to the custom indicators list in CrowdStrike with a detection policy of \"detect\" or \"none\", and the endpoint can be optionally quarantined from the network.",
+ "hash": "79619e5a31b4302e5150a07fe13c32a2f669f176",
+ "joint": {
+ "cells": [
+ {
+ "0": "S",
+ "1": "T",
+ "2": "A",
+ "3": "R",
+ "4": "T",
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "ref-x": 33,
+ "ref-y": 8,
+ "text": "START"
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "ref-x": 13,
+ "xlink:href": "/inc/coa/img/block_icon_start.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ }
+ },
+ "block_code": "def on_start(container):\n phantom.debug('on_start() called')\n \n # call 'if_sha256_exists' block\n if_sha256_exists(container=container)\n\n return",
+ "callback_code": "# read-only block view not available",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "description": "",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "4fa5d104-e7c6-43d9-8485-4172636299a6",
+ "inPorts": [],
+ "join_code": "# read-only block view not available",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 16,
+ "line_start": 8,
+ "name": "",
+ "notes": "",
+ "number": 0,
+ "order": 1,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -560,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "",
+ "show_number": true,
+ "size": {
+ "height": 54,
+ "width": 80
+ },
+ "status": "",
+ "title": "START",
+ "type": "coa.StartEnd",
+ "warn": false,
+ "z": 26
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "e7df7f9c-7de3-4800-bb0c-a06f4b930e17",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "4fa5d104-e7c6-43d9-8485-4172636299a6",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "9438c5bf-bef5-455c-bf2a-8c3edd0e080f",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 27
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "9a480146-1bcb-4d7e-ba1d-3737838fa170",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "c5d59d69-49e7-4433-a650-d1b0b98e74be",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "0484d948-e831-4efc-b3a4-5f7f6ffb9441",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 45
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "9d7d3005-2b76-4c46-9a3e-0340a7b15461",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "a03011e0-61d6-4949-b0c2-03e18b844dba",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "278bf5f1-38a2-4a6c-924e-4f37b28fa60e",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 62
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "e98a19a1-65ba-40d6-a3c3-49f6f9c63478",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "9438c5bf-bef5-455c-bf2a-8c3edd0e080f",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "c0ae58bf-47b9-4b4d-92bf-0172765aafc6",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 67
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "abd2b302-0df4-4795-be1b-bf5ca53710b7",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "9438c5bf-bef5-455c-bf2a-8c3edd0e080f",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "ffbb7b76-3326-4a51-aeb9-b60c5a82893a",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 68
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "12e9a5e5-83c1-4056-9fcc-99bfafcb07ae",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "ffbb7b76-3326-4a51-aeb9-b60c5a82893a",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "c5d59d69-49e7-4433-a650-d1b0b98e74be",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 72
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "98bee464-56d3-471d-a0c8-c0d7fe380b87",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "0484d948-e831-4efc-b3a4-5f7f6ffb9441",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "6d11a3cf-6f79-4280-a83c-ff518a10f734",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 77
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "46b3bc83-60ee-493f-bb85-519eca01c1f1",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "0484d948-e831-4efc-b3a4-5f7f6ffb9441",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 90
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "6de32435-c2b3-46d4-8e2b-cfed0ad4d5d2",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "0ab1d7d6-afc7-4a0d-b9f4-8079cf67c624",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 96
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "c973bc87-1068-4a4f-b77d-da57579d114c",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "a03011e0-61d6-4949-b0c2-03e18b844dba",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 99
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "438d8d1b-db6f-4005-a9dc-6b4f0dddfb55",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "port": "out-3",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(3) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "b827b91f-97e9-4a99-983a-bdb0b4eb98ce",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 101
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "d8de0ef2-d498-41d4-9c74-7b84550458d6",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "ea7fbdda-bb34-4d57-9973-03db50614381",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 108
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "4a76ade7-9d28-4cec-873a-2a41e5d65816",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "005c6087-3fe9-4e37-89f7-f170dd34412b",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "09fbbded-a2ad-433f-968d-40f3ae3c189e",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 123
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "2976e19a-9a82-4e59-90de-8990cae42c3c",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "ea7fbdda-bb34-4d57-9973-03db50614381",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "44aeff0b-c413-4567-8916-e979e6c31fe0",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 129
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "dda15c41-a25c-4a4b-a82a-cff5f5d6c1c1",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "0484d948-e831-4efc-b3a4-5f7f6ffb9441",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "2d0844c0-d8d8-4435-9b26-38ea0b6f2c3b",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 135
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "009d45df-a04f-4b81-9b48-7fd11e7519c7",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "2d0844c0-d8d8-4435-9b26-38ea0b6f2c3b",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "583356d6-13eb-45bf-9d38-5cbe82358374",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 137
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "37948fb9-ef42-475e-897b-b5d7ab70c787",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "583356d6-13eb-45bf-9d38-5cbe82358374",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "09fbbded-a2ad-433f-968d-40f3ae3c189e",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 142
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "77f22435-3a23-40cc-8db2-fb8a0d58d71c",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "09fbbded-a2ad-433f-968d-40f3ae3c189e",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "e6b6bdfa-6ec1-40a6-96fd-1f9b535b2087",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 158
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "7e7cfb9e-a76f-454a-8bb3-75834b3c43b5",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "e6b6bdfa-6ec1-40a6-96fd-1f9b535b2087",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "f39ff0a8-97cc-494b-b692-346dd89eab7a",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 169
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "f7faed44-e0ab-47b7-ac8e-0f9d359172e4",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "e6b6bdfa-6ec1-40a6-96fd-1f9b535b2087",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "d5f48d34-ef50-4204-956c-7023b9846414",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 171
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "d6bcabed-8255-4f1c-be0f-56ba3de1a048",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "f39ff0a8-97cc-494b-b692-346dd89eab7a",
+ "port": "out-3",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(3) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "da97de34-c6e5-47a8-bfcb-0a7ee4cca2a1",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 185
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "9317d7f4-b334-4bf2-858d-a5e7342316a9",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "da97de34-c6e5-47a8-bfcb-0a7ee4cca2a1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "d04015bf-190d-415d-8fab-06f8f1276751",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 187
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "4c25afd4-6695-4f80-aff8-3e10cb1c2c87",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "f39ff0a8-97cc-494b-b692-346dd89eab7a",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "d6ae9b4a-a027-4ce4-b4ea-15a67a35668d",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 191
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "211f8472-10ee-4574-acca-42911a6f30fa",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "f39ff0a8-97cc-494b-b692-346dd89eab7a",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "0f9d0bb7-4931-4e17-b50f-03ff0551c70d",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 194
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "e77c9eac-4850-48f5-8d35-895a8d05e027",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "0f9d0bb7-4931-4e17-b50f-03ff0551c70d",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "a8b369f1-2a55-4e49-85da-a66c35534861",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 207
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "ab597937-b68a-4157-9f2e-5f751fdbc2e2",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "d5f48d34-ef50-4204-956c-7023b9846414",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "e67e9ce0-f06d-4687-b3ed-d5d24860ed82",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 214
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "e0fef39f-1fc8-4576-9c72-4174b190b878",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "d5f48d34-ef50-4204-956c-7023b9846414",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "8f1bc7f0-5b9e-4e9c-9159-ee6a2b73c0e5",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 216
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "f59e09bf-d4fd-453b-b411-73cebcf84946",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "a8b369f1-2a55-4e49-85da-a66c35534861",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "a51b3d43-d32c-4e5a-8e14-0a18c119d81a",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 221
+ },
+ {
+ "0": "E",
+ "1": "N",
+ "2": "D",
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".title": {
+ "text": "END"
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_end.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ }
+ },
+ "block_code": "def on_finish(container, summary):\n phantom.debug('on_finish() called')\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 return",
+ "callback_code": "# read-only block view not available",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "create detect indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "description": "",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "a51b3d43-d32c-4e5a-8e14-0a18c119d81a",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "# read-only block view not available",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 792,
+ "line_start": 779,
+ "name": "",
+ "notes": "",
+ "number": 0,
+ "order": 33,
+ "outPorts": [],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1760,
+ "y": 80
+ },
+ "previous_function": "",
+ "previous_name": "",
+ "show_number": true,
+ "size": {
+ "height": 54,
+ "width": 80
+ },
+ "status": "",
+ "title": "END",
+ "type": "coa.StartEnd",
+ "warn": false,
+ "z": 228
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "68b66efc-be78-468d-bb79-c78cea946d63",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "6d11a3cf-6f79-4280-a83c-ff518a10f734",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "005c6087-3fe9-4e37-89f7-f170dd34412b",
+ "selector": "> g:nth-child(1) > g:nth-child(1) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "type": "link",
+ "z": 241
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 2
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def if_sha256_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('if_sha256_exists() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n conditions=[\n [\"artifact:*.cef.fileHashSha256\", \"!=\", \"\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n filter_main_artifact(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 2\n ignore_if_no_sha256(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "if sha256 exists",
+ "description": "Ensure that the event has at least one artifact with a SHA256 file hash before attempting to process the event.",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "9438c5bf-bef5-455c-bf2a-8c3edd0e080f",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 66,
+ "line_start": 46,
+ "name": "decision",
+ "notes": "Ensure that the event has at least one artifact with a SHA256 file hash before attempting to process the event.",
+ "number": 2,
+ "order": 3,
+ "outPorts": [
+ "out-1",
+ "out-2"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "!=",
+ "data_type": "",
+ "param": "artifact:*.cef.fileHashSha256",
+ "value": ""
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -420,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "if_sha256_exists",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 252
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 1
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def filter_main_artifact(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('filter_main_artifact() called')\n\n # collect filtered artifact ids for 'if' condition 1\n matched_artifacts_1, matched_results_1 = phantom.condition(\n container=container,\n conditions=[\n [\"artifact:*.label\", \"==\", \"event\"],\n ],\n name=\"filter_main_artifact:condition_1\")\n\n # call connected blocks if filtered artifacts or results\n if matched_artifacts_1 or matched_results_1:\n get_indicator_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "filter main artifact",
+ "description": "Only process the main detection artifact, not any sub event artifacts.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "ffbb7b76-3326-4a51-aeb9-b60c5a82893a",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 208,
+ "line_start": 191,
+ "name": "filter",
+ "notes": "Only process the main detection artifact, not any sub event artifacts.",
+ "number": 1,
+ "order": 10,
+ "outPorts": [
+ "out-1"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "artifact:*.label",
+ "value": "event"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -280,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "filter_main_artifact",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "filter",
+ "status": "",
+ "type": "coa.Filter",
+ "warn": false,
+ "z": 253
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "ignore if no sha256"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def ignore_if_no_sha256(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('ignore_if_no_sha256() called')\n\n phantom.comment(container=container, comment=\"Ignoring alert because no SHA256 file hash was found\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "Ignoring alert because no SHA256 file hash was found",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "ignore if no sha256",
+ "description": "End the playbook if no SHA256 file hash is found in any of the artifacts.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "c0ae58bf-47b9-4b4d-92bf-0172765aafc6",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 76,
+ "line_start": 69,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "End the playbook if no SHA256 file hash is found in any of the artifacts.",
+ "number": 1,
+ "order": 4,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -140,
+ "y": 200
+ },
+ "previous_function": "",
+ "previous_name": "ignore_if_no_sha256",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 255
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 4
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-2": {
+ "port": {
+ "id": "out-3",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": -2
+ },
+ ".outPorts>.port-2>.port-body": {
+ "port": {
+ "id": "out-3",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def indicator_policy_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('indicator_policy_decision() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"get_indicator_2:action_result.data.*.resources.*.policy\", \"==\", \"none\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n detection_policy_none(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # check for 'elif' condition 2\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"get_indicator_2:action_result.data.*.resources.*.policy\", \"==\", \"detect\"],\n ])\n\n # call connected blocks if condition 2 matched\n if matched:\n escalate_severity_to_high(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n format_repeat_note(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 3\n comment_unexpected_policy(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "indicator policy decision",
+ "description": "Handle the Indicator differently if the policy is \"detect\", \"none\", or other.",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "44f59298-23fc-4206-b2bb-672cb157944e",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 246,
+ "line_start": 211,
+ "name": "decision",
+ "notes": "Handle the Indicator differently if the policy is \"detect\", \"none\", or other.",
+ "number": 4,
+ "order": 11,
+ "outPorts": [
+ "out-1",
+ "out-2",
+ "out-3"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "get_indicator_2:action_result.data.*.resources.*.policy",
+ "value": "none"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "get_indicator_2:action_result.data.*.resources.*.policy",
+ "value": "detect"
+ }
+ ],
+ "display": "Else If",
+ "logic": "and",
+ "type": "elif"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 180,
+ "y": 340
+ },
+ "previous_function": "",
+ "previous_name": "indicator_policy_decision",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 258
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "set status",
+ "attrs": {
+ ".api": {
+ "text": "close event"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def close_event(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('close_event() called')\n\n phantom.set_status(container=container, status=\"Closed\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "key": "set-status",
+ "setStatusStatus": "Closed",
+ "setStatusStatus_display": "Closed"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "close event",
+ "description": "Close the event because the Indicator policy is \"none\", meaning the detection is a false positive.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "44aeff0b-c413-4567-8916-e979e6c31fe0",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 357,
+ "line_start": 350,
+ "message": "Configuring now",
+ "name": "set status",
+ "notes": "Close the event because the Indicator policy is \"none\", meaning the detection is a false positive.",
+ "number": 8,
+ "order": 16,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 560,
+ "y": 340
+ },
+ "previous_function": "",
+ "previous_name": "close_event",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 260
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "set severity",
+ "attrs": {
+ ".api": {
+ "text": "escalate severity to high"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def escalate_severity_to_high(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('escalate_severity_to_high() called')\n\n phantom.set_severity(container=container, severity=\"High\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "key": "set-severity",
+ "setSeveritySeverity": "High",
+ "setSeveritySeverity_display": "High"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "escalate severity to high",
+ "description": "Escalate the event because the Indicator policy is \"detect\", meaning the event is a true positive.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "0ab1d7d6-afc7-4a0d-b9f4-8079cf67c624",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 136,
+ "line_start": 129,
+ "message": "Configuring now",
+ "name": "set severity",
+ "notes": "Escalate the event because the Indicator policy is \"detect\", meaning the event is a true positive.",
+ "number": 3,
+ "order": 7,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 320,
+ "y": 480
+ },
+ "previous_function": "",
+ "previous_name": "escalate_severity_to_high",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 261
+ },
+ {
+ "action": "get process detail",
+ "action_type": "investigate",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "falcon_process_id": "list_processes_with_hash:action_result.data.*.falcon_process_id"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "get process detail",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "falcon_process_id": "list_processes_with_hash:action_result.data.*.falcon_process_id"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "column_name": "Status",
+ "column_order": 1,
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "column_name": "Falcon Process ID",
+ "column_order": 0,
+ "contains": [
+ "falcon process id"
+ ],
+ "data_path": "action_result.parameter.falcon_process_id",
+ "data_type": "string",
+ "example_values": [
+ "pid:07c312fabcb8473454d0a16f118928fg:16716090292999"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "column_name": "Command Line",
+ "column_order": 2,
+ "data_path": "action_result.data.*.command_line",
+ "data_type": "string",
+ "example_values": [
+ "C:\test\test.exe"
+ ]
+ },
+ {
+ "column_name": "Crowdstrike Device ID",
+ "column_order": 6,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.data.*.device_id",
+ "data_type": "string",
+ "example_values": [
+ "07c312fabcb8473454d0a16f118928fg"
+ ]
+ },
+ {
+ "column_name": "File Name",
+ "column_order": 3,
+ "contains": [
+ "file name"
+ ],
+ "data_path": "action_result.data.*.file_name",
+ "data_type": "string",
+ "example_values": [
+ "\testdata\test\test\test.exe"
+ ]
+ },
+ {
+ "contains": [
+ "pid"
+ ],
+ "data_path": "action_result.data.*.process_id",
+ "data_type": "string",
+ "example_values": [
+ "pid:07c312fabcb8473454d0a16f118928fg:16716090292999"
+ ]
+ },
+ {
+ "contains": [
+ "pid"
+ ],
+ "data_path": "action_result.data.*.process_id_local",
+ "data_type": "string",
+ "example_values": [
+ "16716090292999"
+ ]
+ },
+ {
+ "column_name": "Start Timestamp",
+ "column_order": 4,
+ "data_path": "action_result.data.*.start_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2020-02-14T01:41:11Z"
+ ]
+ },
+ {
+ "column_name": "Start Timestamp Raw",
+ "column_order": 7,
+ "data_path": "action_result.data.*.start_timestamp_raw",
+ "data_type": "string",
+ "example_values": [
+ "132261180718697221"
+ ]
+ },
+ {
+ "column_name": "Stop Timestamp",
+ "column_order": 5,
+ "data_path": "action_result.data.*.stop_timestamp",
+ "data_type": "string"
+ },
+ {
+ "column_name": "Stop TimestampRaw",
+ "column_order": 8,
+ "data_path": "action_result.data.*.stop_timestamp_raw",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.summary",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Process details fetched successfully"
+ ]
+ }
+ ],
+ "parameters": {
+ "falcon_process_id": {
+ "contains": [
+ "falcon process id"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Process ID from previous Falcon IOC search",
+ "key": "falcon_process_id",
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "get process details"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Investigate"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_investigate.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def get_process_details(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('get_process_details() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'get_process_details' call\n results_data_1 = phantom.collect2(container=container, datapath=['list_processes_with_hash:action_result.data.*.falcon_process_id', 'list_processes_with_hash:action_result.parameter.context.artifact_id'], action_results=results)\n\n parameters = []\n \n # build parameters list for 'get_process_details' call\n for results_item_1 in results_data_1:\n if results_item_1[0]:\n parameters.append({\n 'falcon_process_id': results_item_1[0],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': results_item_1[1]},\n })\n\n phantom.act(action=\"get process detail\", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name=\"get_process_details\", parent_action=action)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "list processes with hash",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "get process details",
+ "delay": 0,
+ "description": "Fetch additional information about each process listed in the previous step.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "583356d6-13eb-45bf-9d38-5cbe82358374",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 410,
+ "line_start": 387,
+ "message": "Configuring now",
+ "name": "get process detail",
+ "notes": "Fetch additional information about each process listed in the previous step.",
+ "number": 1,
+ "order": 18,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 480,
+ "y": -80
+ },
+ "previous_function": "",
+ "previous_name": "get_process_details",
+ "required_params": {
+ "falcon_process_id": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Investigate",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 265
+ },
+ {
+ "action": "get system info",
+ "action_type": "investigate",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "id": "hunt_file_1:action_result.data.*.device_id"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "get system info",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "id": "hunt_file_1:action_result.data.*.device_id"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.service_pack_minor",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.build_number",
+ "data_type": "string",
+ "example_values": [
+ "17134"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.mac_address",
+ "data_type": "string",
+ "example_values": [
+ "00-0c-29-a0-10-27"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.uninstall_protection",
+ "data_type": "string",
+ "example_values": [
+ "ENABLED"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.applied_date",
+ "data_type": "string",
+ "example_values": [
+ "2019-02-08T02:39:21.726331953Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.settings_hash",
+ "data_type": "string",
+ "example_values": [
+ "f472bd8e"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "remote-response"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2019-02-08T02:36:05.073298048Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.remote_response.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "6c74313d6c864180bd759c3235dbd550"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.device_control.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.device_control.applied_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-05-12T17:24:23.856260169Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.device_control.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-05-12T17:24:12.52970392Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.device_control.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "device-control"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.device_control.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "cb4babb273274f79a91e8a0e84164916"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.applied_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-04-16T02:44:27.694202488Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.settings_hash",
+ "data_type": "string",
+ "example_values": [
+ "f48b1bd1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "globalconfig"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-04-16T02:42:41.826629904Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.global_config.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "49ee9efc99164562ad89640955f372ce"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.service_pack_major",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.local_ip",
+ "data_type": "string",
+ "example_values": [
+ "10.1.18.49"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.pointer_size",
+ "data_type": "string",
+ "example_values": [
+ "8"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.applied_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-07-08T03:12:30.212194872Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "firewall"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.rule_set_id",
+ "data_type": "string",
+ "example_values": [
+ "2018f9894359493cb756bfa7dd3357a6"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2020-07-08T03:07:38.48127371Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.firewall.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "2018f9894359493cb756bfa7dd3357a6"
+ ]
+ },
+ {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.parameter.id",
+ "data_type": "string",
+ "example_values": [
+ "0498d1102b23481162ff846d0633e14c"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.agent_load_flags",
+ "data_type": "string",
+ "example_values": [
+ "3"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.agent_local_time",
+ "data_type": "string",
+ "example_values": [
+ "2015-07-31T14:07:42.816Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.agent_version",
+ "data_type": "string",
+ "example_values": [
+ "2.0.0010.3005"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.bios_manufacturer",
+ "data_type": "string",
+ "example_values": [
+ "Phoenix Technologies LTD"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.bios_version",
+ "data_type": "string",
+ "example_values": [
+ "6.00"
+ ]
+ },
+ {
+ "contains": [
+ "md5"
+ ],
+ "data_path": "action_result.data.*.cid",
+ "data_type": "string",
+ "example_values": [
+ "3f40c380adc74a3187c27252c0227cff"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.config_id_base",
+ "data_type": "string",
+ "example_values": [
+ "65994752"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.config_id_build",
+ "data_type": "string",
+ "example_values": [
+ "3005"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.config_id_platform",
+ "data_type": "string",
+ "example_values": [
+ "3"
+ ]
+ },
+ {
+ "column_name": "Crowdstrike Device ID",
+ "column_order": 0,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.data.*.device_id",
+ "data_type": "string",
+ "example_values": [
+ "0498d1102b23481162ff846d0633e14c"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.prevention.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.prevention.applied_date",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.prevention.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:39:31.220730539Z"
+ ]
+ },
+ {
+ "contains": [
+ "md5"
+ ],
+ "data_path": "action_result.data.*.device_policies.prevention.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "f81459e0d85b4bc7b3ad14ad40889042"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.prevention.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "prevention"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.prevention.settings_hash",
+ "data_type": "string",
+ "example_values": [
+ "87cb8b2e"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.applied_date",
+ "data_type": "string",
+ "example_values": []
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:39:31.220769757Z"
+ ]
+ },
+ {
+ "contains": [
+ "md5"
+ ],
+ "data_path": "action_result.data.*.device_policies.sensor_update.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "62a3908297584c52bdafaa7fdf3c3bdd"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "sensor-update"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.device_policies.sensor_update.settings_hash",
+ "data_type": "string",
+ "example_values": [
+ "65994753|3|2|automatic"
+ ]
+ },
+ {
+ "contains": [
+ "ip"
+ ],
+ "data_path": "action_result.data.*.external_ip",
+ "data_type": "string",
+ "example_values": [
+ "50.18.218.205"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.first_seen",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:38:09Z"
+ ]
+ },
+ {
+ "contains": [
+ "sha256"
+ ],
+ "data_path": "action_result.data.*.group_hash",
+ "data_type": "string",
+ "example_values": [
+ "e2a8b394c0e62960747ff5d64a335162b36ba4c5a54ee6499b438b94e5269ae8"
+ ]
+ },
+ {
+ "contains": [
+ "md5"
+ ],
+ "data_path": "action_result.data.*.groups",
+ "data_type": "string",
+ "example_values": [
+ "873560309d1b4686a6cee666575e7a93"
+ ]
+ },
+ {
+ "column_name": "Hostname",
+ "column_order": 1,
+ "contains": [
+ "host name"
+ ],
+ "data_path": "action_result.data.*.hostname",
+ "data_type": "string",
+ "example_values": [
+ "TheNarrowSea",
+ "CentOS70"
+ ]
+ },
+ {
+ "column_name": "Last Seen",
+ "column_order": 2,
+ "data_path": "action_result.data.*.last_seen",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:39:34Z"
+ ]
+ },
+ {
+ "contains": [
+ "domain"
+ ],
+ "data_path": "action_result.data.*.machine_domain",
+ "data_type": "string",
+ "example_values": [
+ "VICTIMNET.local"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.major_version",
+ "data_type": "string",
+ "example_values": [
+ "6"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.meta.version",
+ "data_type": "string",
+ "example_values": [
+ "6",
+ "106635"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.minor_version",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.modified_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:40:09Z"
+ ]
+ },
+ {
+ "column_name": "OS Version",
+ "column_order": 3,
+ "data_path": "action_result.data.*.os_version",
+ "data_type": "string",
+ "example_values": [
+ "Windows Server 2008 R2",
+ "CentOS 7"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.ou",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.platform_id",
+ "data_type": "string",
+ "example_values": [
+ "0",
+ "3"
+ ]
+ },
+ {
+ "column_name": "Platform",
+ "column_order": 4,
+ "data_path": "action_result.data.*.platform_name",
+ "data_type": "string",
+ "example_values": [
+ "Windows"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.policies.*.applied",
+ "data_type": "boolean",
+ "example_values": [
+ true
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.policies.*.applied_date",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.policies.*.assigned_date",
+ "data_type": "string",
+ "example_values": [
+ "2018-03-10T15:39:31.220730539Z"
+ ]
+ },
+ {
+ "contains": [
+ "md5"
+ ],
+ "data_path": "action_result.data.*.policies.*.policy_id",
+ "data_type": "string",
+ "example_values": [
+ "f81459e0d85b4bc7b3ad14ad40889042"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.policies.*.policy_type",
+ "data_type": "string",
+ "example_values": [
+ "prevention"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.policies.*.settings_hash",
+ "data_type": "string",
+ "example_values": [
+ "87cb8b2e"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.product_type",
+ "data_type": "string",
+ "example_values": [
+ "3"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.product_type_desc",
+ "data_type": "string",
+ "example_values": [
+ "Server"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.provision_status",
+ "data_type": "string",
+ "example_values": [
+ "Provisioned"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.release_group",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.site_name",
+ "data_type": "string",
+ "example_values": [
+ "Default-First-Site-Name"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.slow_changing_modified_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2018-04-23T22:52:27Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.status",
+ "data_type": "string",
+ "example_values": [
+ "normal"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.system_manufacturer",
+ "data_type": "string",
+ "example_values": [
+ "VMware, Inc."
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.system_product_name",
+ "data_type": "string",
+ "example_values": [
+ "VMware Virtual Platform"
+ ]
+ },
+ {
+ "contains": [
+ "host name"
+ ],
+ "data_path": "action_result.summary.hostname",
+ "data_type": "string",
+ "example_values": [
+ "TheNarrowSea"
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Device details fetched successfully"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "id": {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Device ID from previous Crowdstrike IOC search",
+ "key": "id",
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "get system info"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Investigate"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_investigate.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def get_system_info_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('get_system_info_1() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'get_system_info_1' call\n results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_1:action_result.data.*.device_id', 'hunt_file_1:action_result.parameter.context.artifact_id'], action_results=results)\n\n parameters = []\n \n # build parameters list for 'get_system_info_1' call\n for results_item_1 in results_data_1:\n if results_item_1[0]:\n parameters.append({\n 'id': results_item_1[0],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': results_item_1[1]},\n })\n\n phantom.act(action=\"get system info\", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name=\"get_system_info_1\", parent_action=action)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "hunt file",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "delay": 0,
+ "description": "Fetch additional information about each machine listed in the previous step.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "005c6087-3fe9-4e37-89f7-f170dd34412b",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 293,
+ "line_start": 270,
+ "message": "Configuring now",
+ "name": "get system info",
+ "notes": "Fetch additional information about each machine listed in the previous step.",
+ "number": 1,
+ "order": 14,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 480,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "get_system_info_1",
+ "required_params": {
+ "id": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Investigate",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 267
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format detect description"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_detect_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_detect_description() called')\n \n template = \"\"\"This indicator was created by Phantom in the playbook crowdstrike_malware_triage to detect and block process executions based on the file hash first seen in {0} and processed in Phantom as {1}\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink\",\n \"container:url\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_detect_description\")\n\n create_detect_indicator(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format detect description",
+ "description": "Format a description to provide when creating an Indicator with a policy of \"detect\".",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "0f9d0bb7-4931-4e17-b50f-03ff0551c70d",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 615,
+ "line_start": 598,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Format a description to provide when creating an Indicator with a policy of \"detect\".",
+ "number": 5,
+ "order": 25,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink"
+ },
+ {
+ "position": 1,
+ "type": "",
+ "value": "container:url"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1280,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "format_detect_description",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "This indicator was created by Phantom in the playbook crowdstrike_malware_triage to detect and block process executions based on the file hash first seen in {0} and processed in Phantom as {1}",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 276
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "comment no indicator"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def comment_no_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('comment_no_indicator() called')\n\n phantom.comment(container=container, comment=\"The analyst decided not to create a custom indicator for the file hash.\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "The analyst decided not to create a custom indicator for the file hash.",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "comment no indicator",
+ "description": "Explain in a comment that no Indicator will be created.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "d6ae9b4a-a027-4ce4-b4ea-15a67a35668d",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 595,
+ "line_start": 588,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "Explain in a comment that no Indicator will be created.",
+ "number": 9,
+ "order": 24,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1280,
+ "y": -80
+ },
+ "previous_function": "",
+ "previous_name": "comment_no_indicator",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 281
+ },
+ {
+ "action": "upload indicator",
+ "action_type": "contain",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "description": "",
+ "expiration": "",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "policy": "detect",
+ "share_level": "red",
+ "source": ""
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "upload indicator",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "description": "",
+ "expiration": "",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "policy": "detect",
+ "share_level": "red",
+ "source": ""
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.description",
+ "data_type": "string",
+ "example_values": [
+ "test description"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.expiration",
+ "data_type": "numeric",
+ "example_values": [
+ 10
+ ]
+ },
+ {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain",
+ "ip"
+ ],
+ "data_path": "action_result.parameter.ioc",
+ "data_type": "string",
+ "example_values": [
+ "test"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.policy",
+ "data_type": "string",
+ "example_values": [
+ "detect"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.share_level",
+ "data_type": "string",
+ "example_values": [
+ "red"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.source",
+ "data_type": "string",
+ "example_values": [
+ "test source"
+ ]
+ },
+ {
+ "data_path": "action_result.data",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.summary",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "IOC Uploaded to create alert"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "description": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator description",
+ "key": "description",
+ "order": 5,
+ "required": false
+ },
+ "expiration": {
+ "data_type": "numeric",
+ "default": null,
+ "description": "Alert lifetime in days (Valid for domains and ips only)",
+ "key": "expiration",
+ "order": 3,
+ "required": false
+ },
+ "ioc": {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain",
+ "ip"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Input domain, ip, or hash ioc",
+ "key": "ioc",
+ "order": 0,
+ "primary": true,
+ "required": true
+ },
+ "policy": {
+ "data_type": "string",
+ "default": null,
+ "description": "Enforcement Policy (in case of detection)",
+ "key": "policy",
+ "order": 1,
+ "required": true,
+ "value_list": [
+ "detect",
+ "none"
+ ]
+ },
+ "share_level": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator share level",
+ "key": "share_level",
+ "order": 2,
+ "required": false,
+ "value_list": [
+ "red"
+ ]
+ },
+ "source": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator Originating source",
+ "key": "source",
+ "order": 4,
+ "required": false
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "create detect indicator"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Contain"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_contain.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def create_detect_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('create_detect_indicator() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'create_detect_indicator' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'create_detect_indicator' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n if filtered_artifacts_item_1[0]:\n parameters.append({\n 'ioc': filtered_artifacts_item_1[0],\n 'policy': \"detect\",\n 'source': \"\",\n 'expiration': \"\",\n 'description': \"\",\n 'share_level': \"red\",\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"upload indicator\", parameters=parameters, assets=['crowdstrike_oauth'], name=\"create_detect_indicator\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "create detect indicator",
+ "delay": 0,
+ "description": "Create an Indicator to detect and block this file hash.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "a8b369f1-2a55-4e49-85da-a66c35534861",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 646,
+ "line_start": 618,
+ "message": "Configuring now",
+ "name": "upload indicator",
+ "notes": "Create an Indicator to detect and block this file hash.",
+ "number": 2,
+ "order": 26,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1520,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "create_detect_indicator",
+ "required_params": {
+ "ioc": true,
+ "policy": true
+ },
+ "reviewer": "",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Contain",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 282
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format repeat note"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_repeat_note() called')\n \n template = \"\"\"CrowdStrike detected a file on an endpoint which matched a previously detected file hash: \n\n| Field | Value |\n|---|---|\n| Host | {0} |\n| Command Line | {1} |\n| SHA 256 | {2} |\n| File Path | {3}\\\\\\\\{4} |\n| CrowdStrike Detection Link | {5} | \n\n---\n\nThis event will have the severity escalated to high, and should be investigated further.\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_repeat_note\")\n\n add_repeat_note(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format repeat note",
+ "description": "Format a note to summarize all known information about the event.",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "a03011e0-61d6-4949-b0c2-03e18b844dba",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 172,
+ "line_start": 139,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Format a note to summarize all known information about the event.",
+ "number": 2,
+ "order": 8,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName"
+ },
+ {
+ "position": 1,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine"
+ },
+ {
+ "position": 2,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ {
+ "position": 3,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath"
+ },
+ {
+ "position": 4,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName"
+ },
+ {
+ "position": 5,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 320,
+ "y": 620
+ },
+ "previous_function": "",
+ "previous_name": "format_repeat_note",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "CrowdStrike detected a file on an endpoint which matched a previously detected file hash: \n\n| Field | Value |\n|---|---|\n| Host | {0} |\n| Command Line | {1} |\n| SHA 256 | {2} |\n| File Path | {3}\\\\{4} |\n| CrowdStrike Detection Link | {5} | \n\n---\n\nThis event will have the severity escalated to high, and should be investigated further.",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 284
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "detection policy none"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def detection_policy_none(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('detection_policy_none() called')\n\n phantom.comment(container=container, comment=\"The file hash indicator has a detection policy of none, so previous investigations have found that the file is not harmful. This playbook will take no further action and the event will be closed.\")\n close_event(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "The file hash indicator has a detection policy of none, so previous investigations have found that the file is not harmful. This playbook will take no further action and the event will be closed.",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "detection policy none",
+ "description": "Add a comment to explain why the event is being closed.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "ea7fbdda-bb34-4d57-9973-03db50614381",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 267,
+ "line_start": 259,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "Add a comment to explain why the event is being closed.",
+ "number": 7,
+ "order": 13,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 320,
+ "y": 340
+ },
+ "previous_function": "",
+ "previous_name": "detection_policy_none",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 287
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "837789d7-0479-4e6b-b678-3d036385f0ed",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "278bf5f1-38a2-4a6c-924e-4f37b28fa60e",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "f41cc6f3-3db1-4909-b141-04c01050331f",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 289
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "7f5c6b2b-9839-4db7-acf7-6999c8469f60",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "f41cc6f3-3db1-4909-b141-04c01050331f",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "98e3644d-2438-4cf7-8aaf-928647553f7b",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 294
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "3ca96a50-53a8-4881-a653-6f4fe7ebc6d3",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "98e3644d-2438-4cf7-8aaf-928647553f7b",
+ "port": "out-1",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(1) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "4b535b2e-3be9-4a09-be52-dbbe8ada4228",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 301
+ },
+ {
+ "attrs": {
+ ".connection": {
+ "stroke": "#818D99",
+ "stroke-width": 2
+ },
+ ".marker-target": {
+ "d": "M 10 0 L 0 5 L 10 10 z",
+ "fill": "#818D99",
+ "stroke": "#818D99"
+ }
+ },
+ "connector": {
+ "args": {
+ "radius": 5
+ },
+ "name": "rounded"
+ },
+ "endDirections": [
+ "left"
+ ],
+ "id": "0be99cce-991a-48a7-aa9e-ff9dfbd8ce9e",
+ "router": {
+ "name": "metro"
+ },
+ "source": {
+ "id": "98e3644d-2438-4cf7-8aaf-928647553f7b",
+ "port": "out-2",
+ "selector": "> g:nth-child(1) > g:nth-child(2) > g:nth-child(2) > circle:nth-child(1)"
+ },
+ "startDirections": [
+ "right"
+ ],
+ "target": {
+ "id": "dc3a4fa8-879c-49f9-8af9-3c050b7f1aba",
+ "selector": ".port-body[type=\"input\"]"
+ },
+ "type": "link",
+ "z": 307
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "comment no quarantine 1"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def comment_no_quarantine_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('comment_no_quarantine_1() called')\n\n phantom.comment(container=container, comment=\"The analyst decided not to quarantine the endpoint.\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "The analyst decided not to quarantine the endpoint.",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "comment no quarantine 1",
+ "description": "Do not quarantine the endpoint because the analyst responded No in the prompt.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "e67e9ce0-f06d-4687-b3ed-d5d24860ed82",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 656,
+ "line_start": 649,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "Do not quarantine the endpoint because the analyst responded No in the prompt.",
+ "number": 10,
+ "order": 27,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1280,
+ "y": 340
+ },
+ "previous_function": "",
+ "previous_name": "comment_no_quarantine_1",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 311
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "comment no quarantine 2"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def comment_no_quarantine_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('comment_no_quarantine_2() called')\n\n phantom.comment(container=container, comment=\"The analyst decided not to quarantine the endpoint.\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "The analyst decided not to quarantine the endpoint.",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "crowdstrike known file quarantine",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "comment no quarantine 2",
+ "description": "Do not quarantine the endpoint because the analyst responded No in the prompt.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "dc3a4fa8-879c-49f9-8af9-3c050b7f1aba",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 779,
+ "line_start": 772,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "Do not quarantine the endpoint because the analyst responded No in the prompt.",
+ "number": 11,
+ "order": 32,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1080,
+ "y": 760
+ },
+ "previous_function": "",
+ "previous_name": "comment_no_quarantine_2",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 312
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add note",
+ "attrs": {
+ ".api": {
+ "text": "add repeat note"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def add_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('add_repeat_note() called')\n\n formatted_data_1 = phantom.get_format_data(name='format_repeat_note')\n\n note_title = \"Known Malicious File\"\n note_content = formatted_data_1\n note_format = \"markdown\"\n phantom.add_note(container=container, note_type=\"general\", title=note_title, content=note_content, note_format=note_format)\n crowdstrike_known_file_quarantine(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addNoteContent": "format_repeat_note:formatted_data",
+ "addNoteNoteFormat": "markdown",
+ "addNoteTitle": "Known Malicious File",
+ "key": "add-note"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "add repeat note",
+ "description": "Add a note to summarize the event information.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "278bf5f1-38a2-4a6c-924e-4f37b28fa60e",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 188,
+ "line_start": 175,
+ "message": "Configuring now",
+ "name": "add note",
+ "notes": "Add a note to summarize the event information.",
+ "number": 4,
+ "order": 9,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 560,
+ "y": 620
+ },
+ "previous_function": "",
+ "previous_name": "add_repeat_note",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 314
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 6
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def quarantine_decision_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('quarantine_decision_1() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"crowdstrike_new_file_detection:action_result.summary.responses.1\", \"==\", \"Yes\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n quarantine_device_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 2\n comment_no_quarantine_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "quarantine decision 1",
+ "description": "Check the quarantine device prompt response.",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "d5f48d34-ef50-4204-956c-7023b9846414",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 533,
+ "line_start": 512,
+ "name": "decision",
+ "notes": "Check the quarantine device prompt response.",
+ "number": 6,
+ "order": 21,
+ "outPorts": [
+ "out-1",
+ "out-2"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "crowdstrike_new_file_detection:action_result.summary.responses.1",
+ "value": "Yes"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1140,
+ "y": 200
+ },
+ "previous_function": "",
+ "previous_name": "quarantine_decision_1",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 318
+ },
+ {
+ "action": "quarantine device",
+ "action_type": "contain",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "device_id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "hostname": ""
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "quarantine device",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "device_id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "hostname": ""
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.parameter.device_id",
+ "data_type": "string",
+ "example_values": [
+ "c70bbe8334aa47bd61046603eb27b15a"
+ ]
+ },
+ {
+ "contains": [
+ "host name"
+ ],
+ "data_path": "action_result.parameter.hostname",
+ "data_type": "string",
+ "example_values": [
+ "CB-TEST-01"
+ ]
+ },
+ {
+ "column_name": "Device ID",
+ "column_order": 0,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.data.*.id",
+ "data_type": "string",
+ "example_values": [
+ "c70bbe8334aa47bd61046603eb27b15a"
+ ]
+ },
+ {
+ "column_name": "Path",
+ "column_order": 1,
+ "data_path": "action_result.data.*.path",
+ "data_type": "string",
+ "example_values": [
+ "/devices/entities/devices/v1"
+ ]
+ },
+ {
+ "data_path": "action_result.summary.total_quarantined_device",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Device quarantined successfully"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "device_id": {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Comma-separated list of device IDs",
+ "key": "device_id",
+ "order": 0,
+ "primary": true,
+ "required": false
+ },
+ "hostname": {
+ "contains": [
+ "host name"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Comma-separated list of hostnames",
+ "key": "hostname",
+ "order": 1,
+ "primary": true,
+ "required": false
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "quarantine device 1"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Contain"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_contain.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def quarantine_device_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('quarantine_device_1() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'quarantine_device_1' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'quarantine_device_1' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n parameters.append({\n 'hostname': \"\",\n 'device_id': filtered_artifacts_item_1[0],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"quarantine device\", parameters=parameters, assets=['crowdstrike_oauth'], name=\"quarantine_device_1\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "quarantine device 1",
+ "delay": 0,
+ "description": "Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "8f1bc7f0-5b9e-4e9c-9159-ee6a2b73c0e5",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 682,
+ "line_start": 659,
+ "message": "Configuring now",
+ "name": "quarantine device",
+ "notes": "Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.",
+ "number": 1,
+ "order": 28,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1280,
+ "y": 200
+ },
+ "previous_function": "",
+ "previous_name": "quarantine_device_1",
+ "required_params": {},
+ "reviewer": "",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Contain",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 321
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 7
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def quarantine_decision_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('quarantine_decision_2() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"crowdstrike_known_file_quarantine:action_result.summary.responses.0\", \"==\", \"Yes\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n quarantine_device_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 2\n comment_no_quarantine_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "crowdstrike known file quarantine",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "quarantine decision 2",
+ "description": "Check if the analyst responded Yes or No to the quarantine.",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "98e3644d-2438-4cf7-8aaf-928647553f7b",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 743,
+ "line_start": 722,
+ "name": "decision",
+ "notes": "Check if the analyst responded Yes or No to the quarantine.",
+ "number": 7,
+ "order": 30,
+ "outPorts": [
+ "out-1",
+ "out-2"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "crowdstrike_known_file_quarantine:action_result.summary.responses.0",
+ "value": "Yes"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 940,
+ "y": 620
+ },
+ "previous_function": "",
+ "previous_name": "quarantine_decision_2",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 322
+ },
+ {
+ "action": "quarantine device",
+ "action_type": "contain",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "device_id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "hostname": ""
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "quarantine device",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "device_id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "hostname": ""
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.parameter.device_id",
+ "data_type": "string",
+ "example_values": [
+ "c70bbe8334aa47bd61046603eb27b15a"
+ ]
+ },
+ {
+ "contains": [
+ "host name"
+ ],
+ "data_path": "action_result.parameter.hostname",
+ "data_type": "string",
+ "example_values": [
+ "CB-TEST-01"
+ ]
+ },
+ {
+ "column_name": "Device ID",
+ "column_order": 0,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.data.*.id",
+ "data_type": "string",
+ "example_values": [
+ "c70bbe8334aa47bd61046603eb27b15a"
+ ]
+ },
+ {
+ "column_name": "Path",
+ "column_order": 1,
+ "data_path": "action_result.data.*.path",
+ "data_type": "string",
+ "example_values": [
+ "/devices/entities/devices/v1"
+ ]
+ },
+ {
+ "data_path": "action_result.summary.total_quarantined_device",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Device quarantined successfully"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "device_id": {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Comma-separated list of device IDs",
+ "key": "device_id",
+ "order": 0,
+ "primary": true,
+ "required": false
+ },
+ "hostname": {
+ "contains": [
+ "host name"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Comma-separated list of hostnames",
+ "key": "hostname",
+ "order": 1,
+ "primary": true,
+ "required": false
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "quarantine device 2"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Contain"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_contain.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def quarantine_device_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('quarantine_device_2() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'quarantine_device_2' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'quarantine_device_2' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n parameters.append({\n 'hostname': \"\",\n 'device_id': filtered_artifacts_item_1[0],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"quarantine device\", parameters=parameters, assets=['crowdstrike_oauth'], name=\"quarantine_device_2\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "crowdstrike known file quarantine",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "delay": 0,
+ "description": "Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "4b535b2e-3be9-4a09-be52-dbbe8ada4228",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 769,
+ "line_start": 746,
+ "message": "Configuring now",
+ "name": "quarantine device",
+ "notes": "Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.",
+ "number": 2,
+ "order": 31,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1080,
+ "y": 620
+ },
+ "previous_function": "",
+ "previous_name": "quarantine_device_2",
+ "required_params": {},
+ "reviewer": "",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Contain",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 323
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format ignore description"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_ignore_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_ignore_description() called')\n \n template = \"\"\"This indicator was created by Phantom in the playbook crowdstrike_malware_triage to ignore CrowdStrike detections based on the file hash first seen in {0} and processed in Phantom as {1}\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink\",\n \"container:url\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_ignore_description\")\n\n create_ignore_indicator(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format ignore description",
+ "description": "Format a description to provide when creating an Indicator with a policy of \"none\".",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "da97de34-c6e5-47a8-bfcb-0a7ee4cca2a1",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 585,
+ "line_start": 568,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Format a description to provide when creating an Indicator with a policy of \"none\".",
+ "number": 4,
+ "order": 23,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink"
+ },
+ {
+ "position": 1,
+ "type": "",
+ "value": "container:url"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1280,
+ "y": -220
+ },
+ "previous_function": "",
+ "previous_name": "format_ignore_description",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "This indicator was created by Phantom in the playbook crowdstrike_malware_triage to ignore CrowdStrike detections based on the file hash first seen in {0} and processed in Phantom as {1}",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 324
+ },
+ {
+ "action": "upload indicator",
+ "action_type": "contain",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "description": "format_ignore_description:formatted_data",
+ "expiration": "",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "policy": "none",
+ "share_level": "red",
+ "source": "Phantom Playbook crowdstrike_malware_triage"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "upload indicator",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "description": "format_ignore_description:formatted_data",
+ "expiration": "",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "policy": "none",
+ "share_level": "red",
+ "source": "Phantom Playbook crowdstrike_malware_triage"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.description",
+ "data_type": "string",
+ "example_values": [
+ "test description"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.expiration",
+ "data_type": "numeric",
+ "example_values": [
+ 10
+ ]
+ },
+ {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain",
+ "ip"
+ ],
+ "data_path": "action_result.parameter.ioc",
+ "data_type": "string",
+ "example_values": [
+ "test"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.policy",
+ "data_type": "string",
+ "example_values": [
+ "detect"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.share_level",
+ "data_type": "string",
+ "example_values": [
+ "red"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.source",
+ "data_type": "string",
+ "example_values": [
+ "test source"
+ ]
+ },
+ {
+ "data_path": "action_result.data",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.summary",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "IOC Uploaded to create alert"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "description": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator description",
+ "key": "description",
+ "order": 5,
+ "required": false
+ },
+ "expiration": {
+ "data_type": "numeric",
+ "default": null,
+ "description": "Alert lifetime in days (Valid for domains and ips only)",
+ "key": "expiration",
+ "order": 3,
+ "required": false
+ },
+ "ioc": {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain",
+ "ip"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Input domain, ip, or hash ioc",
+ "key": "ioc",
+ "order": 0,
+ "primary": true,
+ "required": true
+ },
+ "policy": {
+ "data_type": "string",
+ "default": null,
+ "description": "Enforcement Policy (in case of detection)",
+ "key": "policy",
+ "order": 1,
+ "required": true,
+ "value_list": [
+ "detect",
+ "none"
+ ]
+ },
+ "share_level": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator share level",
+ "key": "share_level",
+ "order": 2,
+ "required": false,
+ "value_list": [
+ "red"
+ ]
+ },
+ "source": {
+ "data_type": "string",
+ "default": null,
+ "description": "Indicator Originating source",
+ "key": "source",
+ "order": 4,
+ "required": false
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "create ignore indicator"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Contain"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_contain.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def create_ignore_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('create_ignore_indicator() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'create_ignore_indicator' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n formatted_data_1 = phantom.get_format_data(name='format_ignore_description')\n\n parameters = []\n \n # build parameters list for 'create_ignore_indicator' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n if filtered_artifacts_item_1[0]:\n parameters.append({\n 'ioc': filtered_artifacts_item_1[0],\n 'policy': \"none\",\n 'source': \"Phantom Playbook crowdstrike_malware_triage\",\n 'expiration': \"\",\n 'description': formatted_data_1,\n 'share_level': \"red\",\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"upload indicator\", parameters=parameters, assets=['crowdstrike_oauth'], name=\"create_ignore_indicator\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "create ignore indicator",
+ "delay": 0,
+ "description": "Create an Indicator in CrowdStrike with a policy of \"none\" to ignore detections based on this file hash in the future.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "d04015bf-190d-415d-8fab-06f8f1276751",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 565,
+ "line_start": 536,
+ "message": "Configuring now",
+ "name": "upload indicator",
+ "notes": "Create an Indicator in CrowdStrike with a policy of \"none\" to ignore detections based on this file hash in the future.",
+ "number": 1,
+ "order": 22,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1520,
+ "y": -220
+ },
+ "previous_function": "",
+ "previous_name": "create_ignore_indicator",
+ "required_params": {
+ "ioc": true,
+ "policy": true
+ },
+ "reviewer": "",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Contain",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 325
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "api": "add comment",
+ "attrs": {
+ ".api": {
+ "text": "comment unexpected po..."
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "API"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def comment_unexpected_policy(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('comment_unexpected_policy() called')\n\n phantom.comment(container=container, comment=\"The playbook received an unexpected indicator policy and needs to be extended to handle this situation.\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "color": "",
+ "configured": [
+ {
+ "addCommentComment": "The playbook received an unexpected indicator policy and needs to be extended to handle this situation.",
+ "key": "add-comment"
+ }
+ ],
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "comment unexpected policy",
+ "description": "End processing because this playbook only expects \"none\" or \"detect\" as the Indicator policy.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "b827b91f-97e9-4a99-983a-bdb0b4eb98ce",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 256,
+ "line_start": 249,
+ "message": "Configuring now",
+ "name": "add comment",
+ "notes": "End processing because this playbook only expects \"none\" or \"detect\" as the Indicator policy.",
+ "number": 5,
+ "order": 12,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 320,
+ "y": 200
+ },
+ "previous_function": "",
+ "previous_name": "comment_unexpected_policy",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "api",
+ "status": "",
+ "title": "API",
+ "type": "coa.API",
+ "warn": false,
+ "z": 326
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".format": {
+ "text": "format prompt"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out-1": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out-1>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "format"
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('format_prompt() called')\n \n template = \"\"\"CrowdStrike detected the following suspicious activity on an endpoint:\n\n| Field | Value |\n|---|---|\n| Host | {0} |\n| Command Line | {1} |\n| SHA 256 | {2} |\n| File Path | {3}\\\\\\\\{4}\n| CrowdStrike Detection Link | {5} |\n| Details of processes associated with the file hash | |\n| Count of machines that have the file on disk | {6} |\n| System information of machines that have the file on disk | |\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName\",\n \"filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink\",\n \"hunt_file_1:action_result.summary.device_count\",\n ]\n\n phantom.format(container=container, template=template, parameters=parameters, name=\"format_prompt\")\n\n crowdstrike_new_file_detection(container=container)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "get system info, get process details",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "format prompt",
+ "description": "Summarize all the gathered information to help the analyst decide a response in the prompt.",
+ "format": "format",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "09fbbded-a2ad-433f-968d-40f3ae3c189e",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "def join_format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):\n phantom.debug('join_format_prompt() called')\n \n # if the joined function has already been called, do nothing\n if phantom.get_run_data(key='join_format_prompt_called'):\n return\n\n # check if all connected incoming playbooks, actions, or custom functions are done i.e. have succeeded or failed\n if phantom.completed(action_names=['get_process_details']):\n \n # save the state that the joined function has now been called\n phantom.save_run_data(key='join_format_prompt_called', value='format_prompt')\n \n # call connected block \"format_prompt\"\n format_prompt(container=container, handle=handle)\n \n return",
+ "join_optional": [
+ "get_system_info_1"
+ ],
+ "join_start": 329,
+ "line_end": 347,
+ "line_start": 296,
+ "message": "Configuring now",
+ "name": "format",
+ "notes": "Summarize all the gathered information to help the analyst decide a response in the prompt.",
+ "number": 3,
+ "order": 15,
+ "outPorts": [
+ "out-1"
+ ],
+ "parameters": [
+ {
+ "position": 1,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName"
+ },
+ {
+ "position": 1,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine"
+ },
+ {
+ "position": 2,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ {
+ "position": 3,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath"
+ },
+ {
+ "position": 4,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName"
+ },
+ {
+ "position": 5,
+ "type": "",
+ "value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink"
+ },
+ {
+ "position": 6,
+ "type": "",
+ "value": "hunt_file_1:action_result.summary.device_count"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 740,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "format_prompt",
+ "show_number": true,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "format",
+ "status": "",
+ "template": "CrowdStrike detected the following suspicious activity on an endpoint:\n\n| Field | Value |\n|---|---|\n| Host | {0} |\n| Command Line | {1} |\n| SHA 256 | {2} |\n| File Path | {3}\\\\{4}\n| CrowdStrike Detection Link | {5} |\n| Details of processes associated with the file hash | |\n| Count of machines that have the file on disk | {6} |\n| System information of machines that have the file on disk | |",
+ "title": "format",
+ "type": "coa.Format",
+ "warn": false,
+ "z": 328
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 5
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-2": {
+ "port": {
+ "id": "out-3",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": -2
+ },
+ ".outPorts>.port-2>.port-body": {
+ "port": {
+ "id": "out-3",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def indicator_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('indicator_decision() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"No, do not create an Indicator in CrowdStrike at this time.\", \"==\", \"crowdstrike_new_file_detection:action_result.summary.responses.0\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n comment_no_indicator(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # check for 'elif' condition 2\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)\", \"==\", \"crowdstrike_new_file_detection:action_result.summary.responses.0\"],\n ])\n\n # call connected blocks if condition 2 matched\n if matched:\n format_detect_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # check for 'elif' condition 3\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"Yes, create a CrowdStrike Indicator to ignore this file hash going forward (False Positive)\", \"==\", \"crowdstrike_new_file_detection:action_result.summary.responses.0\"],\n ])\n\n # call connected blocks if condition 3 matched\n if matched:\n format_ignore_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "crowdstrike new file detection",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "indicator decision",
+ "description": "Parse the prompt response to determine how to handle the indicator.",
+ "hasElse": false,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "f39ff0a8-97cc-494b-b692-346dd89eab7a",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 509,
+ "line_start": 465,
+ "name": "decision",
+ "notes": "Parse the prompt response to determine how to handle the indicator.",
+ "number": 5,
+ "order": 20,
+ "outPorts": [
+ "out-1",
+ "out-2",
+ "out-3"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "No, do not create an Indicator in CrowdStrike at this time.",
+ "value": "crowdstrike_new_file_detection:action_result.summary.responses.0"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)",
+ "value": "crowdstrike_new_file_detection:action_result.summary.responses.0"
+ }
+ ],
+ "display": "Else If",
+ "logic": "and",
+ "type": "elif"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "Yes, create a CrowdStrike Indicator to ignore this file hash going forward (False Positive)",
+ "value": "crowdstrike_new_file_detection:action_result.summary.responses.0"
+ }
+ ],
+ "display": "Else If",
+ "logic": "and",
+ "type": "elif"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 1140,
+ "y": -80
+ },
+ "previous_function": "",
+ "previous_name": "indicator_decision",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 330
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#637282",
+ "transform": "rotate(45 30 70)"
+ },
+ ".inPorts>.port-0>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 3
+ },
+ ".outPorts>.port-0": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ },
+ "ref-x": 83,
+ "ref-y": 40
+ },
+ ".outPorts>.port-0>.port-body": {
+ "port": {
+ "id": "out-1",
+ "type": "out"
+ }
+ },
+ ".outPorts>.port-1": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ },
+ "ref-x": 41,
+ "ref-y": 82
+ },
+ ".outPorts>.port-1>.port-body": {
+ "port": {
+ "id": "out-2",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def if_indicator_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('if_indicator_exists() called')\n\n # check for 'if' condition 1\n matched = phantom.decision(\n container=container,\n action_results=results,\n conditions=[\n [\"Resource Not Found\", \"in\", \"get_indicator_2:action_result.message\"],\n ])\n\n # call connected blocks if condition 1 matched\n if matched:\n hunt_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n list_processes_with_hash(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n return\n\n # call connected blocks for 'else' condition 2\n indicator_policy_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": false,
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "if indicator exists",
+ "description": "Determine which response to take based on whether an Indicator exists in CrowdStrike for the SHA256 file hash.",
+ "hasElse": true,
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "0484d948-e831-4efc-b3a4-5f7f6ffb9441",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 126,
+ "line_start": 104,
+ "name": "decision",
+ "notes": "Determine which response to take based on whether an Indicator exists in CrowdStrike for the SHA256 file hash.",
+ "number": 3,
+ "order": 6,
+ "outPorts": [
+ "out-1",
+ "out-2"
+ ],
+ "outputs": [
+ {
+ "conditions": [
+ {
+ "comparison": "in",
+ "data_type": "",
+ "param": "Resource Not Found",
+ "value": "get_indicator_2:action_result.message"
+ }
+ ],
+ "display": "If",
+ "logic": "and",
+ "type": "if"
+ },
+ {
+ "conditions": [
+ {
+ "comparison": "==",
+ "data_type": "",
+ "param": "",
+ "value": ""
+ }
+ ],
+ "display": "Else",
+ "logic": "and",
+ "type": "else"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 100,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "if_indicator_exists",
+ "show_number": true,
+ "size": {
+ "height": 82,
+ "width": 82
+ },
+ "state": "decision",
+ "status": "",
+ "type": "coa.Decision",
+ "warn": "",
+ "z": 332
+ },
+ {
+ "action": "hunt file",
+ "action_type": "investigate",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "count_only": "False",
+ "hash": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "hunt file",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "count_only": "False",
+ "hash": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.parameter.count_only",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5"
+ ],
+ "data_path": "action_result.parameter.hash",
+ "data_type": "string",
+ "example_values": [
+ "eeb27d04c5fb25f7459407c0e5394621f12100e301b22d04a6b8f78e2adbf44t"
+ ]
+ },
+ {
+ "column_name": "Crowdstrike Device ID",
+ "column_order": 0,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.data.*.device_id",
+ "data_type": "string",
+ "example_values": [
+ "07c312fabcb8473454d0a16f118928fg"
+ ]
+ },
+ {
+ "data_path": "action_result.summary.device_count",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Device count: 1"
+ ]
+ }
+ ],
+ "parameters": {
+ "count_only": {
+ "data_type": "boolean",
+ "default": false,
+ "description": "Get endpoint count only",
+ "key": "count_only",
+ "required": false
+ },
+ "hash": {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "File hash to search",
+ "key": "hash",
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "hunt file"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Investigate"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_investigate.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def hunt_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('hunt_file_1() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'hunt_file_1' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'hunt_file_1' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n if filtered_artifacts_item_1[0]:\n parameters.append({\n 'hash': filtered_artifacts_item_1[0],\n 'count_only': False,\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"hunt file\", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_system_info_1, name=\"hunt_file_1\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "delay": 0,
+ "description": "List all machines where the file hash has been seen.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "6d11a3cf-6f79-4280-a83c-ff518a10f734",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 43,
+ "line_start": 19,
+ "message": "Configuring now",
+ "name": "hunt file",
+ "notes": "List all machines where the file hash has been seen.",
+ "number": 1,
+ "order": 2,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 240,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "hunt_file_1",
+ "required_params": {
+ "hash": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Investigate",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 333
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "approver": "admin",
+ "approver_display": "admin",
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 1
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def crowdstrike_new_file_detection(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('crowdstrike_new_file_detection() called')\n \n # set user and message variables for phantom.prompt call\n user = \"admin\"\n message = \"\"\"{0}\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"format_prompt:formatted_data\",\n ]\n\n #responses:\n response_types = [\n {\n \"prompt\": \"Should Phantom create an Indicator in CrowdStrike to track this file hash from now on?\",\n \"options\": {\n \"type\": \"list\",\n \"choices\": [\n \"No, do not create an Indicator in CrowdStrike at this time.\",\n \"Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)\",\n \"Yes, create a CrowdStrike Indicator to ignore this file hash from now on. (False Positive)\",\n ]\n },\n },\n {\n \"prompt\": \"Should Phantom quarantine the endpoint?\",\n \"options\": {\n \"type\": \"list\",\n \"choices\": [\n \"Yes\",\n \"No\",\n ]\n },\n },\n ]\n\n phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name=\"crowdstrike_new_file_detection\", parameters=parameters, response_types=response_types, callback=crowdstrike_new_file_detection_callback)\n\n return",
+ "callback_code": "def crowdstrike_new_file_detection_callback(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):\n phantom.debug('crowdstrike_new_file_detection_callback() called')\n \n indicator_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n quarantine_decision_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)\n\n return",
+ "callback_start": 454,
+ "callsback": true,
+ "connected_to_start": true,
+ "connection_name": "get system info, get process details",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "crowdstrike new file detection",
+ "description": "Prompt the user to determine whether or not to create an Indicator for the file hash and whether or not to quarantine the endpoint.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "e6b6bdfa-6ec1-40a6-96fd-1f9b535b2087",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 462,
+ "line_start": 413,
+ "message": "{0}",
+ "name": "prompt",
+ "notes": "Prompt the user to determine whether or not to create an Indicator for the file hash and whether or not to quarantine the endpoint.",
+ "number": 1,
+ "order": 19,
+ "outPorts": [
+ "out"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "format_prompt:formatted_data"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 980,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "crowdstrike_new_file_detection",
+ "respond_in": "30",
+ "response_key": "Message",
+ "response_options": [],
+ "response_type": "list",
+ "responses": [
+ {
+ "response_key": "Custom List",
+ "response_options": [
+ "No, do not create an Indicator in CrowdStrike at this time.",
+ "Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)",
+ "Yes, create a CrowdStrike Indicator to ignore this file hash from now on. (False Positive)"
+ ],
+ "response_prompt": "Should Phantom create an Indicator in CrowdStrike to track this file hash from now on?",
+ "response_type": "list",
+ "responses_prompt": "Should Phantom create an Indicator in CrowdStrike to track this file hash from now on??"
+ },
+ {
+ "response_key": "Yes/No",
+ "response_options": [
+ "Yes",
+ "No"
+ ],
+ "response_prompt": "Should Phantom quarantine the endpoint?",
+ "response_type": "list"
+ }
+ ],
+ "show_number": true,
+ "size": {
+ "height": 80,
+ "width": 80
+ },
+ "state": "prompt",
+ "status": "",
+ "type": "coa.Prompt",
+ "warn": false,
+ "z": 334
+ },
+ {
+ "action": "get indicator",
+ "action_type": "investigate",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "indicator_type": "sha256",
+ "indicator_value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "get indicator",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "indicator_type": "sha256",
+ "indicator_value": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Indicator fetched successfully"
+ ]
+ },
+ {
+ "data_path": "action_result.summary",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.parameter.indicator_type",
+ "data_type": "string",
+ "example_values": [
+ "domain"
+ ]
+ },
+ {
+ "contains": [
+ "domain",
+ "md5",
+ "sha256",
+ "ip"
+ ],
+ "data_path": "action_result.parameter.indicator_value",
+ "data_type": "string",
+ "example_values": [
+ "xyz"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.source",
+ "data_type": "string",
+ "example_values": [
+ "test source"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.description",
+ "data_type": "string",
+ "example_values": [
+ "test description"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.meta.query_time",
+ "data_type": "numeric",
+ "example_values": [
+ 0.002269266
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.meta.trace_id",
+ "data_type": "string",
+ "example_values": [
+ "6a4b970e-93a9-4151-bac4-e721ff3925a8"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.modified_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2018-08-17T15:19:31Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.modified_by",
+ "data_type": "string",
+ "example_values": [
+ "C16JJOUVVY125J3O50FF"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.share_level",
+ "data_type": "string",
+ "example_values": [
+ "red"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.created_by",
+ "data_type": "string",
+ "example_values": [
+ "C16JJOUVVY125J3O50FF"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.created_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2018-08-17T15:19:31Z"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.value",
+ "data_type": "string",
+ "example_values": [
+ "xyz"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.policy",
+ "data_type": "string",
+ "example_values": [
+ "none"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.type",
+ "data_type": "string",
+ "example_values": [
+ "domain"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.resources.*.expiration_timestamp",
+ "data_type": "string",
+ "example_values": [
+ "2018-09-16T00:00:00Z"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "indicator_type": {
+ "data_type": "string",
+ "default": null,
+ "description": "The type of the indicator",
+ "key": "indicator_type",
+ "order": 1,
+ "required": true,
+ "value_list": [
+ "sha256",
+ "md5",
+ "domain",
+ "ipv4",
+ "ipv6"
+ ]
+ },
+ "indicator_value": {
+ "contains": [
+ "domain",
+ "md5",
+ "sha256",
+ "ip"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "String representation of the indicator",
+ "key": "indicator_value",
+ "order": 0,
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "get indicator"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Investigate"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_investigate.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def get_indicator_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('get_indicator_2() called')\n\n # collect data for 'get_indicator_2' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'get_indicator_2' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n if filtered_artifacts_item_1[0]:\n parameters.append({\n 'indicator_type': \"sha256\",\n 'indicator_value': filtered_artifacts_item_1[0],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[1]},\n })\n\n phantom.act(action=\"get indicator\", parameters=parameters, assets=['crowdstrike_oauth'], callback=if_indicator_exists, name=\"get_indicator_2\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "",
+ "connection_type": "",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "",
+ "delay": 0,
+ "description": "Fetch the CrowdStrike indicator for the SHA256 file hash, if there is one. This action will fail if there is no matching indicator in CrowdStrike, but the playbook will check for the failure and continue.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "c5d59d69-49e7-4433-a650-d1b0b98e74be",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 101,
+ "line_start": 79,
+ "message": "Configuring now",
+ "name": "get indicator",
+ "notes": "Fetch the CrowdStrike indicator for the SHA256 file hash, if there is one. This action will fail if there is no matching indicator in CrowdStrike, but the playbook will check for the failure and continue.",
+ "number": 2,
+ "order": 5,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -140,
+ "y": 60
+ },
+ "previous_function": "",
+ "previous_name": "get_indicator_2",
+ "required_params": {
+ "indicator_type": true,
+ "indicator_value": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Investigate",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 335
+ },
+ {
+ "active": false,
+ "angle": 0,
+ "approver": "admin",
+ "approver_display": "admin",
+ "attrs": {
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".number": {
+ "text": 2
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.error image": {
+ "xlink:href": "/inc/coa/img/block_icon_warn.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ }
+ },
+ "block_code": "def crowdstrike_known_file_quarantine(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('crowdstrike_known_file_quarantine() called')\n \n # set user and message variables for phantom.prompt call\n user = \"admin\"\n message = \"\"\"{0}\n\n---\n\nShould Phantom quarantine the device?\"\"\"\n\n # parameter list for template variable replacement\n parameters = [\n \"format_repeat_note:formatted_data\",\n ]\n\n #responses:\n response_types = [\n {\n \"prompt\": \"\",\n \"options\": {\n \"type\": \"list\",\n \"choices\": [\n \"Yes\",\n \"No\",\n ]\n },\n },\n ]\n\n phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name=\"crowdstrike_known_file_quarantine\", parameters=parameters, response_types=response_types, callback=quarantine_decision_2)\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "crowdstrike known file quarantine",
+ "description": "Ask the analyst if the endpoint should be quarantined.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "f41cc6f3-3db1-4909-b141-04c01050331f",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 719,
+ "line_start": 685,
+ "message": "{0}\n\n---\n\nShould Phantom quarantine the device?",
+ "name": "prompt",
+ "notes": "Ask the analyst if the endpoint should be quarantined.",
+ "number": 2,
+ "order": 29,
+ "outPorts": [
+ "out"
+ ],
+ "parameters": [
+ {
+ "position": 0,
+ "type": "",
+ "value": "format_repeat_note:formatted_data"
+ }
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 800,
+ "y": 620
+ },
+ "previous_function": "",
+ "previous_name": "crowdstrike_known_file_quarantine",
+ "respond_in": "30",
+ "response_key": "Message",
+ "response_options": [],
+ "response_type": "list",
+ "responses": [
+ {
+ "response_key": "Yes/No",
+ "response_options": [
+ "Yes",
+ "No"
+ ],
+ "response_prompt": "",
+ "response_type": "list"
+ }
+ ],
+ "show_number": true,
+ "size": {
+ "height": 80,
+ "width": 80
+ },
+ "state": "prompt",
+ "status": "",
+ "type": "coa.Prompt",
+ "warn": false,
+ "z": 336
+ },
+ {
+ "action": "list processes",
+ "action_type": "investigate",
+ "active": false,
+ "active_keys": {},
+ "active_values": {
+ "id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "angle": 0,
+ "app": "CrowdStrike OAuth API",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "approver": "",
+ "assets": [
+ {
+ "action": "list processes",
+ "actions": [
+ "update indicator",
+ "delete indicator",
+ "upload indicator",
+ "list processes",
+ "on poll",
+ "list put files",
+ "list custom indicators",
+ "get indicator",
+ "upload put file",
+ "hunt domain",
+ "hunt file",
+ "get process detail",
+ "get system info",
+ "set status",
+ "get session file",
+ "list incidents",
+ "list incident behaviors",
+ "get incident details",
+ "list crowdscores",
+ "get role",
+ "list roles",
+ "get user roles",
+ "list users",
+ "update incident",
+ "get incident behaviors",
+ "list session files",
+ "get command details",
+ "run admin command",
+ "run command",
+ "list sessions",
+ "delete session",
+ "create session",
+ "remove hosts",
+ "assign hosts",
+ "unquarantine device",
+ "quarantine device",
+ "list groups",
+ "query device",
+ "test connectivity"
+ ],
+ "active": true,
+ "app_name": "CrowdStrike OAuth API",
+ "app_version": "2.0.5",
+ "appid": "ae971ba5-3117-444a-8ac5-6ce779f3a232",
+ "asset_name": "crowdstrike_oauth",
+ "config_type": "asset",
+ "count": 0,
+ "fields": {
+ "id": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId",
+ "ioc": "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256"
+ },
+ "has_app": true,
+ "id": 19,
+ "loaded": false,
+ "missing": false,
+ "name": "crowdstrike_oauth",
+ "output": [
+ {
+ "column_name": "Status",
+ "column_order": 2,
+ "data_path": "action_result.status",
+ "data_type": "string",
+ "example_values": [
+ "success",
+ "failed"
+ ]
+ },
+ {
+ "column_name": "Crowdstrike Device ID",
+ "column_order": 0,
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_path": "action_result.parameter.id",
+ "data_type": "string",
+ "example_values": [
+ "07c312fabcb8473454d0a16f118928ab"
+ ]
+ },
+ {
+ "column_name": "IOC Queried",
+ "column_order": 1,
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain"
+ ],
+ "data_path": "action_result.parameter.ioc",
+ "data_type": "string",
+ "example_values": [
+ "eeb27d04c5fb25f7459407c0e5394621f12100e301b22d04a6b8f78e2adbf33d"
+ ]
+ },
+ {
+ "column_name": "Falcon Process ID",
+ "column_order": 3,
+ "contains": [
+ "falcon process id"
+ ],
+ "data_path": "action_result.data.*.falcon_process_id",
+ "data_type": "string",
+ "example_values": [
+ "pid:07c312fabcb8473454d0a16f118928fg:16716090292999"
+ ]
+ },
+ {
+ "data_path": "action_result.message",
+ "data_type": "string",
+ "example_values": [
+ "Process count: 1"
+ ]
+ },
+ {
+ "data_path": "summary.total_objects",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "summary.total_objects_successful",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ },
+ {
+ "data_path": "action_result.summary.process_count",
+ "data_type": "numeric",
+ "example_values": [
+ 1
+ ]
+ }
+ ],
+ "parameters": {
+ "id": {
+ "contains": [
+ "crowdstrike device id"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "Crowdstrike Device ID to search on",
+ "key": "id",
+ "primary": true,
+ "required": true
+ },
+ "ioc": {
+ "contains": [
+ "hash",
+ "sha256",
+ "sha1",
+ "md5",
+ "domain"
+ ],
+ "data_type": "string",
+ "default": null,
+ "description": "File Hash or Domain to use for searching",
+ "key": "ioc",
+ "primary": true,
+ "required": true
+ }
+ },
+ "product_name": "CrowdStrike",
+ "product_vendor": "CrowdStrike",
+ "targets": "19",
+ "type": "endpoint"
+ }
+ ],
+ "attrs": {
+ ".action": {
+ "text": "list processes with hash"
+ },
+ ".background": {
+ "fill": "#000000",
+ "stroke": "#5C6773"
+ },
+ ".color-band": {
+ "fill": "#3C444D"
+ },
+ ".inPorts>.port-in": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".inPorts>.port-in>.port-body": {
+ "port": {
+ "id": "in",
+ "type": "in"
+ }
+ },
+ ".message": {
+ "opacity": 0,
+ "ref-x": 5,
+ "ref-y": 105,
+ "text": "Configuring now"
+ },
+ ".outPorts>.port-out": {
+ "ref": ".background",
+ "ref-x": 0.5
+ },
+ ".outPorts>.port-out>.port-body": {
+ "port": {
+ "id": "out",
+ "type": "out"
+ }
+ },
+ ".title": {
+ "text": "Investigate"
+ },
+ "g.approver image": {
+ "opacity": 1
+ },
+ "g.code image": {
+ "opacity": 1
+ },
+ "g.delete": {
+ "display": "none"
+ },
+ "g.error": {
+ "opacity": 0
+ },
+ "g.icon image": {
+ "xlink:href": "/inc/coa/img/block_icon_investigate.svg"
+ },
+ "g.notes": {
+ "display": "block"
+ },
+ "g.notes image": {
+ "opacity": 1,
+ "xlink:href": "/inc/coa/img/block_icon_note_dark_on.svg"
+ },
+ "g.timer image": {
+ "opacity": 1
+ }
+ },
+ "block_code": "def list_processes_with_hash(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):\n phantom.debug('list_processes_with_hash() called')\n \n #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))\n \n # collect data for 'list_processes_with_hash' call\n filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])\n\n parameters = []\n \n # build parameters list for 'list_processes_with_hash' call\n for filtered_artifacts_item_1 in filtered_artifacts_data_1:\n if filtered_artifacts_item_1[0] and filtered_artifacts_item_1[1]:\n parameters.append({\n 'id': filtered_artifacts_item_1[0],\n 'ioc': filtered_artifacts_item_1[1],\n # context (artifact id) is added to associate results with the artifact\n 'context': {'artifact_id': filtered_artifacts_item_1[2]},\n })\n\n phantom.act(action=\"list processes\", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_process_details, name=\"list_processes_with_hash\")\n\n return",
+ "callback_code": "",
+ "callback_start": 1,
+ "callsback": true,
+ "color": "",
+ "connected_to_start": true,
+ "connection_name": "get indicator",
+ "connection_type": "action",
+ "custom_callback": "",
+ "custom_code": "",
+ "custom_join": "",
+ "custom_name": "list processes with hash",
+ "delay": 0,
+ "description": "List all processes seen on this host associated with this file hash.",
+ "has_custom": false,
+ "has_custom_block": false,
+ "has_custom_callback": false,
+ "has_custom_join": false,
+ "id": "2d0844c0-d8d8-4435-9b26-38ea0b6f2c3b",
+ "inPorts": [
+ "in"
+ ],
+ "join_code": "",
+ "join_optional": [],
+ "join_start": 1,
+ "line_end": 384,
+ "line_start": 360,
+ "message": "Configuring now",
+ "name": "list processes",
+ "notes": "List all processes seen on this host associated with this file hash.",
+ "number": 1,
+ "order": 17,
+ "outPorts": [
+ "out"
+ ],
+ "ports": {
+ "groups": {
+ "in": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "left"
+ }
+ },
+ "position": {
+ "name": "left"
+ }
+ },
+ "out": {
+ "attrs": {
+ ".port-body": {
+ "fill": "#fff",
+ "magnet": true,
+ "r": 10,
+ "stroke": "#000"
+ },
+ ".port-label": {
+ "fill": "#000"
+ }
+ },
+ "label": {
+ "position": {
+ "args": {
+ "y": 10
+ },
+ "name": "right"
+ }
+ },
+ "position": {
+ "name": "right"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": 240,
+ "y": -80
+ },
+ "previous_function": "",
+ "previous_name": "list_processes_with_hash",
+ "required_params": {
+ "id": true,
+ "ioc": true
+ },
+ "reviewer": "",
+ "show_number": false,
+ "size": {
+ "height": 100,
+ "width": 180
+ },
+ "state": "app_action_assets",
+ "status": "",
+ "title": "Investigate",
+ "type": "coa.Action",
+ "warn": false,
+ "z": 337
+ }
+ ]
+ },
+ "notes": "This playbook uses the following Apps:\n - CrowdStrike OAuth (get indicator, hunt file, and more) [asset name = crowdstrike_oauth] - Investigate and respond on the endpoint with CrowdStrike Falcon\n\nDeployment Notes:\n - Change the target user of the prompt from admin to the appropriate user or role"
+ },
+ "python_version": "3",
+ "schema": 4,
+ "version": "4.10.0.40961"
+ },
+ "create_time": "2021-02-25T15:14:37.456337+00:00",
+ "draft_mode": false,
+ "labels": [
+ "crowdstrike"
+ ],
+ "tags": []
+}
diff --git a/playbooks/crowdstrike_malware_triage.png b/playbooks/crowdstrike_malware_triage.png
new file mode 100644
index 0000000000..e6a6c0e2be
Binary files /dev/null and b/playbooks/crowdstrike_malware_triage.png differ
diff --git a/playbooks/crowdstrike_malware_triage.py b/playbooks/crowdstrike_malware_triage.py
new file mode 100644
index 0000000000..f4d792de49
--- /dev/null
+++ b/playbooks/crowdstrike_malware_triage.py
@@ -0,0 +1,792 @@
+"""
+Enrich and respond to a CrowdStrike Falcon detection involving a potentially malicious executable on an endpoint. Check for previous sightings of the same executable, hunt across other endpoints for the file, gather details about all processes associated with the file, and collect all the gathered information into a prompt for an analyst to review. Based on the analyst's choice, the file can be added to the custom indicators list in CrowdStrike with a detection policy of "detect" or "none", and the endpoint can be optionally quarantined from the network.
+"""
+
+import phantom.rules as phantom
+import json
+from datetime import datetime, timedelta
+def on_start(container):
+ phantom.debug('on_start() called')
+
+ # call 'if_sha256_exists' block
+ if_sha256_exists(container=container)
+
+ return
+
+"""
+List all machines where the file hash has been seen.
+"""
+def hunt_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('hunt_file_1() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'hunt_file_1' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'hunt_file_1' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ if filtered_artifacts_item_1[0]:
+ parameters.append({
+ 'hash': filtered_artifacts_item_1[0],
+ 'count_only': False,
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="hunt file", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_system_info_1, name="hunt_file_1")
+
+ return
+
+"""
+Ensure that the event has at least one artifact with a SHA256 file hash before attempting to process the event.
+"""
+def if_sha256_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('if_sha256_exists() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ conditions=[
+ ["artifact:*.cef.fileHashSha256", "!=", ""],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ filter_main_artifact(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 2
+ ignore_if_no_sha256(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+End the playbook if no SHA256 file hash is found in any of the artifacts.
+"""
+def ignore_if_no_sha256(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('ignore_if_no_sha256() called')
+
+ phantom.comment(container=container, comment="Ignoring alert because no SHA256 file hash was found")
+
+ return
+
+"""
+Fetch the CrowdStrike indicator for the SHA256 file hash, if there is one. This action will fail if there is no matching indicator in CrowdStrike, but the playbook will check for the failure and continue.
+"""
+def get_indicator_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('get_indicator_2() called')
+
+ # collect data for 'get_indicator_2' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'get_indicator_2' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ if filtered_artifacts_item_1[0]:
+ parameters.append({
+ 'indicator_type': "sha256",
+ 'indicator_value': filtered_artifacts_item_1[0],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="get indicator", parameters=parameters, assets=['crowdstrike_oauth'], callback=if_indicator_exists, name="get_indicator_2")
+
+ return
+
+"""
+Determine which response to take based on whether an Indicator exists in CrowdStrike for the SHA256 file hash.
+"""
+def if_indicator_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('if_indicator_exists() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["Resource Not Found", "in", "get_indicator_2:action_result.message"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ hunt_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ list_processes_with_hash(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 2
+ indicator_policy_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+Escalate the event because the Indicator policy is "detect", meaning the event is a true positive.
+"""
+def escalate_severity_to_high(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('escalate_severity_to_high() called')
+
+ phantom.set_severity(container=container, severity="High")
+
+ return
+
+"""
+Format a note to summarize all known information about the event.
+"""
+def format_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_repeat_note() called')
+
+ template = """CrowdStrike detected a file on an endpoint which matched a previously detected file hash:
+
+| Field | Value |
+|---|---|
+| Host | {0} |
+| Command Line | {1} |
+| SHA 256 | {2} |
+| File Path | {3}\\\\{4} |
+| CrowdStrike Detection Link | {5} |
+
+---
+
+This event will have the severity escalated to high, and should be investigated further."""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_repeat_note")
+
+ add_repeat_note(container=container)
+
+ return
+
+"""
+Add a note to summarize the event information.
+"""
+def add_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('add_repeat_note() called')
+
+ formatted_data_1 = phantom.get_format_data(name='format_repeat_note')
+
+ note_title = "Known Malicious File"
+ note_content = formatted_data_1
+ note_format = "markdown"
+ phantom.add_note(container=container, note_type="general", title=note_title, content=note_content, note_format=note_format)
+ crowdstrike_known_file_quarantine(container=container)
+
+ return
+
+"""
+Only process the main detection artifact, not any sub event artifacts.
+"""
+def filter_main_artifact(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('filter_main_artifact() called')
+
+ # collect filtered artifact ids for 'if' condition 1
+ matched_artifacts_1, matched_results_1 = phantom.condition(
+ container=container,
+ conditions=[
+ ["artifact:*.label", "==", "event"],
+ ],
+ name="filter_main_artifact:condition_1")
+
+ # call connected blocks if filtered artifacts or results
+ if matched_artifacts_1 or matched_results_1:
+ get_indicator_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
+
+ return
+
+"""
+Handle the Indicator differently if the policy is "detect", "none", or other.
+"""
+def indicator_policy_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('indicator_policy_decision() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["get_indicator_2:action_result.data.*.resources.*.policy", "==", "none"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ detection_policy_none(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # check for 'elif' condition 2
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["get_indicator_2:action_result.data.*.resources.*.policy", "==", "detect"],
+ ])
+
+ # call connected blocks if condition 2 matched
+ if matched:
+ escalate_severity_to_high(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ format_repeat_note(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 3
+ comment_unexpected_policy(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+End processing because this playbook only expects "none" or "detect" as the Indicator policy.
+"""
+def comment_unexpected_policy(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('comment_unexpected_policy() called')
+
+ phantom.comment(container=container, comment="The playbook received an unexpected indicator policy and needs to be extended to handle this situation.")
+
+ return
+
+"""
+Add a comment to explain why the event is being closed.
+"""
+def detection_policy_none(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('detection_policy_none() called')
+
+ phantom.comment(container=container, comment="The file hash indicator has a detection policy of none, so previous investigations have found that the file is not harmful. This playbook will take no further action and the event will be closed.")
+ close_event(container=container)
+
+ return
+
+"""
+Fetch additional information about each machine listed in the previous step.
+"""
+def get_system_info_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('get_system_info_1() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'get_system_info_1' call
+ results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_1:action_result.data.*.device_id', 'hunt_file_1:action_result.parameter.context.artifact_id'], action_results=results)
+
+ parameters = []
+
+ # build parameters list for 'get_system_info_1' call
+ for results_item_1 in results_data_1:
+ if results_item_1[0]:
+ parameters.append({
+ 'id': results_item_1[0],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': results_item_1[1]},
+ })
+
+ phantom.act(action="get system info", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name="get_system_info_1", parent_action=action)
+
+ return
+
+"""
+Summarize all the gathered information to help the analyst decide a response in the prompt.
+"""
+def format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_prompt() called')
+
+ template = """CrowdStrike detected the following suspicious activity on an endpoint:
+
+| Field | Value |
+|---|---|
+| Host | {0} |
+| Command Line | {1} |
+| SHA 256 | {2} |
+| File Path | {3}\\\\{4}
+| CrowdStrike Detection Link | {5} |
+| Details of processes associated with the file hash | |
+| Count of machines that have the file on disk | {6} |
+| System information of machines that have the file on disk | |"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName",
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
+ "hunt_file_1:action_result.summary.device_count",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_prompt")
+
+ crowdstrike_new_file_detection(container=container)
+
+ return
+
+def join_format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
+ phantom.debug('join_format_prompt() called')
+
+ # if the joined function has already been called, do nothing
+ if phantom.get_run_data(key='join_format_prompt_called'):
+ return
+
+ # check if all connected incoming playbooks, actions, or custom functions are done i.e. have succeeded or failed
+ if phantom.completed(action_names=['get_process_details']):
+
+ # save the state that the joined function has now been called
+ phantom.save_run_data(key='join_format_prompt_called', value='format_prompt')
+
+ # call connected block "format_prompt"
+ format_prompt(container=container, handle=handle)
+
+ return
+
+"""
+Close the event because the Indicator policy is "none", meaning the detection is a false positive.
+"""
+def close_event(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('close_event() called')
+
+ phantom.set_status(container=container, status="Closed")
+
+ return
+
+"""
+List all processes seen on this host associated with this file hash.
+"""
+def list_processes_with_hash(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('list_processes_with_hash() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'list_processes_with_hash' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'list_processes_with_hash' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ if filtered_artifacts_item_1[0] and filtered_artifacts_item_1[1]:
+ parameters.append({
+ 'id': filtered_artifacts_item_1[0],
+ 'ioc': filtered_artifacts_item_1[1],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[2]},
+ })
+
+ phantom.act(action="list processes", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_process_details, name="list_processes_with_hash")
+
+ return
+
+"""
+Fetch additional information about each process listed in the previous step.
+"""
+def get_process_details(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('get_process_details() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'get_process_details' call
+ results_data_1 = phantom.collect2(container=container, datapath=['list_processes_with_hash:action_result.data.*.falcon_process_id', 'list_processes_with_hash:action_result.parameter.context.artifact_id'], action_results=results)
+
+ parameters = []
+
+ # build parameters list for 'get_process_details' call
+ for results_item_1 in results_data_1:
+ if results_item_1[0]:
+ parameters.append({
+ 'falcon_process_id': results_item_1[0],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': results_item_1[1]},
+ })
+
+ phantom.act(action="get process detail", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name="get_process_details", parent_action=action)
+
+ return
+
+"""
+Prompt the user to determine whether or not to create an Indicator for the file hash and whether or not to quarantine the endpoint.
+"""
+def crowdstrike_new_file_detection(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('crowdstrike_new_file_detection() called')
+
+ # set user and message variables for phantom.prompt call
+ user = "admin"
+ message = """{0}"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "format_prompt:formatted_data",
+ ]
+
+ #responses:
+ response_types = [
+ {
+ "prompt": "Should Phantom create an Indicator in CrowdStrike to track this file hash from now on?",
+ "options": {
+ "type": "list",
+ "choices": [
+ "No, do not create an Indicator in CrowdStrike at this time.",
+ "Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)",
+ "Yes, create a CrowdStrike Indicator to ignore this file hash from now on. (False Positive)",
+ ]
+ },
+ },
+ {
+ "prompt": "Should Phantom quarantine the endpoint?",
+ "options": {
+ "type": "list",
+ "choices": [
+ "Yes",
+ "No",
+ ]
+ },
+ },
+ ]
+
+ phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="crowdstrike_new_file_detection", parameters=parameters, response_types=response_types, callback=crowdstrike_new_file_detection_callback)
+
+ return
+
+def crowdstrike_new_file_detection_callback(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
+ phantom.debug('crowdstrike_new_file_detection_callback() called')
+
+ indicator_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ quarantine_decision_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+Parse the prompt response to determine how to handle the indicator.
+"""
+def indicator_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('indicator_decision() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["No, do not create an Indicator in CrowdStrike at this time.", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ comment_no_indicator(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # check for 'elif' condition 2
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
+ ])
+
+ # call connected blocks if condition 2 matched
+ if matched:
+ format_detect_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # check for 'elif' condition 3
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["Yes, create a CrowdStrike Indicator to ignore this file hash going forward (False Positive)", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
+ ])
+
+ # call connected blocks if condition 3 matched
+ if matched:
+ format_ignore_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ return
+
+"""
+Check the quarantine device prompt response.
+"""
+def quarantine_decision_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('quarantine_decision_1() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["crowdstrike_new_file_detection:action_result.summary.responses.1", "==", "Yes"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ quarantine_device_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 2
+ comment_no_quarantine_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+Create an Indicator in CrowdStrike with a policy of "none" to ignore detections based on this file hash in the future.
+"""
+def create_ignore_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('create_ignore_indicator() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'create_ignore_indicator' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+ formatted_data_1 = phantom.get_format_data(name='format_ignore_description')
+
+ parameters = []
+
+ # build parameters list for 'create_ignore_indicator' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ if filtered_artifacts_item_1[0]:
+ parameters.append({
+ 'ioc': filtered_artifacts_item_1[0],
+ 'policy': "none",
+ 'source': "Phantom Playbook crowdstrike_malware_triage",
+ 'expiration': "",
+ 'description': formatted_data_1,
+ 'share_level': "red",
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="upload indicator", parameters=parameters, assets=['crowdstrike_oauth'], name="create_ignore_indicator")
+
+ return
+
+"""
+Format a description to provide when creating an Indicator with a policy of "none".
+"""
+def format_ignore_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_ignore_description() called')
+
+ template = """This indicator was created by Phantom in the playbook crowdstrike_malware_triage to ignore CrowdStrike detections based on the file hash first seen in {0} and processed in Phantom as {1}"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
+ "container:url",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_ignore_description")
+
+ create_ignore_indicator(container=container)
+
+ return
+
+"""
+Explain in a comment that no Indicator will be created.
+"""
+def comment_no_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('comment_no_indicator() called')
+
+ phantom.comment(container=container, comment="The analyst decided not to create a custom indicator for the file hash.")
+
+ return
+
+"""
+Format a description to provide when creating an Indicator with a policy of "detect".
+"""
+def format_detect_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('format_detect_description() called')
+
+ template = """This indicator was created by Phantom in the playbook crowdstrike_malware_triage to detect and block process executions based on the file hash first seen in {0} and processed in Phantom as {1}"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
+ "container:url",
+ ]
+
+ phantom.format(container=container, template=template, parameters=parameters, name="format_detect_description")
+
+ create_detect_indicator(container=container)
+
+ return
+
+"""
+Create an Indicator to detect and block this file hash.
+"""
+def create_detect_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('create_detect_indicator() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'create_detect_indicator' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'create_detect_indicator' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ if filtered_artifacts_item_1[0]:
+ parameters.append({
+ 'ioc': filtered_artifacts_item_1[0],
+ 'policy': "detect",
+ 'source': "",
+ 'expiration': "",
+ 'description': "",
+ 'share_level': "red",
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="upload indicator", parameters=parameters, assets=['crowdstrike_oauth'], name="create_detect_indicator")
+
+ return
+
+"""
+Do not quarantine the endpoint because the analyst responded No in the prompt.
+"""
+def comment_no_quarantine_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('comment_no_quarantine_1() called')
+
+ phantom.comment(container=container, comment="The analyst decided not to quarantine the endpoint.")
+
+ return
+
+"""
+Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.
+"""
+def quarantine_device_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('quarantine_device_1() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'quarantine_device_1' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'quarantine_device_1' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ parameters.append({
+ 'hostname': "",
+ 'device_id': filtered_artifacts_item_1[0],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="quarantine device", parameters=parameters, assets=['crowdstrike_oauth'], name="quarantine_device_1")
+
+ return
+
+"""
+Ask the analyst if the endpoint should be quarantined.
+"""
+def crowdstrike_known_file_quarantine(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('crowdstrike_known_file_quarantine() called')
+
+ # set user and message variables for phantom.prompt call
+ user = "admin"
+ message = """{0}
+
+---
+
+Should Phantom quarantine the device?"""
+
+ # parameter list for template variable replacement
+ parameters = [
+ "format_repeat_note:formatted_data",
+ ]
+
+ #responses:
+ response_types = [
+ {
+ "prompt": "",
+ "options": {
+ "type": "list",
+ "choices": [
+ "Yes",
+ "No",
+ ]
+ },
+ },
+ ]
+
+ phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="crowdstrike_known_file_quarantine", parameters=parameters, response_types=response_types, callback=quarantine_decision_2)
+
+ return
+
+"""
+Check if the analyst responded Yes or No to the quarantine.
+"""
+def quarantine_decision_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('quarantine_decision_2() called')
+
+ # check for 'if' condition 1
+ matched = phantom.decision(
+ container=container,
+ action_results=results,
+ conditions=[
+ ["crowdstrike_known_file_quarantine:action_result.summary.responses.0", "==", "Yes"],
+ ])
+
+ # call connected blocks if condition 1 matched
+ if matched:
+ quarantine_device_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+ return
+
+ # call connected blocks for 'else' condition 2
+ comment_no_quarantine_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
+
+ return
+
+"""
+Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.
+"""
+def quarantine_device_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('quarantine_device_2() called')
+
+ #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
+
+ # collect data for 'quarantine_device_2' call
+ filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
+
+ parameters = []
+
+ # build parameters list for 'quarantine_device_2' call
+ for filtered_artifacts_item_1 in filtered_artifacts_data_1:
+ parameters.append({
+ 'hostname': "",
+ 'device_id': filtered_artifacts_item_1[0],
+ # context (artifact id) is added to associate results with the artifact
+ 'context': {'artifact_id': filtered_artifacts_item_1[1]},
+ })
+
+ phantom.act(action="quarantine device", parameters=parameters, assets=['crowdstrike_oauth'], name="quarantine_device_2")
+
+ return
+
+"""
+Do not quarantine the endpoint because the analyst responded No in the prompt.
+"""
+def comment_no_quarantine_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
+ phantom.debug('comment_no_quarantine_2() called')
+
+ phantom.comment(container=container, comment="The analyst decided not to quarantine the endpoint.")
+
+ return
+
+def on_finish(container, summary):
+ phantom.debug('on_finish() called')
+ # This function is called after all actions are completed.
+ # summary of all the action and/or all details of actions
+ # can be collected here.
+
+ # summary_json = phantom.get_summary()
+ # if 'result' in summary_json:
+ # for action_result in summary_json['result']:
+ # if 'action_run_id' in action_result:
+ # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
+ # phantom.debug(action_results)
+
+ return
\ No newline at end of file
diff --git a/playbooks/crowdstrike_malware_triage.yml b/playbooks/crowdstrike_malware_triage.yml
new file mode 100644
index 0000000000..d24da6eed5
--- /dev/null
+++ b/playbooks/crowdstrike_malware_triage.yml
@@ -0,0 +1,20 @@
+name: Crowdstrike Malware Triage
+id: fc0edc96-fa2b-48b0-9a6f-63da6783fd63
+version: 1
+date: '2021-02-25'
+author: Philip Royer, Splunk
+type: Response
+description: This playbook is used to enrich and respond to a CrowdStrike Falcon detection involving a potentially malicious executable on an endpoint. Check for previous sightings of the same executable, hunt across other endpoints for the file, gather details about all processes associated with the file, and collect all the gathered information into a prompt for an analyst to review. Based on the analyst's choice, the file can be added to the custom indicators list in CrowdStrike with a detection policy of "detect" or "none", and the endpoint can be optionally quarantined from the network.
+playbook: crowdstrike_malware_triage
+how_to_implement: This playbook uses the Crowdstrike OAuth app. Change the target user of the prompt from admin to the appropriate user or role.
+references: []
+app_list:
+- "Crowdstrike OAuth"
+tags:
+ platform_tags:
+ - Response
+ playbook_fields:
+ - filePath
+ - destinationAddress
+ product:
+ - Splunk SOAR
diff --git a/playbooks/custom_functions/artifact_create.json b/playbooks/custom_functions/artifact_create.json
new file mode 100644
index 0000000000..51fc5de82a
--- /dev/null
+++ b/playbooks/custom_functions/artifact_create.json
@@ -0,0 +1,95 @@
+{
+ "create_time": "2021-08-13T13:55:18.025884+00:00",
+ "custom_function_id": "d4bcb95cc227e78a6e6985e2400015a14ada3056",
+ "description": "Create a new artifact with the specified attributes.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "phantom container id"
+ ],
+ "description": "Container which the artifact will be added to.",
+ "input_type": "item",
+ "name": "container",
+ "placeholder": "container:id"
+ },
+ {
+ "contains_type": [],
+ "description": "The name of the new artifact, which is optional and defaults to \"artifact\".",
+ "input_type": "item",
+ "name": "name",
+ "placeholder": "artifact"
+ },
+ {
+ "contains_type": [],
+ "description": "The label of the new artifact, which is optional and defaults to \"events\"",
+ "input_type": "item",
+ "name": "label",
+ "placeholder": "events"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "The severity of the new artifact, which is optional and defaults to \"Medium\". Typically this is either \"High\", \"Medium\", or \"Low\".",
+ "input_type": "item",
+ "name": "severity",
+ "placeholder": "Medium"
+ },
+ {
+ "contains_type": [],
+ "description": "The name of the CEF field to populate in the artifact, such as \"destinationAddress\" or \"sourceDnsDomain\". Required only if cef_value is provided.",
+ "input_type": "item",
+ "name": "cef_field",
+ "placeholder": "destinationAddress"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "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.",
+ "input_type": "item",
+ "name": "cef_value",
+ "placeholder": "192.0.2.192"
+ },
+ {
+ "contains_type": [],
+ "description": "The CEF data type of the data in cef_value. For example, this could be \"ip\", \"hash\", or \"domain\". Optional.",
+ "input_type": "item",
+ "name": "cef_data_type",
+ "placeholder": "ip"
+ },
+ {
+ "contains_type": [],
+ "description": "A comma-separated list of tags to apply to the created artifact, which is optional.",
+ "input_type": "item",
+ "name": "tags",
+ "placeholder": "tag1, tag2, tag3"
+ },
+ {
+ "contains_type": [],
+ "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\".",
+ "input_type": "item",
+ "name": "run_automation",
+ "placeholder": "false"
+ },
+ {
+ "contains_type": [],
+ "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.",
+ "input_type": "item",
+ "name": "input_json",
+ "placeholder": "{\"source_data_identifier\": \"1234\", \"data\": \"5678\"}"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [
+ "phantom artifact id"
+ ],
+ "data_path": "artifact_id",
+ "description": "The ID of the created artifact."
+ }
+ ],
+ "platform_version": "4.10.4.56260",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/artifact_create.py b/playbooks/custom_functions/artifact_create.py
new file mode 100644
index 0000000000..519e58ece4
--- /dev/null
+++ b/playbooks/custom_functions/artifact_create.py
@@ -0,0 +1,104 @@
+def artifact_create(container=None, name=None, label=None, severity=None, cef_field=None, cef_value=None, cef_data_type=None, tags=None, run_automation=None, input_json=None, **kwargs):
+ """
+ Create a new artifact with the specified attributes.
+
+ Args:
+ container (CEF type: phantom container id): Container which the artifact will be added to.
+ name: The name of the new artifact, which is optional and defaults to "artifact".
+ label: The label of the new artifact, which is optional and defaults to "events"
+ severity: The severity of the new artifact, which is optional and defaults to "Medium". Typically this is either "High", "Medium", or "Low".
+ cef_field: The name of the CEF field to populate in the artifact, such as "destinationAddress" or "sourceDnsDomain". Required only if cef_value is provided.
+ cef_value (CEF type: *): 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.
+ cef_data_type: The CEF data type of the data in cef_value. For example, this could be "ip", "hash", or "domain". Optional.
+ tags: A comma-separated list of tags to apply to the created artifact, which is optional.
+ run_automation: 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".
+ input_json: 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.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ artifact_id (CEF type: phantom artifact id): The ID of the created artifact.
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ new_artifact = {}
+ json_dict = None
+
+ if isinstance(container, int):
+ container_id = container
+ elif isinstance(container, dict):
+ container_id = container['id']
+ else:
+ raise TypeError("container is neither an int nor a dictionary")
+
+ if name:
+ new_artifact['name'] = name
+ else:
+ new_artifact['name'] = 'artifact'
+ if label:
+ new_artifact['label'] = label
+ else:
+ new_artifact['label'] = 'events'
+ if severity:
+ new_artifact['severity'] = severity
+ else:
+ new_artifact['severity'] = 'Medium'
+
+ # validate that if cef_field or cef_value is provided, the other is also provided
+ if (cef_field and not cef_value) or (cef_value and not cef_field):
+ raise ValueError("only one of cef_field and cef_value was provided")
+
+ # cef_data should be formatted {cef_field: cef_value}
+ if cef_field:
+ new_artifact['cef_data'] = {cef_field: cef_value}
+ if cef_data_type and isinstance(cef_data_type, str):
+ new_artifact['field_mapping'] = {cef_field: [cef_data_type]}
+
+ # run_automation must be "true" or "false" and defaults to "false"
+ if run_automation:
+ if not isinstance(run_automation, str):
+ raise TypeError("run automation must be a string")
+ if run_automation.lower() == 'true':
+ new_artifact['run_automation'] = True
+ elif run_automation.lower() == 'false':
+ new_artifact['run_automation'] = False
+ else:
+ raise ValueError("run_automation must be either 'true' or 'false'")
+ else:
+ new_artifact['run_automation'] = False
+
+ if input_json:
+ # ensure valid input_json
+ if isinstance(input_json, dict):
+ json_dict = input_json
+ elif isinstance(input_json, str):
+ json_dict = json.loads(input_json)
+ else:
+ raise ValueError("input_json must be either 'dict' or valid json 'string'")
+
+ if json_dict:
+ # Merge dictionaries, using the value from json_dict if there are any conflicting keys
+ for json_key in json_dict:
+ # extract tags from json_dict since it is not a valid parameter for phantom.add_artifact()
+ if json_key == 'tags':
+ tags = json_dict[json_key]
+ else:
+ new_artifact[json_key] = json_dict[json_key]
+
+ # now actually create the artifact
+ phantom.debug('creating a new artifact with the following attributes:\n{}'.format(new_artifact))
+ success, message, artifact_id = phantom.add_artifact(**new_artifact)
+
+ phantom.debug('add_artifact() returned the following:\nsuccess: {}\nmessage: {}\nartifact_id: {}'.format(success, message, artifact_id))
+ if not success:
+ raise RuntimeError("add_artifact() failed")
+
+ # add the tags in a separate REST call because there is no tags parameter in add_artifact()
+ if tags:
+ tags = tags.replace(" ", "").split(",")
+ url = phantom.build_phantom_rest_url('artifact', artifact_id)
+ response = phantom.requests.post(uri=url, json={'tags': tags}, verify=False).json()
+ phantom.debug('response from POST request to add tags:\n{}'.format(response))
+
+ # Return the id of the created artifact
+ return {'artifact_id': artifact_id}
diff --git a/playbooks/custom_functions/artifact_update.json b/playbooks/custom_functions/artifact_update.json
new file mode 100644
index 0000000000..e8f7a68f78
--- /dev/null
+++ b/playbooks/custom_functions/artifact_update.json
@@ -0,0 +1,80 @@
+{
+ "create_time": "2021-07-24T01:17:48.431013+00:00",
+ "custom_function_id": "1d358be9992079dad6d3313d465e65318930cf70",
+ "description": "Update an artifact with the specified attributes. All parameters are optional, except that cef_field and cef_value must both be provided if one is provided.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "phantom artifact id"
+ ],
+ "description": "ID of the artifact to update, which is required.",
+ "input_type": "item",
+ "name": "artifact_id",
+ "placeholder": "1234"
+ },
+ {
+ "contains_type": [],
+ "description": "Change the name of the artifact.",
+ "input_type": "item",
+ "name": "name",
+ "placeholder": "artifact"
+ },
+ {
+ "contains_type": [],
+ "description": "Change the label of the artifact.",
+ "input_type": "item",
+ "name": "label",
+ "placeholder": "events"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "Change the severity of the artifact. Typically this is either \"High\", \"Medium\", or \"Low\".",
+ "input_type": "item",
+ "name": "severity",
+ "placeholder": "Medium"
+ },
+ {
+ "contains_type": [],
+ "description": "The name of the CEF field to populate in the artifact, such as \"destinationAddress\" or \"sourceDnsDomain\". Required only if cef_value is provided.",
+ "input_type": "item",
+ "name": "cef_field",
+ "placeholder": "destinationAddress"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "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.",
+ "input_type": "item",
+ "name": "cef_value",
+ "placeholder": "192.0.2.192"
+ },
+ {
+ "contains_type": [],
+ "description": "The CEF data type of the data in cef_value. For example, this could be \"ip\", \"hash\", or \"domain\". Optional, but only operational if cef_field is provided.",
+ "input_type": "item",
+ "name": "cef_data_type",
+ "placeholder": "ip"
+ },
+ {
+ "contains_type": [],
+ "description": "A comma-separated list of tags to apply to the artifact, which is optional.",
+ "input_type": "item",
+ "name": "tags",
+ "placeholder": "tag1, tag2, tag3"
+ },
+ {
+ "contains_type": [],
+ "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.",
+ "input_type": "item",
+ "name": "input_json",
+ "placeholder": "{\"source_data_identifier\": \"1234\", \"data\": \"5678\"}"
+ }
+ ],
+ "outputs": [],
+ "platform_version": "4.10.4.56260",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/artifact_update.py b/playbooks/custom_functions/artifact_update.py
new file mode 100644
index 0000000000..e60dbb03bb
--- /dev/null
+++ b/playbooks/custom_functions/artifact_update.py
@@ -0,0 +1,65 @@
+def artifact_update(artifact_id=None, name=None, label=None, severity=None, cef_field=None, cef_value=None, cef_data_type=None, tags=None, input_json=None, **kwargs):
+ """
+ Update an artifact with the specified attributes. All parameters are optional, except that cef_field and cef_value must both be provided if one is provided.
+
+ Args:
+ artifact_id (CEF type: phantom artifact id): ID of the artifact to update, which is required.
+ name: Change the name of the artifact.
+ label: Change the label of the artifact.
+ severity: Change the severity of the artifact. Typically this is either "High", "Medium", or "Low".
+ cef_field: The name of the CEF field to populate in the artifact, such as "destinationAddress" or "sourceDnsDomain". Required only if cef_value is provided.
+ cef_value (CEF type: *): 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.
+ cef_data_type: The CEF data type of the data in cef_value. For example, this could be "ip", "hash", or "domain". Optional, but only operational if cef_field is provided.
+ tags: A comma-separated list of tags to apply to the artifact, which is optional.
+ input_json: 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.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ updated_artifact = {}
+
+ if not isinstance(artifact_id, int):
+ raise TypeError("artifact_id is required")
+
+ if name:
+ updated_artifact['name'] = name
+ if label:
+ updated_artifact['label'] = label
+ if severity:
+ updated_artifact['severity'] = severity
+
+ # validate that if cef_field or cef_value is provided, the other is also provided
+ if (cef_field and not cef_value) or (cef_value and not cef_field):
+ raise ValueError("only one of cef_field and cef_value was provided")
+
+ # cef_data should be formatted {cef_field: cef_value}
+ if cef_field:
+ updated_artifact['cef'] = {cef_field: cef_value}
+ if cef_data_type and isinstance(cef_data_type, str):
+ updated_artifact['cef_types'] = {cef_field: [cef_data_type]}
+
+ # separate tags by comma
+ if tags:
+ tags = tags.replace(" ", "").split(",")
+ updated_artifact['tags'] = tags
+
+ if input_json:
+ json_dict = json.loads(input_json)
+ # Merge dictionaries, using the value from json_dict if there are any conflicting keys
+ for json_key in json_dict:
+ updated_artifact[json_key] = json_dict[json_key]
+
+ # now actually update the artifact
+ phantom.debug('updating artifact {} with the following attributes:\n{}'.format(artifact_id, updated_artifact))
+ url = phantom.build_phantom_rest_url('artifact', artifact_id)
+ response = phantom.requests.post(url, json=updated_artifact, verify=False).json()
+
+ phantom.debug('POST /rest/artifact returned the following response:\n{}'.format(response))
+ if 'success' not in response or response['success'] != True:
+ raise RuntimeError("POST /rest/artifact failed")
+
+ return
diff --git a/playbooks/custom_functions/asset_get_attributes.json b/playbooks/custom_functions/asset_get_attributes.json
new file mode 100644
index 0000000000..e438ef4871
--- /dev/null
+++ b/playbooks/custom_functions/asset_get_attributes.json
@@ -0,0 +1,77 @@
+{
+ "create_time": "2021-08-24T13:51:40.605448+00:00",
+ "custom_function_id": "5ca49f921dfa723aff4e340671d610634f89e262",
+ "description": "Allows the retrieval of an attribute from an asset configuration for access in a playbook. This can be valuable in instances such as a dynamic note that references the Asset hostname. Must provide asset name or id.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "Asset numeric ID or asset name.",
+ "input_type": "item",
+ "name": "asset",
+ "placeholder": "splunk_es"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [],
+ "data_path": "id",
+ "description": "Unique asset id"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "name",
+ "description": "Unique asset name"
+ },
+ {
+ "contains_type": [],
+ "data_path": "configuration",
+ "description": "Access individual configuration attributes by appending \".\"\nExample: configuration.device"
+ },
+ {
+ "contains_type": [],
+ "data_path": "tags",
+ "description": "Asset tags"
+ },
+ {
+ "contains_type": [],
+ "data_path": "description",
+ "description": "Asset description"
+ },
+ {
+ "contains_type": [],
+ "data_path": "product_name",
+ "description": "Asset product_name"
+ },
+ {
+ "contains_type": [],
+ "data_path": "product_vendor",
+ "description": "Asset product_vendor"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "product_version",
+ "description": "Asset product_version"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "type",
+ "description": "Asset type"
+ },
+ {
+ "contains_type": [],
+ "data_path": "version",
+ "description": "Asset version"
+ }
+ ],
+ "platform_version": "4.10.6.61906",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/asset_get_attributes.py b/playbooks/custom_functions/asset_get_attributes.py
new file mode 100644
index 0000000000..89a575257e
--- /dev/null
+++ b/playbooks/custom_functions/asset_get_attributes.py
@@ -0,0 +1,50 @@
+def asset_get_attributes(asset=None, **kwargs):
+ """
+ Allows the retrieval of an attribute from an asset configuration for access in a playbook. This can be valuable in instances such as a dynamic note that references the Asset hostname. Must provide asset name or id.
+
+ Args:
+ asset: Asset numeric ID or asset name.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ id: Unique asset id
+ name: Unique asset name
+ configuration: Access individual configuration attributes by appending "."
+ Example: configuration.device
+ tags: Asset tags
+ description: Asset description
+ product_name: Asset product_name
+ product_vendor: Asset product_vendor
+ product_version: Asset product_version
+ type: Asset type
+ version: Asset version
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ outputs = {}
+ url = phantom.build_phantom_rest_url('asset')
+
+ if isinstance(asset, int):
+ url += '/{}'.format(asset)
+
+ # Attempt to translate asset_name to asset_id
+ elif isinstance(asset, str):
+ params = {'_filter_name': '"{}"'.format(asset)}
+ response = phantom.requests.get(uri=url, params=params, verify=False).json()
+ if response['count'] == 1:
+ url += '/{}'.format(response['data'][0]['id'])
+ else:
+ raise RuntimeError("No valid asset id found for provided asset name: {}".format(asset))
+ else:
+ raise TypeError("No valid asset id or name provided.")
+
+ response = phantom.requests.get(uri=url, verify=False).json()
+ if response.get('id'):
+ outputs = response
+ else:
+ raise RuntimeError("No valid asset id found.")
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/base64_decode.json b/playbooks/custom_functions/base64_decode.json
new file mode 100644
index 0000000000..f3d97da0cd
--- /dev/null
+++ b/playbooks/custom_functions/base64_decode.json
@@ -0,0 +1,51 @@
+{
+ "create_time": "2021-10-18T17:15:17.576903+00:00",
+ "custom_function_id": "a5663cbe44479126d9fdff5818c8500011abc53e",
+ "description": "Decode one or more strings encoded with base64. The input can be a single chunk of base64 or a list of strings separated by a delimiter.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "Y2FsYy5leGU=",
+ "input_type": "item",
+ "name": "input_string",
+ "placeholder": "base64 string to decode"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "Defaults to False. If True, use the delimiter to split the input string and decode each of the components separately if it is base64.",
+ "input_type": "item",
+ "name": "split_input",
+ "placeholder": "True or False"
+ },
+ {
+ "contains_type": [],
+ "description": "The character to use as a delimiter if split_input is True. Defaults to a comma. The special option \"space\" can be used to split on a single space character (\" \").",
+ "input_type": "item",
+ "name": "delimiter",
+ "placeholder": ","
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "*.input_string",
+ "description": "Base64 string before being decoded"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "*.output_string",
+ "description": "Resulting string after decoding from base64"
+ }
+ ],
+ "platform_version": "5.0.1.66250",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/base64_decode.py b/playbooks/custom_functions/base64_decode.py
new file mode 100644
index 0000000000..c43458612a
--- /dev/null
+++ b/playbooks/custom_functions/base64_decode.py
@@ -0,0 +1,66 @@
+def base64_decode(input_string=None, split_input=None, delimiter=None, **kwargs):
+ """
+ Decode one or more strings encoded with base64. The input can be a single chunk of base64 or a list of strings separated by a delimiter.
+
+ Args:
+ input_string (CEF type: *): Y2FsYy5leGU=
+ split_input: Defaults to False. If True, use the delimiter to split the input string and decode each of the components separately if it is base64.
+ delimiter: The character to use as a delimiter if split_input is True. Defaults to a comma. The special option "space" can be used to split on a single space character (" ").
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ *.input_string (CEF type: *): Base64 string before being decoded
+ *.output_string (CEF type: *): Resulting string after decoding from base64
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+ import base64
+
+ if not input_string or not isinstance(input_string, str):
+ raise ValueError('input_string must be a string')
+
+ def isBase64(sb):
+ try:
+ if isinstance(sb, str):
+ # If there's any unicode here, an exception will be thrown and the function will return false
+ sb_bytes = bytes(sb, 'ascii')
+ elif isinstance(sb, bytes):
+ sb_bytes = sb
+ else:
+ raise ValueError("Argument must be string or bytes")
+ return base64.b64encode(base64.b64decode(sb_bytes)) == sb_bytes
+ except Exception:
+ return False
+
+ outputs = []
+
+ # split_input defaults to false
+ if split_input == True or (isinstance(split_input, str) and split_input.lower() == 'true'):
+ split_input = True
+ else:
+ split_input = False
+
+ # create the list of inputs, whether it be the single input or a delimiter-separated list
+ if not split_input:
+ input_list = [input_string]
+ else:
+ if not isinstance(delimiter, str):
+ delimiter = ','
+ if delimiter == 'space':
+ delimiter = ' '
+ input_list = input_string.split(delimiter)
+
+ # now that input_list is set up, perform the base64 decode on each item that is valid base64
+ for index, value in enumerate(input_list):
+ if isBase64(value):
+ try:
+ value_bytes = value.encode('ascii')
+ data = base64.b64decode(value_bytes, validate=True)
+ if data:
+ outputs.append({'input_string': value, 'output_string': data.decode('ascii').replace('\x00','')})
+
+ except Exception as e:
+ phantom.error(f'Unable to decode string: {e}')
+
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/collect_by_cef_type.json b/playbooks/custom_functions/collect_by_cef_type.json
new file mode 100644
index 0000000000..8be2ec73ff
--- /dev/null
+++ b/playbooks/custom_functions/collect_by_cef_type.json
@@ -0,0 +1,56 @@
+{
+ "create_time": "2021-08-24T16:17:12.241297+00:00",
+ "custom_function_id": "98612a9a22a18dff43b6644ed00c2c523d348d79",
+ "description": "Collect all artifact values that match the desired CEF data types, such as \"ip\", \"url\", \"sha1\", or \"all\". Optionally also filter for artifacts that have the specified tags.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "phantom container id"
+ ],
+ "description": "Container ID or container object.",
+ "input_type": "item",
+ "name": "container",
+ "placeholder": "container:id"
+ },
+ {
+ "contains_type": [],
+ "description": "The CEF data type to collect values for. This could be a single string or a comma separated list such as \"hash,filehash,file_hash\". The special value \"all\" can also be used to collect all field values from all artifacts.",
+ "input_type": "item",
+ "name": "data_types",
+ "placeholder": "data_type1, data_type2, data_type3"
+ },
+ {
+ "contains_type": [],
+ "description": "If tags are provided, only return fields from artifacts that have all of the provided tags. This could be an individual tag or a comma separated list.",
+ "input_type": "item",
+ "name": "tags",
+ "placeholder": "tag1,tag2,tag3"
+ },
+ {
+ "contains_type": [],
+ "description": "Defaults to 'new'. Define custom scope. Advanced Settings Scope is not passed to a custom function. Options are 'all' or 'new'.",
+ "input_type": "item",
+ "name": "scope",
+ "placeholder": "new"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "*.artifact_value",
+ "description": "The value of the field with the matching CEF data type."
+ },
+ {
+ "contains_type": [
+ "phantom artifact id"
+ ],
+ "data_path": "*.artifact_id",
+ "description": "ID of the artifact that contains the value."
+ }
+ ],
+ "platform_version": "4.10.6.61906",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/collect_by_cef_type.py b/playbooks/custom_functions/collect_by_cef_type.py
new file mode 100644
index 0000000000..a38f0d41cc
--- /dev/null
+++ b/playbooks/custom_functions/collect_by_cef_type.py
@@ -0,0 +1,90 @@
+def collect_by_cef_type(container=None, data_types=None, tags=None, scope=None, **kwargs):
+ """
+ Collect all artifact values that match the desired CEF data types, such as "ip", "url", "sha1", or "all". Optionally also filter for artifacts that have the specified tags.
+
+ Args:
+ container (CEF type: phantom container id): Container ID or container object.
+ data_types: The CEF data type to collect values for. This could be a single string or a comma separated list such as "hash,filehash,file_hash". The special value "all" can also be used to collect all field values from all artifacts.
+ tags: If tags are provided, only return fields from artifacts that have all of the provided tags. This could be an individual tag or a comma separated list.
+ scope: Defaults to 'new'. Define custom scope. Advanced Settings Scope is not passed to a custom function. Options are 'all' or 'new'.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ *.artifact_value (CEF type: *): The value of the field with the matching CEF data type.
+ *.artifact_id (CEF type: phantom artifact id): ID of the artifact that contains the value.
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+ import traceback
+
+ # validate container and get ID
+ if isinstance(container, dict) and container['id']:
+ container_dict = container
+ container_id = container['id']
+ elif isinstance(container, int):
+ rest_container = phantom.requests.get(uri=phantom.build_phantom_rest_url('container', container), verify=False).json()
+ if 'id' not in rest_container:
+ raise ValueError('Failed to find container with id {container}')
+ container_dict = rest_container
+ container_id = container
+ else:
+ raise TypeError("The input 'container' is neither a container dictionary nor an int, so it cannot be used")
+
+ # validate the data_types input
+ if not data_types or not isinstance(data_types, str):
+ raise ValueError("The input 'data_types' must exist and must be a string")
+ # if data_types has a comma, split it and treat it as a list
+ elif "," in data_types:
+ data_types = [item.strip() for item in data_types.split(",")]
+ # else it must be a single data type
+ else:
+ data_types = [data_types]
+
+ # validate scope input
+ if isinstance(scope, str) and scope.lower() in ['new', 'all']:
+ scope = scope.lower()
+ elif not scope:
+ scope = None
+ else:
+ raise ValueError("The input 'scope' is not one of 'new' or 'all'")
+
+ # split tags if it contains commas or use as-is
+ if not tags:
+ tags = []
+ # if tags has a comma, split it and treat it as a list
+ elif tags and "," in tags:
+ tags = [item.strip() for item in tags.split(",")]
+ # if there is no comma, treat it as a single tag
+ else:
+ tags = [tags]
+
+ # collect all values matching the cef type (which was previously called "contains")
+ collected_field_values = phantom.collect_from_contains(container=container_dict, action_results=None, contains=data_types, scope=scope)
+ phantom.debug(f'found the following field values: {collected_field_values}')
+
+ # collect all the artifacts in the container to get the artifact IDs
+ artifacts = phantom.requests.get(uri=phantom.build_phantom_rest_url('container', container_id, 'artifacts'), params={'page_size': 0}, verify=False).json()['data']
+
+ # build the output list from artifacts with the collected field values
+ outputs = []
+ for artifact in artifacts:
+ # if any tags are provided, make sure each provided tag is in the artifact's tags
+ if tags:
+ if not set(tags).issubset(set(artifact['tags'])):
+ continue
+ # "all" is a special value to collect every value from every artifact
+ if data_types == ['all']:
+ for cef_key in artifact['cef']:
+ new_output = {'artifact_value': artifact['cef'][cef_key], 'artifact_id': artifact['id']}
+ if new_output not in outputs:
+ outputs.append(new_output)
+ continue
+ for cef_key in artifact['cef']:
+ if artifact['cef'][cef_key] in collected_field_values:
+ new_output = {'artifact_value': artifact['cef'][cef_key], 'artifact_id': artifact['id']}
+ if new_output not in outputs:
+ outputs.append(new_output)
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/container_merge.json b/playbooks/custom_functions/container_merge.json
new file mode 100644
index 0000000000..9ea4df87bc
--- /dev/null
+++ b/playbooks/custom_functions/container_merge.json
@@ -0,0 +1,41 @@
+{
+ "create_time": "2021-10-18T12:31:32.500833+00:00",
+ "custom_function_id": "83776ecf4dd52c71d8497cb500dd332780eb9c72",
+ "description": "An alternative to the add-to-case API call. This function will copy all artifacts, automation, notes and comments over from every container within the container_list into the target_container. The target_container will be upgraded to a case.\n\nThe notes will be copied over with references to the child containers from where they came. A note will be left in the child containers with a link to the target container. The child containers will be marked as evidence within the target container. \n\nAny notes left as a consequence of the merge process will be skipped in subsequent merges.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "phantom container id"
+ ],
+ "description": "The target container to copy the information over. Supports container dictionary or container id.",
+ "input_type": "item",
+ "name": "target_container",
+ "placeholder": "container:id"
+ },
+ {
+ "contains_type": [],
+ "description": "A list of container IDs to copy into the target container.",
+ "input_type": "list",
+ "name": "container_list",
+ "placeholder": "[1, 5, 10]"
+ },
+ {
+ "contains_type": [],
+ "description": "Name or ID of the workbook to add if the container does not have a workbook yet. If no workbook is provided, the system default workbook will be added.",
+ "input_type": "item",
+ "name": "workbook",
+ "placeholder": "My Workbook"
+ },
+ {
+ "contains_type": [],
+ "description": "True or False to close the child containers in the container_list after merge. Defaults to False.",
+ "input_type": "item",
+ "name": "close_containers",
+ "placeholder": "True or False"
+ }
+ ],
+ "outputs": [],
+ "platform_version": "5.0.1.66250",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/container_merge.py b/playbooks/custom_functions/container_merge.py
new file mode 100644
index 0000000000..c301bbb310
--- /dev/null
+++ b/playbooks/custom_functions/container_merge.py
@@ -0,0 +1,192 @@
+def container_merge(target_container=None, container_list=None, workbook=None, close_containers=None, **kwargs):
+ """
+ An alternative to the add-to-case API call. This function will copy all artifacts, automation, notes and comments over from every container within the container_list into the target_container. The target_container will be upgraded to a case.
+
+ The notes will be copied over with references to the child containers from where they came. A note will be left in the child containers with a link to the target container. The child containers will be marked as evidence within the target container.
+
+ Any notes left as a consequence of the merge process will be skipped in subsequent merges.
+
+ Args:
+ target_container (CEF type: phantom container id): The target container to copy the information over. Supports container dictionary or container id.
+ container_list: A list of container IDs to copy into the target container.
+ workbook: Name or ID of the workbook to add if the container does not have a workbook yet. If no workbook is provided, the system default workbook will be added.
+ close_containers: True or False to close the child containers in the container_list after merge. Defaults to False.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ outputs = {}
+
+ # Check if valid target_container input was provided
+ if isinstance(target_container, int):
+ container = phantom.get_container(target_container)
+ elif isinstance(target_container, dict):
+ container = target_container
+ else:
+ raise TypeError(f"target_container '{target_container}' is neither a int or a dictionary")
+
+ container_url = phantom.build_phantom_rest_url('container', container['id'])
+
+ # Check if container_list input is a list of IDs
+ if isinstance(container_list, list) and (all(isinstance(x, int) for x in container_list) or all(x.isnumeric() for x in container_list)):
+ pass
+ else:
+ raise TypeError(f"container_list '{container_list}' is not a list of integers")
+
+ ## Prep parent container as case with workbook ##
+ workbook_name = phantom.requests.get(container_url, verify=False).json().get('workflow_name')
+ # If workbook already exists, proceed to promote to case
+ if workbook_name:
+ phantom.debug("workbook already exists. adding [Parent] to container name and promoting to case")
+ update_data = {'container_type': 'case'}
+ if not '[Parent]' in container['name']:
+ update_data['name'] = "[Parent] {}".format(container['name'])
+ phantom.update(container, update_data)
+ else:
+ phantom.update(container, update_data)
+ # If no workbook exists, add one
+ else:
+ phantom.debug("no workbook in container. adding one by name or using the default")
+ # If workbook ID was provided, add it
+ if isinstance(workbook, int):
+ workbook_id = workbook
+ phantom.add_workbook(container=container['id'], workbook_id=workbook_id)
+ # elif workbook name was provided, attempt to translate it to an id
+ elif isinstance(workbook, str):
+ workbook_url = phantom.build_phantom_rest_url('workbook_template') + '?_filter_name="{}"'.format(workbook)
+ response = phantom.requests.get(workbook_url, verify=False).json()
+ if response['count'] > 1:
+ raise RuntimeError('Unable to add workbook - more than one ID matches workbook name')
+ elif response['data'][0]['id']:
+ workbook_id = response['data'][0]['id']
+ phantom.add_workbook(container=container['id'], workbook_id=workbook_id)
+ else:
+ # Adding default workbook
+ phantom.promote(container=container['id'])
+ # Check again to see if a workbook now exists
+ workbook_name = phantom.requests.get(container_url, verify=False).json().get('workflow_name')
+ # If workbook is now present, promote to case
+ if workbook_name:
+ update_data = {'container_type': 'case'}
+ if not '[Parent]' in container['name']:
+ update_data['name'] = "[Parent] {}".format(container['name'])
+ phantom.update(container, update_data)
+ else:
+ phantom.update(container, update_data)
+ else:
+ raise RuntimeError(f"Error occurred during workbook add for workbook '{workbook_name}'")
+
+ ## Check if current phase is set. If not, set the current phase to the first available phase to avoid artifact merge error ##
+ if not container.get('current_phase_id'):
+ phantom.debug("no current phase, so setting first available phase to current")
+ workbook_phase_url = phantom.build_phantom_rest_url('workbook_phase') + "?_filter_container={}".format(container['id'])
+ request_json = phantom.requests.get(workbook_phase_url, verify=False).json()
+ update_data = {'current_phase_id': request_json['data'][0]['id']}
+ phantom.update(container, update_data)
+
+ child_container_list = []
+ child_container_name_list = []
+ # Iterate through child containers
+ for child_container_id in container_list:
+
+ ### Begin child container processing ###
+ phantom.debug("Processing Child Container ID: {}".format(child_container_id))
+
+ child_container = phantom.get_container(child_container_id)
+ child_container_list.append(child_container_id)
+ child_container_name_list.append(child_container['name'])
+ child_container_url = phantom.build_phantom_rest_url('container', child_container_id)
+
+ ## Update container name with parent relationship
+ if not "[Parent:" in child_container['name']:
+ update_data = {'name': "[Parent: {0}] {1}".format(container['id'], child_container['name'])}
+ phantom.update(child_container, update_data)
+
+ ## Gather and add notes ##
+ for note in phantom.get_notes(container=child_container_id):
+ # Avoid copying any notes related to the merge process.
+ if note['success'] and not note['data']['title'] in ('[Auto-Generated] Related Containers',
+ '[Auto-Generated] Parent Container',
+ '[Auto-Generated] Child Containers'):
+ phantom.add_note(container=container['id'],
+ note_type='general',
+ note_format=note['data']['note_format'],
+ title="[From Event {0}] {1}".format(note['data']['container'], note['data']['title']),
+ content=note['data']['content'])
+
+ ## Copy information and add to case
+ data = {'add_to_case': True,
+ 'container_id': child_container_id,
+ 'copy_artifacts': True,
+ 'copy_automation': True,
+ 'copy_files': True,
+ 'copy_comments': True
+ }
+ phantom.requests.post(container_url, json=data, verify=False)
+
+ ## Leave a note with a link to the parent container
+ phantom.debug("Adding parent relationship note to child container '{}'".format(child_container_id))
+ data_row = "{0} | [{1}]({2}/mission/{0}) |".format(container['id'], container['name'], phantom.get_base_url())
+ phantom.add_note(container=child_container_id,
+ note_type="general",
+ note_format="markdown",
+ title="[Auto-Generated] Parent Container",
+ content="| Container_ID | Container_Name |\n| --- | --- |\n| {}".format(data_row))
+
+ ## Mark child container as evidence in target_container
+ data = {
+ "container_id": container['id'],
+ "object_id": child_container_id,
+ "content_type": "container"
+ }
+ evidence_url = phantom.build_phantom_rest_url('evidence')
+ response = phantom.requests.post(evidence_url, json=data, verify=False).json()
+
+ ## Close child container
+ if isinstance(close_containers, str) and close_containers.lower() == 'true':
+ phantom.set_status(container=child_container_id, status="closed")
+
+ ### End child container processing ###
+
+ ## Format and add note for link back to child_containers in parent_container
+ note_title = "[Auto-Generated] Child Containers"
+ note_format = "markdown"
+ format_list = []
+ # Build new note
+ for child_container_id,child_container_name in zip(child_container_list,child_container_name_list):
+ format_list.append("| {0} | [{1}]({2}/mission/{0}) |\n".format(child_container_id, child_container_name, phantom.get_base_url()))
+ # Fetch any previous merge note
+ params = {'_filter_container': '"{}"'.format(container['id']), '_filter_title': '"[Auto-Generated] Child Containers"'}
+ note_url = phantom.build_phantom_rest_url('note')
+ response_data = phantom.requests.get(note_url, verify=False).json()
+ # If an old note was found, proceed to overwrite it
+ if response_data['count'] > 0:
+ note_item = response_data['data'][0]
+ note_content = note_item['content']
+ # Append new information to existing note
+ for c_note in format_list:
+ note_content += c_note
+ data = {"note_type": "general",
+ "title": note_title,
+ "content": note_content,
+ "note_format": note_format}
+ # Overwrite note
+ response_data = phantom.requests.post(note_url + "/{}".format(note_item['id']), json=data, verify=False).json()
+ # If no old note was found, add new with header
+ else:
+ template = "| Container ID | Container Name |\n| --- | --- |\n"
+ for c_note in format_list:
+ template += c_note
+ success, message, process_container_merge__note_id = phantom.add_note(container=container,
+ note_type="general",
+ title=note_title,
+ content=template,
+ note_format=note_format)
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/container_update.json b/playbooks/custom_functions/container_update.json
new file mode 100644
index 0000000000..5ac43b8864
--- /dev/null
+++ b/playbooks/custom_functions/container_update.json
@@ -0,0 +1,85 @@
+{
+ "create_time": "2021-07-19T18:11:14.706144+00:00",
+ "custom_function_id": "7272e46db8e97248abb1584c72c0734ff9e303dc",
+ "description": "Allows updating various attributes of a container in a single custom function. Any attributes of a container not listed can be updated via the input_json parameter. ",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "phantom container id"
+ ],
+ "description": "Supports a container id or container dictionary",
+ "input_type": "item",
+ "name": "container_input",
+ "placeholder": "container:id"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change container name",
+ "input_type": "item",
+ "name": "name",
+ "placeholder": "My Container Name"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container description",
+ "input_type": "item",
+ "name": "description",
+ "placeholder": "My Container Description"
+ },
+ {
+ "contains_type": [
+ "phantom container label"
+ ],
+ "description": "Optional parameter to change the container label",
+ "input_type": "item",
+ "name": "label",
+ "placeholder": "my_label"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container owner. Accepts a username or role name or keyword \"current\" to set the currently running playbook user as the owner.",
+ "input_type": "item",
+ "name": "owner",
+ "placeholder": "admin"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container sensitivity. ",
+ "input_type": "item",
+ "name": "sensitivity",
+ "placeholder": "amber"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container severity.",
+ "input_type": "item",
+ "name": "severity",
+ "placeholder": "medium"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container status.",
+ "input_type": "item",
+ "name": "status",
+ "placeholder": "open"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to change the container tags. Must be in the format of a comma separated list.",
+ "input_type": "item",
+ "name": "tags",
+ "placeholder": "tag1, tag2"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to modify any extra attributes of a container. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.",
+ "input_type": "item",
+ "name": "input_json",
+ "placeholder": "{\"custom_fields\": {\"field_name\": \"field_value\"}}"
+ }
+ ],
+ "outputs": [],
+ "platform_version": "4.10.4.56260",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/container_update.py b/playbooks/custom_functions/container_update.py
new file mode 100644
index 0000000000..bed550a3b6
--- /dev/null
+++ b/playbooks/custom_functions/container_update.py
@@ -0,0 +1,85 @@
+def container_update(container_input=None, name=None, description=None, label=None, owner=None, sensitivity=None, severity=None, status=None, tags=None, input_json=None, **kwargs):
+ """
+ Allows updating various attributes of a container in a single custom function. Any attributes of a container not listed can be updated via the input_json parameter.
+
+ Args:
+ container_input (CEF type: phantom container id): Supports a container id or container dictionary
+ name: Optional parameter to change container name
+ description: Optional parameter to change the container description
+ label (CEF type: phantom container label): Optional parameter to change the container label
+ owner: Optional parameter to change the container owner. Accepts a username or role name or keyword "current" to set the currently running playbook user as the owner.
+ sensitivity: Optional parameter to change the container sensitivity.
+ severity: Optional parameter to change the container severity.
+ status: Optional parameter to change the container status.
+ tags: Optional parameter to change the container tags. Must be in the format of a comma separated list.
+ input_json: Optional parameter to modify any extra attributes of a container. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ outputs = {}
+ update_dict = {}
+
+ if isinstance(container_input, int):
+ container = phantom.get_container(container_input)
+ elif isinstance(container_input, dict):
+ container = container_input
+ else:
+ raise TypeError("container_input is neither a int or a dictionary")
+
+ if name:
+ update_dict['name'] = name
+ if description:
+ update_dict['description'] = description
+ if label:
+ update_dict['label'] = label
+ if owner:
+ # If keyword 'current' entered then translate effective_user id to a username
+ if owner.lower() == 'current':
+ update_dict['owner_id'] = phantom.get_effective_user()
+ else:
+ # Attempt to translate name to owner_id
+ url = phantom.build_phantom_rest_url('ph_user') + f'?_filter_username="{owner}"'
+ data = phantom.requests.get(url, verify=False).json().get('data')
+ if data and len(data) == 1:
+ update_dict['owner_id'] = data[0]['id']
+ elif data and len(data) > 1:
+ phantom.error(f'Multiple matches for owner "{owner}"')
+ else:
+ # Attempt to translate name to role_id
+ url = phantom.build_phantom_rest_url('role') + f'?_filter_name="{owner}"'
+ data = phantom.requests.get(url, verify=False).json().get('data')
+ if data and len(data) == 1:
+ update_dict['role_id'] = data[0]['id']
+ elif data and len(data) > 1:
+ phantom.error(f'Multiple matches for role "{owner}"')
+ else:
+ phantom.error(f'"{owner}" is not a valid username or role')
+ if sensitivity:
+ update_dict['sensitivity'] = sensitivity
+ if severity:
+ update_dict['severity'] = severity
+ if status:
+ update_dict['status'] = status
+ if tags:
+ tags = tags.replace(" ", "").split(",")
+ update_dict['tags'] = tags
+ if input_json:
+ json_dict = json.loads(input_json)
+ # Merge dictionaries together. The second argument, "**json_dict" will take precedence and overwrite any duplicate parameters.
+ update_dict = {**update_dict, **json_dict}
+
+ if update_dict:
+ phantom.debug('Updating container {0} with the following information: "{1}"'.format(container['id'], update_dict))
+ phantom.update(container, update_dict)
+ else:
+ phantom.debug("Valid container entered but no valid container changes provided.")
+
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/custom_list_enumerate.json b/playbooks/custom_functions/custom_list_enumerate.json
new file mode 100644
index 0000000000..0c12ad0d42
--- /dev/null
+++ b/playbooks/custom_functions/custom_list_enumerate.json
@@ -0,0 +1,71 @@
+{
+ "create_time": "2021-03-24T13:38:50.951017+00:00",
+ "custom_function_id": "b7a89f44958aee7bbdb3054d43c06df9a2026370",
+ "description": "Fetch a custom list and iterate through the rows, producing a dictionary output for each row with the row number and the value for each column.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [],
+ "description": "the name or ID of a custom list",
+ "input_type": "item",
+ "name": "custom_list",
+ "placeholder": "my_custom_list"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [],
+ "data_path": "*.row_num",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_0",
+ "description": ""
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "*.column_1",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_2",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_3",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_4",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_5",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_6",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_7",
+ "description": ""
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.column_8",
+ "description": ""
+ }
+ ],
+ "platform_version": "4.10.2.47587",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/custom_list_enumerate.py b/playbooks/custom_functions/custom_list_enumerate.py
new file mode 100644
index 0000000000..eb75286321
--- /dev/null
+++ b/playbooks/custom_functions/custom_list_enumerate.py
@@ -0,0 +1,49 @@
+def custom_list_enumerate(custom_list=None, **kwargs):
+ """
+ Fetch a custom list and iterate through the rows, producing a dictionary output for each row with the row number and the value for each column.
+
+ Args:
+ custom_list: the name or ID of a custom list
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ *.row_num
+ *.column_0
+ *.column_1
+ *.column_2
+ *.column_3
+ *.column_4
+ *.column_5
+ *.column_6
+ *.column_7
+ *.column_8
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ if not custom_list:
+ raise ValueError('list_name_or_num parameter is required')
+
+ outputs = []
+
+ # Use REST to get the custom list
+ custom_list_request = phantom.requests.get(
+ phantom.build_phantom_rest_url('decided_list', custom_list),
+ verify=False
+ )
+
+ # Raise error if unsuccessful
+ custom_list_request.raise_for_status()
+
+ # Get the list content
+ custom_list = custom_list_request.json().get('content', [])
+
+ # Iterate through all rows and save to a list of dicts
+ for row_num, row in enumerate(custom_list):
+ row_dict = {'column_{}'.format(col): val for col, val in enumerate(row)}
+ row_dict['row_num'] = row_num
+ outputs.append(row_dict)
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
diff --git a/playbooks/custom_functions/custom_list_value_in_strings.json b/playbooks/custom_functions/custom_list_value_in_strings.json
new file mode 100644
index 0000000000..34d25c78e6
--- /dev/null
+++ b/playbooks/custom_functions/custom_list_value_in_strings.json
@@ -0,0 +1,56 @@
+{
+ "create_time": "2021-09-20T17:42:46.572482+00:00",
+ "custom_function_id": "2ec78e71ee35dce744423a989e7efcaa0b17f51f",
+ "description": "Iterates through all items of a custom list to see if any list value (i.e. \"sample.com\") exists in the input you are comparing it to (i.e \"findme.sample.com\"). Returns a list of matches, a list of misses, a count of matches, and a count of misses.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "Name of the custom list. Every string in this list will be compared to see if it is a substring of any of the comparison_strings",
+ "input_type": "item",
+ "name": "custom_list",
+ "placeholder": "custom_list_name"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "String to use for comparison.",
+ "input_type": "list",
+ "name": "comparison_strings",
+ "placeholder": "comparison_strings"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "matches.*.match",
+ "description": "List of all items from the list that are substrings of any of the comparison strings"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "match_count",
+ "description": "Number of matches"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "misses.*.miss",
+ "description": "List of all items from the list that are not substrings of any of the comparison strings"
+ },
+ {
+ "contains_type": [],
+ "data_path": "miss_count",
+ "description": "Number of misses"
+ }
+ ],
+ "platform_version": "4.10.7.63984",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/custom_list_value_in_strings.py b/playbooks/custom_functions/custom_list_value_in_strings.py
new file mode 100644
index 0000000000..5974828243
--- /dev/null
+++ b/playbooks/custom_functions/custom_list_value_in_strings.py
@@ -0,0 +1,49 @@
+def custom_list_value_in_strings(custom_list=None, comparison_strings=None, **kwargs):
+ """
+ Iterates through all items of a custom list to see if any list value (i.e. "sample.com") exists in the input you are comparing it to (i.e "findme.sample.com"). Returns a list of matches, a list of misses, a count of matches, and a count of misses.
+
+ Args:
+ custom_list: Name of the custom list. Every string in this list will be compared to see if it is a substring of any of the comparison_strings
+ comparison_strings (CEF type: *): String to use for comparison.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ matches.*.match (CEF type: *): List of all items from the list that are substrings of any of the comparison strings
+ match_count: Number of matches
+ misses.*.miss (CEF type: *): List of all items from the list that are not substrings of any of the comparison strings
+ miss_count: Number of misses
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ # Get the custom list
+ success, message, this_list = phantom.get_list(list_name=custom_list)
+
+ # Create the lists to store matches and misses
+ matches = []
+ misses = []
+
+ # Loop through each comparison string
+ for comparison_string in comparison_strings:
+
+ # Loop through the custom list to see if any list value is found in the comparison string
+ for row in this_list:
+ for cell in row:
+ if comparison_string.find(cell) != -1:
+ matches.append({"match": cell})
+ else:
+ misses.append({"miss": cell})
+
+ # Prepare the outputs
+ match_count = len(matches)
+ miss_count = len(misses)
+ outputs = {
+ 'matches': matches,
+ 'match_count': match_count,
+ 'misses': misses,
+ 'miss_count': miss_count,
+ }
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
\ No newline at end of file
diff --git a/playbooks/custom_functions/datetime_modify.json b/playbooks/custom_functions/datetime_modify.json
new file mode 100644
index 0000000000..b5f4ffec40
--- /dev/null
+++ b/playbooks/custom_functions/datetime_modify.json
@@ -0,0 +1,66 @@
+{
+ "create_time": "2021-08-20T19:37:15.192987+00:00",
+ "custom_function_id": "1df6dfb4792ebd6ffca642caf7056300a16ce635",
+ "description": "Change a timestamp by adding or subtracting minutes, hours, or days.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "The datetime to modify, which should be provided in a string format determined by input_format_string",
+ "input_type": "item",
+ "name": "input_datetime",
+ "placeholder": "2020-06-27T14:53:08.219016Z"
+ },
+ {
+ "contains_type": [],
+ "description": "The format string to use for the input according to the Python's datetime.strptime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'. In addition to strptime() formats, the special format \"epoch\" can be used to accept unix epoch timestamps.",
+ "input_type": "item",
+ "name": "input_format_string",
+ "placeholder": "%Y-%m-%dT%H:%M:%S.%fZ"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "description": "Choose a unit to modify the date by, which must be either seconds, minutes, hours, or days. If none is provided the default will be 'minutes'",
+ "input_type": "item",
+ "name": "modification_unit",
+ "placeholder": "minutes"
+ },
+ {
+ "contains_type": [],
+ "description": "The number of seconds, minutes, hours, or days to add or subtract. Use a negative number such as -1.5 to subtract time. Defaults to zero.",
+ "input_type": "item",
+ "name": "amount_to_modify",
+ "placeholder": "0"
+ },
+ {
+ "contains_type": [],
+ "description": "The format string to use for the output according to the Python's datetime.strftime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'.",
+ "input_type": "item",
+ "name": "output_format_string",
+ "placeholder": "%Y-%m-%dT%H:%M:%S.%fZ"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [],
+ "data_path": "datetime_string",
+ "description": "The output datetime as formatted by the given output_format_string using Python's datetime.strftime()"
+ },
+ {
+ "contains_type": [],
+ "data_path": "epoch_time",
+ "description": "An integer representing the output time as a number of seconds since January 1 1970 assuming a naive UTC timezone. This is easier to use for comparisons to other epoch timestamps."
+ },
+ {
+ "contains_type": [],
+ "data_path": "seconds_modified",
+ "description": "The number of seconds (positive or negative) by which the input was modified"
+ }
+ ],
+ "platform_version": "4.10.6.61906",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/datetime_modify.py b/playbooks/custom_functions/datetime_modify.py
new file mode 100644
index 0000000000..259a16d012
--- /dev/null
+++ b/playbooks/custom_functions/datetime_modify.py
@@ -0,0 +1,92 @@
+def datetime_modify(input_datetime=None, input_format_string=None, modification_unit=None, amount_to_modify=None, output_format_string=None, **kwargs):
+ """
+ Change a timestamp by adding or subtracting minutes, hours, or days.
+
+ Args:
+ input_datetime: The datetime to modify, which should be provided in a string format determined by input_format_string
+ input_format_string: The format string to use for the input according to the Python's datetime.strptime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'. In addition to strptime() formats, the special format "epoch" can be used to accept unix epoch timestamps.
+ modification_unit: Choose a unit to modify the date by, which must be either seconds, minutes, hours, or days. If none is provided the default will be 'minutes'
+ amount_to_modify: The number of seconds, minutes, hours, or days to add or subtract. Use a negative number such as -1.5 to subtract time. Defaults to zero.
+ output_format_string: The format string to use for the output according to the Python's datetime.strftime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'.
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ datetime_string: The output datetime as formatted by the given output_format_string using Python's datetime.strftime()
+ epoch_time: An integer representing the output time as a number of seconds since January 1 1970 assuming a naive UTC timezone. This is easier to use for comparisons to other epoch timestamps.
+ seconds_modified: The number of seconds (positive or negative) by which the input was modified
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+ import datetime
+
+ outputs = {}
+
+ # set the input format string to the phantom default if none is provided
+ if not input_format_string:
+ input_format_string = "%Y-%m-%dT%H:%M:%S.%fZ"
+
+ # set the date to the default, which is the current time if none is provided
+ if not input_datetime:
+ input_datetime = datetime.datetime.now().strftime(input_format_string)
+
+ # use the phantom default as the output format string if none is provided
+ if not output_format_string:
+ output_format_string = "%Y-%m-%dT%H:%M:%S.%fZ"
+
+ if input_format_string.lower() == 'epoch':
+ parsed_input = datetime.datetime.utcfromtimestamp(int(input_datetime))
+ else:
+ parsed_input = datetime.datetime.strptime(input_datetime, input_format_string)
+ phantom.debug("parsed the input datetime as: {}".format(parsed_input))
+
+ # validate the modification_unit parameter, which must be a unit of time
+ if modification_unit == None:
+ modification_unit = 'minutes'
+ if modification_unit not in ['seconds', 'minutes', 'hours', 'days']:
+ raise ValueError('invalid modification_unit. must be either seconds, minutes, hours, or days.')
+
+ # amount_to_modify defaults to zero
+ if not amount_to_modify:
+ amount_to_modify = 0
+
+ # validate that amount_to_modify is an int or float (booleans will work as 0 or 1, but should not be used)
+ if not isinstance(amount_to_modify, int) and not isinstance(amount_to_modify, float):
+ raise ValueError('invalid amount_to_modify. must be an int or float')
+
+ # convert all time units to seconds
+ conversions = {
+ "seconds": 1,
+ "minutes": 60,
+ "hours": 60*60,
+ "days": 60*60*24
+ }
+ conversion_multiplier = conversions.get(modification_unit, None)
+ if not conversion_multiplier:
+ raise KeyError("failed to convert modification_unit to seconds")
+
+ seconds_to_modify = amount_to_modify * conversion_multiplier
+ if seconds_to_modify < 0:
+ phantom.debug("subtracting {} {} which is {} seconds".format(amount_to_modify * -1, modification_unit, seconds_to_modify * -1))
+ else:
+ phantom.debug("adding {} {} which is {} seconds".format(amount_to_modify, modification_unit, seconds_to_modify))
+
+ outputs['seconds_modified'] = seconds_to_modify
+ seconds_to_modify = datetime.timedelta(seconds=seconds_to_modify)
+
+ # do the actual modification
+ phantom.debug("adding {} plus {}".format(parsed_input, seconds_to_modify))
+ result_time = parsed_input + seconds_to_modify
+ phantom.debug("the unformatted result is: {}".format(result_time))
+
+ # use the provided output_format_string to turn the output into a string
+ string_output = result_time.strftime(output_format_string)
+ phantom.debug("the formatted result is: {}".format(string_output))
+ outputs['datetime_string'] = string_output
+
+ # also return an epoch time (seconds since Jan 1 1970) which assumes the input is a naive UTC datetime for time zone purposes
+ epoch_time = (result_time - datetime.datetime.utcfromtimestamp(0)).total_seconds()
+ outputs['epoch_time'] = epoch_time
+
+ # Return a JSON-serializable object
+ assert json.dumps(outputs) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return outputs
\ No newline at end of file
diff --git a/playbooks/custom_functions/debug.json b/playbooks/custom_functions/debug.json
new file mode 100644
index 0000000000..e514aefa3e
--- /dev/null
+++ b/playbooks/custom_functions/debug.json
@@ -0,0 +1,121 @@
+{
+ "create_time": "2021-04-28T19:54:35.225927+00:00",
+ "custom_function_id": "537aa035a6106bc6aeba14414631e2f17b7bc8bd",
+ "description": "Print debug messages with the type and value of 0-10 different inputs. This is useful for checking the values of input data or the outputs of other playbook blocks.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_1",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_2",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_3",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_4",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_5",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_6",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_7",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_8",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_9",
+ "placeholder": ""
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "",
+ "input_type": "list",
+ "name": "input_10",
+ "placeholder": ""
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [],
+ "data_path": "*.input_name",
+ "description": "The variable name used for this input, such as input_1 or input_7"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "*.value",
+ "description": "The string representation of the value of this input"
+ },
+ {
+ "contains_type": [
+ ""
+ ],
+ "data_path": "*.types",
+ "description": "The string representation of the type of this input, such as \"\""
+ }
+ ],
+ "platform_version": "4.10.3.51237",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/debug.py b/playbooks/custom_functions/debug.py
new file mode 100644
index 0000000000..abcb003301
--- /dev/null
+++ b/playbooks/custom_functions/debug.py
@@ -0,0 +1,40 @@
+def debug(input_1=None, input_2=None, input_3=None, input_4=None, input_5=None, input_6=None, input_7=None, input_8=None, input_9=None, input_10=None, **kwargs):
+ """
+ Print debug messages with the type and value of 0-10 different inputs. This is useful for checking the values of input data or the outputs of other playbook blocks.
+
+ Args:
+ input_1 (CEF type: *)
+ input_2 (CEF type: *)
+ input_3 (CEF type: *)
+ input_4 (CEF type: *)
+ input_5 (CEF type: *)
+ input_6 (CEF type: *)
+ input_7 (CEF type: *)
+ input_8 (CEF type: *)
+ input_9 (CEF type: *)
+ input_10 (CEF type: *)
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ *.input_name: The variable name used for this input, such as input_1 or input_7
+ *.value (CEF type: *): The string representation of the value of this input
+ *.types: The string representation of the type of this input, such as ""
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+
+ output = []
+ for index, input_value in enumerate([input_1, input_2, input_3, input_4, input_5, input_6, input_7, input_8, input_9, input_10]):
+ this_output = {}
+ phantom.debug("input_{}:".format(index+1))
+ this_output['input_name'] = "input_{}".format(index+1)
+ phantom.debug(" value: " + str(input_value))
+ this_output['value'] = str(input_value)
+ if isinstance(input_value, list):
+ list_item_types = str([type(list_item) for list_item in input_value])
+ phantom.debug(" types: " + list_item_types)
+ this_output['types'] = list_item_types
+ output.append(this_output)
+
+ assert json.dumps(output) # Will raise an exception if the :outputs: object is not JSON-serializable
+ return output
diff --git a/playbooks/custom_functions/find_related_containers.json b/playbooks/custom_functions/find_related_containers.json
new file mode 100644
index 0000000000..1ae234becf
--- /dev/null
+++ b/playbooks/custom_functions/find_related_containers.json
@@ -0,0 +1,118 @@
+{
+ "create_time": "2021-10-07T15:52:23.940165+00:00",
+ "custom_function_id": "24c4ef5ecd259674a07cd3c747f4223f09b5dd8f",
+ "description": "Takes a provided list of indicator values to search for and finds all related containers. It will produce a list of the related container details.",
+ "draft_mode": false,
+ "inputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "An indicator value to search on, such as a file hash or IP address. To search on all indicator values in the container, use \"*\".",
+ "input_type": "list",
+ "name": "value_list",
+ "placeholder": "*"
+ },
+ {
+ "contains_type": [
+ "*"
+ ],
+ "description": "The minimum number of similar indicator records that a container must have to be considered \"related.\" If no match count provided, this will default to 1.",
+ "input_type": "item",
+ "name": "minimum_match_count",
+ "placeholder": "1-100"
+ },
+ {
+ "contains_type": [
+ "phantom container id"
+ ],
+ "description": "The container to run indicator analysis against. Supports container object or container_id. This container will also be excluded from the results for related_containers.",
+ "input_type": "item",
+ "name": "container",
+ "placeholder": "container:id"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional modifier to only consider related containers within a time window. Default is -30d. Supports year (y), month (m), day (d), hour (h), or minute (m) Custom function will always set the earliest container window based on the input container \"create_time\".",
+ "input_type": "item",
+ "name": "earliest_time",
+ "placeholder": "-30d"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional comma-separated list of statuses to filter on. Only containers that have statuses matching an item in this list will be included.",
+ "input_type": "item",
+ "name": "filter_status",
+ "placeholder": "open"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional comma-separated list of labels to filter on. Only containers that have labels matching an item in this list will be included.",
+ "input_type": "item",
+ "name": "filter_label",
+ "placeholder": "events"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional comma-separated list of severities to filter on. Only containers that have severities matching an item in this list will be included.",
+ "input_type": "item",
+ "name": "filter_severity",
+ "placeholder": "medium"
+ },
+ {
+ "contains_type": [],
+ "description": "Optional parameter to filter containers that are in a case or not. Defaults to True (drop containers that are already in a case).",
+ "input_type": "item",
+ "name": "filter_in_case",
+ "placeholder": "True or False"
+ }
+ ],
+ "outputs": [
+ {
+ "contains_type": [
+ "*"
+ ],
+ "data_path": "*.container_id",
+ "description": "The unique id of the related container"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.container_indicator_match_count",
+ "description": "The number of indicators matched to the related container"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.container_status",
+ "description": "The status of the related container e.g. new, open, closed"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.container_type",
+ "description": "The type of the related container, e.g. default or case"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.container_name",
+ "description": "The name of the related container"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.in_case",
+ "description": "True or False if the related container is already included in a case"
+ },
+ {
+ "contains_type": [],
+ "data_path": "*.indicator_ids",
+ "description": "Indicator ID that matched"
+ },
+ {
+ "contains_type": [
+ "url"
+ ],
+ "data_path": "*.container_url",
+ "description": "Link to container"
+ }
+ ],
+ "platform_version": "5.0.1.66250",
+ "python_version": "3"
+}
\ No newline at end of file
diff --git a/playbooks/custom_functions/find_related_containers.py b/playbooks/custom_functions/find_related_containers.py
new file mode 100644
index 0000000000..749842d4dd
--- /dev/null
+++ b/playbooks/custom_functions/find_related_containers.py
@@ -0,0 +1,263 @@
+def find_related_containers(value_list=None, minimum_match_count=None, container=None, earliest_time=None, filter_status=None, filter_label=None, filter_severity=None, filter_in_case=None, **kwargs):
+ """
+ Takes a provided list of indicator values to search for and finds all related containers. It will produce a list of the related container details.
+
+ Args:
+ value_list (CEF type: *): An indicator value to search on, such as a file hash or IP address. To search on all indicator values in the container, use "*".
+ minimum_match_count (CEF type: *): The minimum number of similar indicator records that a container must have to be considered "related." If no match count provided, this will default to 1.
+ container (CEF type: phantom container id): The container to run indicator analysis against. Supports container object or container_id. This container will also be excluded from the results for related_containers.
+ earliest_time: Optional modifier to only consider related containers within a time window. Default is -30d. Supports year (y), month (m), day (d), hour (h), or minute (m) Custom function will always set the earliest container window based on the input container "create_time".
+ filter_status: Optional comma-separated list of statuses to filter on. Only containers that have statuses matching an item in this list will be included.
+ filter_label: Optional comma-separated list of labels to filter on. Only containers that have labels matching an item in this list will be included.
+ filter_severity: Optional comma-separated list of severities to filter on. Only containers that have severities matching an item in this list will be included.
+ filter_in_case: Optional parameter to filter containers that are in a case or not. Defaults to True (drop containers that are already in a case).
+
+ Returns a JSON-serializable object that implements the configured data paths:
+ *.container_id (CEF type: *): The unique id of the related container
+ *.container_indicator_match_count: The number of indicators matched to the related container
+ *.container_status: The status of the related container e.g. new, open, closed
+ *.container_type: The type of the related container, e.g. default or case
+ *.container_name: The name of the related container
+ *.in_case: True or False if the related container is already included in a case
+ *.indicator_ids: Indicator ID that matched
+ *.container_url (CEF type: url): Link to container
+ """
+ ############################ Custom Code Goes Below This Line #################################
+ import json
+ import phantom.rules as phantom
+ import re
+ from datetime import datetime, timedelta
+ from urllib import parse
+
+ outputs = []
+ related_containers = []
+ indicator_id_dictionary = {}
+ container_dictionary = {}
+ offset_time = None
+
+ base_url = phantom.get_base_url()
+ indicator_by_value_url = phantom.build_phantom_rest_url('indicator_by_value')
+ indicator_common_container_url = phantom.build_phantom_rest_url('indicator_common_container')
+ container_url = phantom.build_phantom_rest_url('container')
+
+ # Get indicator ids based on value_list
+ def format_offset_time(seconds):
+ datetime_obj = datetime.now() - timedelta(seconds=seconds)
+ formatted_time = datetime_obj.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
+ return formatted_time
+
+ def fetch_indicator_ids(value_list):
+ indicator_id_list = []
+ for value in value_list:
+ params = {'indicator_value': f'{value}', 'timerange': 'all'}
+ indicator_id = phantom.requests.get(indicator_by_value_url, params=params, verify=False).json().get('id')
+ if indicator_id:
+ indicator_id_list.append(indicator_id)
+ return indicator_id_list
+
+ # Ensure valid time modifier
+ if earliest_time:
+ # convert user-provided input to seconds
+ char_lookup = {'y': 31557600, 'mon': 2592000, 'w': 604800, 'd': 86400, 'h': 3600, 'm': 60}
+ pattern = re.compile(r'-(\d+)([mM][oO][nN]|[yYwWdDhHmM]{1})$')
+ if re.search(pattern, earliest_time):
+ integer, char = (re.findall(pattern, earliest_time)[0])
+ time_in_seconds = int(integer) * char_lookup[char.lower()]
+ else:
+ raise RuntimeError(f'earliest_time string "{earliest_time}" is incorrectly formatted. Format is -