diff --git a/playbooks/AD_LDAP_Account_Locking.json b/playbooks/AD_LDAP_Account_Locking.json index 4f444bee1a..83a81d777f 100644 --- a/playbooks/AD_LDAP_Account_Locking.json +++ b/playbooks/AD_LDAP_Account_Locking.json @@ -52,7 +52,7 @@ "targetPort": "4_in" } ], - "hash": "e2151613eb48da444660dc3d67d4f817f1f0dc67", + "hash": "732595dc155a58ef5d12b3104904aa7b3237d745", "nodes": { "0": { "data": { @@ -67,8 +67,8 @@ "id": "0", "type": "start", "warnings": {}, - "x": 20, - "y": 0 + "x": 19.999999999999986, + "y": -6.394884621840902e-14 }, "1": { "data": { @@ -91,6 +91,8 @@ "advanced": { "customName": "username filter", "customNameId": 0, + "delimiter": ",", + "delimiter_enabled": true, "description": "Filter user name inputs to route inputs to appropriate actions.", "join": [], "note": "Filter user name inputs to route inputs to appropriate actions." @@ -118,11 +120,7 @@ "errors": {}, "id": "2", "type": "filter", - "warnings": { - "config": [ - "Reconfigure invalid datapath." - ] - }, + "warnings": {}, "x": 60, "y": 140 }, @@ -205,6 +203,8 @@ "advanced": { "customName": "filter disable account", "customNameId": 0, + "delimiter": ",", + "delimiter_enabled": true, "description": "filter check if the user is disabled successfully.", "join": [], "note": "filter check if the user is disabled successfully." @@ -262,10 +262,10 @@ ], "playbook_type": "data", "python_version": "3", - "schema": "5.0.9", - "version": "6.0.0.114895" + "schema": "5.0.10", + "version": "6.0.1.123902" }, - "create_time": "2023-05-25T08:14:08.217934+00:00", + "create_time": "2023-08-17T18:46:35.895213+00:00", "draft_mode": false, "labels": [ "*" @@ -274,6 +274,7 @@ "user", "microsoft_ad_ldap", "disable_account", - "D3-AL" + "D3-AL", + "active_directory" ] } \ No newline at end of file diff --git a/playbooks/AD_LDAP_Account_Locking.py b/playbooks/AD_LDAP_Account_Locking.py index 2dfa8e10a4..9465838c8f 100644 --- a/playbooks/AD_LDAP_Account_Locking.py +++ b/playbooks/AD_LDAP_Account_Locking.py @@ -31,7 +31,8 @@ def username_filter(action=None, success=None, container=None, results=None, han conditions=[ ["playbook_input:user", "!=", ""] ], - name="username_filter:condition_1") + name="username_filter:condition_1", + delimiter=",") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: @@ -136,7 +137,8 @@ def filter_disable_account(action=None, success=None, container=None, results=No conditions=[ ["disable_user_account:action_result.status", "==", "success"] ], - name="filter_disable_account:condition_1") + name="filter_disable_account:condition_1", + delimiter=",") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: diff --git a/playbooks/Active_Directory_Disable_Account_Dispatch.json b/playbooks/Active_Directory_Disable_Account_Dispatch.json index 43221eeb2b..1a882e29d0 100644 --- a/playbooks/Active_Directory_Disable_Account_Dispatch.json +++ b/playbooks/Active_Directory_Disable_Account_Dispatch.json @@ -6,37 +6,6 @@ "data": { "description": "Accepts user name that needs to be disabled in Active Directory. Generates a report and observable output based on the status of account locking or disabling.", "edges": [ - { - "id": "port_0_to_port_5", - "sourceNode": "0", - "sourcePort": "0_out", - "targetNode": "5", - "targetPort": "5_in" - }, - { - "conditions": [ - { - "index": 0 - } - ], - "id": "port_5_to_port_3", - "sourceNode": "5", - "sourcePort": "5_out", - "targetNode": "3", - "targetPort": "3_in" - }, - { - "conditions": [ - { - "index": 1 - } - ], - "id": "port_5_to_port_6", - "sourceNode": "5", - "sourcePort": "5_out", - "targetNode": "6", - "targetPort": "6_in" - }, { "id": "port_3_to_port_7", "sourceNode": "3", @@ -44,18 +13,6 @@ "targetNode": "7", "targetPort": "7_in" }, - { - "conditions": [ - { - "index": 0 - } - ], - "id": "port_7_to_port_8", - "sourceNode": "7", - "sourcePort": "7_out", - "targetNode": "8", - "targetPort": "8_in" - }, { "conditions": [ { @@ -95,9 +52,40 @@ "sourcePort": "12_out", "targetNode": "1", "targetPort": "1_in" + }, + { + "id": "port_0_to_port_3", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "3", + "targetPort": "3_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_13_to_port_8", + "sourceNode": "13", + "sourcePort": "13_out", + "targetNode": "8", + "targetPort": "8_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_7_to_port_13", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "13", + "targetPort": "13_in" } ], - "hash": "cebfbea38189615536f82a870827b8ef1ede2890", + "hash": "3268ee70fd0ab575e5b7d055b3420d043f661155", "nodes": { "0": { "data": { @@ -112,7 +100,7 @@ "id": "0", "type": "start", "warnings": {}, - "x": 360, + "x": 160, "y": -6.394884621840902e-14 }, "1": { @@ -128,7 +116,7 @@ "id": "1", "type": "end", "warnings": {}, - "x": 19.999999999999986, + "x": 300, "y": 1414 }, "10": { @@ -154,7 +142,7 @@ "type": "format", "userCode": "\n # Write your custom code here...\n #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"merge_report\"))\n", "warnings": {}, - "x": 0, + "x": 280, "y": 880 }, "11": { @@ -233,7 +221,7 @@ "id": "11", "type": "utility", "warnings": {}, - "x": 0, + "x": 280, "y": 1058 }, "12": { @@ -352,8 +340,44 @@ "id": "12", "type": "utility", "warnings": {}, - "x": 0, - "y": 1240 + "x": 280, + "y": 1236 + }, + "13": { + "data": { + "advanced": { + "customName": "observable filter", + "customNameId": 0, + "description": "Filter to check if observable output is successfully generated or not.", + "join": [], + "note": "Filter to check if observable output is successfully generated or not." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "dispatch_account_disable:playbook_output:observable", + "value": "" + } + ], + "conditionIndex": 0, + "customName": "observable_exist", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "observable_filter", + "id": "13", + "type": "filter" + }, + "errors": {}, + "id": "13", + "type": "filter", + "warnings": {}, + "x": 340, + "y": 499 }, "3": { "data": { @@ -384,7 +408,8 @@ }, "playbook_tags": { "datapaths": [ - "disable_account" + "disable_account", + "active_directory" ], "deduplicate": false } @@ -400,136 +425,19 @@ "id": "3", "type": "playbook", "warnings": {}, - "x": 170, - "y": 334.99999999999994 - }, - "5": { - "data": { - "advanced": { - "customName": "username filter", - "customNameId": 0, - "description": "Filter user name inputs to route inputs to appropriate actions.", - "join": [], - "note": "Filter user name inputs to route inputs to appropriate actions." - }, - "conditions": [ - { - "comparisons": [ - { - "conditionIndex": 0, - "op": "!=", - "param": "artifact:*.cef.act", - "value": "" - } - ], - "conditionIndex": 0, - "customName": "username_exist", - "display": "If", - "logic": "and", - "type": "if" - }, - { - "comparisons": [ - { - "conditionIndex": 1, - "op": "==", - "param": "", - "value": "" - } - ], - "conditionIndex": 1, - "customName": "username_not_exist", - "display": "Else", - "logic": "and", - "type": "else" - } - ], - "functionId": 1, - "functionName": "username_filter", - "id": "5", - "type": "decision" - }, - "errors": {}, - "id": "5", - "type": "decision", - "warnings": {}, - "x": 420, - "y": 148 - }, - "6": { - "data": { - "advanced": { - "customName": "artifacts check comment", - "customNameId": 0, - "description": "no valid username or user principal name artifacts input", - "join": [], - "note": "no valid username or user principal name artifacts input" - }, - "functionId": 1, - "functionName": "artifacts_check_comment", - "id": "6", - "selectMore": false, - "tab": "apis", - "type": "utility", - "utilities": { - "comment": { - "description": "", - "fields": [ - { - "description": "", - "label": "comment", - "name": "comment", - "placeholder": "Enter a comment", - "renderType": "datapath", - "required": true - }, - { - "hidden": true, - "name": "container", - "required": false - }, - { - "hidden": true, - "name": "author", - "required": false - }, - { - "hidden": true, - "name": "trace", - "required": false - } - ], - "label": "add comment", - "name": "comment" - } - }, - "utilityType": "api", - "values": { - "comment": { - "_internal": [ - "container", - "author", - "trace" - ], - "comment": "no valid username or user principal name artifacts input" - } - } - }, - "errors": {}, - "id": "6", - "type": "utility", - "warnings": {}, - "x": 510, - "y": 328 + "x": 140, + "y": 147.99999999999997 }, "7": { "data": { "advanced": { - "customName": "observable output filter", + "customName": "observable output decision", "customNameId": 0, - "description": "Filter to check if observable output is successfully generated or not.", + "delimiter": ",", + "delimiter_enabled": true, + "description": "decision to check if observable output is successfully generated or not.", "join": [], - "note": "Filter to check if observable output is successfully generated or not." + "note": "decision to check if observable output is successfully generated or not." }, "conditions": [ { @@ -564,7 +472,7 @@ } ], "functionId": 2, - "functionName": "observable_output_filter", + "functionName": "observable_output_decision", "id": "7", "type": "decision" }, @@ -572,8 +480,8 @@ "id": "7", "type": "decision", "warnings": {}, - "x": 250, - "y": 506 + "x": 220, + "y": 312 }, "8": { "data": { @@ -588,7 +496,7 @@ "functionName": "normalized_observable_filter", "id": "8", "inputParameters": [ - "dispatch_account_disable:playbook_output:observable" + "filtered-data:observable_filter:condition_1:dispatch_account_disable:playbook_output:observable" ], "outputVariables": [ "observable_value", @@ -600,10 +508,10 @@ "errors": {}, "id": "8", "type": "code", - "userCode": "\n # Write your custom code here...\n normalized_observable_filter__observable_message = []\n normalized_observable_filter__observable_value = []\n normalized_observable_filter__observable_merge_report = []\n fmt_output = \"\"\n output_observable_values = [(i or \"\") for i in dispatch_account_disable_output_observable_values]\n \n #phantom.debug(\"output_observable_values: {}\".format(output_observable_values))\n for observable_item in output_observable_values:\n if observable_item['status'] == \"success\":\n user_name = observable_item['value'].split(\"@\")[0]\n normalized_observable_filter__observable_value.append(user_name)\n fmt_output += \"{} | {} | {} | {} | \\n\".format(observable_item['value'], observable_item['type'], observable_item['message'], observable_item['status'])\n normalized_observable_filter__observable_merge_report.append(fmt_output)\n normalized_observable_filter__observable_value = normalized_observable_filter__observable_value[0]\n normalized_observable_filter__observable_type = \"Disable Account\"\n #phantom.debug(normalized_observable_filter__observable_merge_report)\n", + "userCode": "\n # Write your custom code here...\n normalized_observable_filter__observable_message = []\n normalized_observable_filter__observable_value = []\n normalized_observable_filter__observable_merge_report = []\n fmt_output = \"\"\n output_observable_values = [(i or \"\") for i in filtered_output_0_dispatch_account_disable_output_observable_values]\n \n #phantom.debug(\"output_observable_values: {}\".format(output_observable_values))\n for observable_item in output_observable_values:\n if observable_item['status'] == \"success\":\n user_name = observable_item['value'].split(\"@\")[0]\n normalized_observable_filter__observable_value.append(user_name)\n fmt_output += \"{} | {} | {} | {} | \\n\".format(observable_item['value'], observable_item['type'], observable_item['message'], observable_item['status'])\n normalized_observable_filter__observable_merge_report.append(fmt_output)\n normalized_observable_filter__observable_value = normalized_observable_filter__observable_value[0]\n normalized_observable_filter__observable_type = \"Disable Account\"\n #phantom.debug(normalized_observable_filter__observable_merge_report)\n", "warnings": {}, - "x": 0, - "y": 680 + "x": 280, + "y": 686 }, "9": { "data": { @@ -660,7 +568,7 @@ "author", "trace" ], - "comment": "observable output of input playbooks not exits." + "comment": "Observable output of input playbooks does not exist." } } }, @@ -668,8 +576,8 @@ "id": "9", "type": "utility", "warnings": {}, - "x": 340, - "y": 686 + "x": 0, + "y": 492 } }, "notes": "Inputs: users\nActions: Account Locking/Disabling\nOutputs: reports, observables" @@ -678,10 +586,10 @@ "output_spec": null, "playbook_type": "automation", "python_version": "3", - "schema": "5.0.9", - "version": "6.0.0.114895" + "schema": "5.0.10", + "version": "6.0.1.123902" }, - "create_time": "2023-05-22T11:02:19.665263+00:00", + "create_time": "2023-08-17T18:44:17.675610+00:00", "draft_mode": false, "labels": [ "*" @@ -692,6 +600,6 @@ "disable_account", "azure_ad_graph", "microsoft_ad_ldap", - "aws_iam" + "active_directory" ] } \ No newline at end of file diff --git a/playbooks/Active_Directory_Disable_Account_Dispatch.png b/playbooks/Active_Directory_Disable_Account_Dispatch.png index 047ad681ba..a69f2b8da8 100644 Binary files a/playbooks/Active_Directory_Disable_Account_Dispatch.png and b/playbooks/Active_Directory_Disable_Account_Dispatch.png differ diff --git a/playbooks/Active_Directory_Disable_Account_Dispatch.py b/playbooks/Active_Directory_Disable_Account_Dispatch.py index 700c849343..5488a2f55d 100644 --- a/playbooks/Active_Directory_Disable_Account_Dispatch.py +++ b/playbooks/Active_Directory_Disable_Account_Dispatch.py @@ -12,8 +12,8 @@ from datetime import datetime, timedelta def on_start(container): phantom.debug('on_start() called') - # call 'username_filter' block - username_filter(container=container) + # call 'dispatch_account_disable' block + dispatch_account_disable(container=container) return @@ -21,9 +21,11 @@ def on_start(container): def dispatch_account_disable(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): phantom.debug("dispatch_account_disable() called") + playbook_tags_combined_value = phantom.concatenate("disable_account", "active_directory") + inputs = { "playbook_repo": [], - "playbook_tags": ["disable_account"], + "playbook_tags": playbook_tags_combined_value, "artifact_ids_include": [], "indicator_tags_exclude": [], "indicator_tags_include": [], @@ -40,66 +42,17 @@ def dispatch_account_disable(action=None, success=None, container=None, results= ################################################################################ # call playbook "community/dispatch_input_playbooks", returns the playbook_run_id - playbook_run_id = phantom.playbook("community/dispatch_input_playbooks", container=container, name="dispatch_account_disable", callback=observable_output_filter, inputs=inputs) + playbook_run_id = phantom.playbook("community/dispatch_input_playbooks", container=container, name="dispatch_account_disable", callback=observable_output_decision, inputs=inputs) return @phantom.playbook_block() -def username_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("username_filter() called") +def observable_output_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("observable_output_decision() called") ################################################################################ - # Filter user name inputs to route inputs to appropriate actions. - ################################################################################ - - # check for 'if' condition 1 - found_match_1 = phantom.decision( - container=container, - conditions=[ - ["artifact:*.cef.act", "!=", ""] - ]) - - # call connected blocks if condition 1 matched - if found_match_1: - dispatch_account_disable(action=action, success=success, container=container, results=results, handle=handle) - return - - # check for 'else' condition 2 - artifacts_check_comment(action=action, success=success, container=container, results=results, handle=handle) - - return - - -@phantom.playbook_block() -def artifacts_check_comment(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("artifacts_check_comment() called") - - ################################################################################ - # no valid username or user principal name artifacts input - ################################################################################ - - ################################################################################ - ## Custom Code Start - ################################################################################ - - # Write your custom code here... - - ################################################################################ - ## Custom Code End - ################################################################################ - - phantom.comment(container=container, comment="no valid username or user principal name artifacts input") - - return - - -@phantom.playbook_block() -def observable_output_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): - phantom.debug("observable_output_filter() called") - - ################################################################################ - # Filter to check if observable output is successfully generated or not. + # decision to check if observable output is successfully generated or not. ################################################################################ # check for 'if' condition 1 @@ -107,11 +60,12 @@ def observable_output_filter(action=None, success=None, container=None, results= container=container, conditions=[ ["dispatch_account_disable:playbook_output:observable", "!=", ""] - ]) + ], + delimiter=",") # call connected blocks if condition 1 matched if found_match_1: - normalized_observable_filter(action=action, success=success, container=container, results=results, handle=handle) + observable_filter(action=action, success=success, container=container, results=results, handle=handle) return # check for 'else' condition 2 @@ -130,9 +84,9 @@ def normalized_observable_filter(action=None, success=None, container=None, resu # types of disable_account used to locked users in active directory. ################################################################################ - dispatch_account_disable_output_observable = phantom.collect2(container=container, datapath=["dispatch_account_disable:playbook_output:observable"]) + filtered_output_0_dispatch_account_disable_output_observable = phantom.collect2(container=container, datapath=["filtered-data:observable_filter:condition_1:dispatch_account_disable:playbook_output:observable"]) - dispatch_account_disable_output_observable_values = [item[0] for item in dispatch_account_disable_output_observable] + filtered_output_0_dispatch_account_disable_output_observable_values = [item[0] for item in filtered_output_0_dispatch_account_disable_output_observable] normalized_observable_filter__observable_value = None normalized_observable_filter__observable_type = None @@ -147,7 +101,7 @@ def normalized_observable_filter(action=None, success=None, container=None, resu normalized_observable_filter__observable_value = [] normalized_observable_filter__observable_merge_report = [] fmt_output = "" - output_observable_values = [(i or "") for i in dispatch_account_disable_output_observable_values] + output_observable_values = [(i or "") for i in filtered_output_0_dispatch_account_disable_output_observable_values] #phantom.debug("output_observable_values: {}".format(output_observable_values)) for observable_item in output_observable_values: @@ -190,7 +144,7 @@ def observable_check_comment(action=None, success=None, container=None, results= ## Custom Code End ################################################################################ - phantom.comment(container=container, comment="observable output of input playbooks not exits.") + phantom.comment(container=container, comment="Observable output of input playbooks does not exist.") return @@ -298,6 +252,30 @@ def update_workbook_task(action=None, success=None, container=None, results=None return +@phantom.playbook_block() +def observable_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("observable_filter() called") + + ################################################################################ + # Filter to check if observable output is successfully generated or not. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["dispatch_account_disable:playbook_output:observable", "!=", ""] + ], + name="observable_filter:condition_1", + delimiter=None) + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + normalized_observable_filter(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + @phantom.playbook_block() def on_finish(container, summary): phantom.debug("on_finish() called") diff --git a/playbooks/Azure_AD_Account_Locking.json b/playbooks/Azure_AD_Account_Locking.json index 6b9a92df22..29c3415252 100644 --- a/playbooks/Azure_AD_Account_Locking.json +++ b/playbooks/Azure_AD_Account_Locking.json @@ -52,7 +52,7 @@ "targetPort": "4_in" } ], - "hash": "76828347e693a60201c3b9342e6f493ee5253566", + "hash": "6c58fabb2330bc8e95deed79637e55071609c19c", "nodes": { "0": { "data": { @@ -68,7 +68,7 @@ "type": "start", "warnings": {}, "x": 19.999999999999986, - "y": -3.197442310920451e-13 + "y": -3.836930773104541e-13 }, "1": { "data": { @@ -91,6 +91,8 @@ "advanced": { "customName": "user name filter", "customNameId": 0, + "delimiter": ",", + "delimiter_enabled": true, "description": "Filter user name inputs to route inputs to appropriate actions.", "join": [], "note": "Filter user name inputs to route inputs to appropriate actions." @@ -118,11 +120,7 @@ "errors": {}, "id": "2", "type": "filter", - "warnings": { - "config": [ - "Reconfigure invalid datapath." - ] - }, + "warnings": {}, "x": 60, "y": 140 }, @@ -199,6 +197,8 @@ "advanced": { "customName": "filter disable result", "customNameId": 0, + "delimiter": ",", + "delimiter_enabled": true, "description": "filter check if the user is disabled successfully.", "join": [], "note": "filter check if the user is disabled successfully." @@ -257,10 +257,10 @@ ], "playbook_type": "data", "python_version": "3", - "schema": "5.0.9", - "version": "6.0.0.114895" + "schema": "5.0.10", + "version": "6.0.1.123902" }, - "create_time": "2023-05-25T07:40:09.337037+00:00", + "create_time": "2023-08-17T18:47:08.503246+00:00", "draft_mode": false, "labels": [ "*" @@ -269,6 +269,7 @@ "user", "azure_ad_graph", "disable_account", - "D3-AL" + "D3-AL", + "active_directory" ] } \ No newline at end of file diff --git a/playbooks/Azure_AD_Account_Locking.py b/playbooks/Azure_AD_Account_Locking.py index 725e08f17f..99c830990d 100644 --- a/playbooks/Azure_AD_Account_Locking.py +++ b/playbooks/Azure_AD_Account_Locking.py @@ -31,7 +31,8 @@ def user_name_filter(action=None, success=None, container=None, results=None, ha conditions=[ ["playbook_input:user", "!=", ""] ], - name="user_name_filter:condition_1") + name="user_name_filter:condition_1", + delimiter=",") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: @@ -131,7 +132,8 @@ def filter_disable_result(action=None, success=None, container=None, results=Non conditions=[ ["disable_user_account:action_result.status", "==", "success"] ], - name="filter_disable_result:condition_1") + name="filter_disable_result:condition_1", + delimiter=",") # call connected blocks if filtered artifacts or results if matched_artifacts_1 or matched_results_1: