diff --git a/ReversingLabs_Reported_Email_Triage.json b/ReversingLabs_Reported_Email_Triage.json new file mode 100644 index 0000000..1e21216 --- /dev/null +++ b/ReversingLabs_Reported_Email_Triage.json @@ -0,0 +1,364 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Phishing", + "coa": { + "data": { + "description": "", + "edges": [ + { + "id": "port_10_to_port_12", + "sourceNode": "10", + "sourcePort": "10_out", + "targetNode": "12", + "targetPort": "12_in" + }, + { + "id": "port_12_to_port_13", + "sourceNode": "12", + "sourcePort": "12_out", + "targetNode": "13", + "targetPort": "13_in" + }, + { + "id": "port_13_to_port_15", + "sourceNode": "13", + "sourcePort": "13_out", + "targetNode": "15", + "targetPort": "15_in" + }, + { + "id": "port_15_to_port_1", + "sourceNode": "15", + "sourcePort": "15_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_0_to_port_16", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "16", + "targetPort": "16_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_16_to_port_10", + "sourceNode": "16", + "sourcePort": "16_out", + "targetNode": "10", + "targetPort": "10_in" + } + ], + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": { + "input_spec": [ + { + "name": "Name is required" + } + ] + }, + "id": "0", + "type": "start", + "warnings": {}, + "x": 20, + "y": 0 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 20, + "y": 888 + }, + "10": { + "data": { + "action": "run query", + "actionType": "investigate", + "advanced": { + "join": [] + }, + "connector": "MS Graph for Office 365", + "connectorConfigs": [ + "o365_rldevelopment" + ], + "connectorId": "0a0a4087-10e8-4c96-9872-b740ff26d8bb", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "run_query_1", + "id": "10", + "loop": { + "enabled": false, + "exitAfterUnit": "m", + "exitAfterValue": 10, + "exitConditionEnabled": false, + "exitLoopAfter": 2, + "pauseUnit": "m", + "pauseValue": 2 + }, + "parameters": { + "email_address": "secops@company.com", + "folder": "Inbox", + "get_folder_id": true, + "limit": "1", + "query": { + "functionId": 1, + "parameters": [ + "filtered-data:filter_2:condition_1:artifact:*.cef.evidence.1.networkMessageId" + ], + "template": "$filter=contains(subject, '{0}')" + }, + "subject": "" + }, + "requiredParameters": [ + { + "data_type": "string", + "default": "Inbox", + "field": "folder" + }, + { + "data_type": "string", + "field": "email_address" + }, + { + "data_type": "boolean", + "default": true, + "field": "get_folder_id" + } + ], + "type": "action" + }, + "errors": {}, + "id": "10", + "type": "action", + "warnings": {}, + "x": 0, + "y": 296 + }, + "12": { + "data": { + "action": "get email", + "actionType": "investigate", + "advanced": { + "join": [] + }, + "connector": "MS Graph for Office 365", + "connectorConfigs": [ + "o365_rldevelopment" + ], + "connectorId": "0a0a4087-10e8-4c96-9872-b740ff26d8bb", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_email_1", + "id": "12", + "loop": { + "enabled": false, + "exitAfterUnit": "m", + "exitAfterValue": 10, + "exitConditionEnabled": false, + "exitLoopAfter": 2, + "pauseUnit": "m", + "pauseValue": 2 + }, + "parameters": { + "download_attachments": true, + "download_email": false, + "email_address": "secops@company.com", + "id": "run_query_1:action_result.data.*.id" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "id" + }, + { + "data_type": "string", + "field": "email_address" + } + ], + "type": "action" + }, + "errors": {}, + "id": "12", + "type": "action", + "warnings": {}, + "x": 0, + "y": 440 + }, + "13": { + "data": { + "action": "detonate file", + "actionType": "investigate", + "advanced": { + "join": [] + }, + "connector": "Reversinglabs A1000 v2", + "connectorConfigs": [ + "a1000-techalc1" + ], + "connectorId": "3b35341f-c26b-490d-9802-82b23d5524c0", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "detonate_file_1", + "id": "13", + "loop": { + "enabled": false, + "exitAfterUnit": "m", + "exitAfterValue": 10, + "exitConditionEnabled": false, + "exitLoopAfter": 2, + "pauseUnit": "m", + "pauseValue": 2 + }, + "parameters": { + "file_name": "get_email_1:action_result.data.*.attachments.*.name", + "vault_id": "get_email_1:action_result.data.*.attachments.*.vaultId" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "vault_id" + } + ], + "type": "action" + }, + "errors": {}, + "id": "13", + "type": "action", + "warnings": {}, + "x": 0, + "y": 592 + }, + "15": { + "data": { + "action": "get summary report", + "actionType": "generic", + "advanced": { + "join": [] + }, + "connector": "Reversinglabs A1000 v2", + "connectorConfigs": [ + "a1000-techalc1" + ], + "connectorId": "3b35341f-c26b-490d-9802-82b23d5524c0", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "get_summary_report_1", + "id": "15", + "loop": { + "enabled": false, + "exitAfterUnit": "m", + "exitAfterValue": 10, + "exitConditionEnabled": false, + "exitLoopAfter": 2, + "pauseUnit": "m", + "pauseValue": 2 + }, + "parameters": { + "hash": "detonate_file_1:action_result.parameter.vault_id", + "include_network_threat_intelligence": true, + "retry": true, + "skip_reanalysis": true + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "hash" + }, + { + "data_type": "boolean", + "default": true, + "field": "retry" + }, + { + "data_type": "boolean", + "default": true, + "field": "include_network_threat_intelligence" + } + ], + "type": "action" + }, + "errors": {}, + "id": "15", + "type": "action", + "warnings": {}, + "x": 0, + "y": 740 + }, + "16": { + "data": { + "advanced": { + "join": [] + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "==", + "param": "artifact:*.name", + "value": "Email reported by user as malware or phish" + } + ], + "conditionIndex": 0, + "customName": "Filter alert details artifact", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "filter_2", + "id": "16", + "type": "filter" + }, + "errors": {}, + "id": "16", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 120 + } + }, + "notes": "", + "origin": { + "playbook_id": 202, + "playbook_name": "RL - Email Triage", + "playbook_repo_id": 2, + "playbook_repo_name": "local" + } + }, + "input_spec": null, + "output_spec": null, + "playbook_type": "automation", + "python_version": "3", + "schema": "5.0.11", + "version": "6.2.0.355" + }, + "create_time": "2024-09-26T03:07:45.818610+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [] +} \ No newline at end of file diff --git a/ReversingLabs_Reported_Email_Triage.png b/ReversingLabs_Reported_Email_Triage.png new file mode 100644 index 0000000..9f7b8e6 Binary files /dev/null and b/ReversingLabs_Reported_Email_Triage.png differ diff --git a/ReversingLabs_Reported_Email_Triage.py b/ReversingLabs_Reported_Email_Triage.py new file mode 100644 index 0000000..6e495a1 --- /dev/null +++ b/ReversingLabs_Reported_Email_Triage.py @@ -0,0 +1,204 @@ +""" + +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'filter_2' block + filter_2(container=container) + + return + +@phantom.playbook_block() +def run_query_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, loop_state_json=None, **kwargs): + phantom.debug("run_query_1() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + query_formatted_string = phantom.format( + container=container, + template="""$filter=contains(subject, '{0}')""", + parameters=[ + "filtered-data:filter_2:condition_1:artifact:*.cef.evidence.1.networkMessageId" + ]) + + filtered_artifact_0_data_filter_2 = phantom.collect2(container=container, datapath=["filtered-data:filter_2:condition_1:artifact:*.cef.evidence.1.networkMessageId","filtered-data:filter_2:condition_1:artifact:*.id"]) + + parameters = [] + + # build parameters list for 'run_query_1' call + for filtered_artifact_0_item_filter_2 in filtered_artifact_0_data_filter_2: + parameters.append({ + "folder": "Inbox", + "get_folder_id": True, + "email_address": "secops@company.com", + "subject": "", + "query": query_formatted_string, + "limit": 1, + "context": {'artifact_id': filtered_artifact_0_item_filter_2[1]}, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("run query", parameters=parameters, name="run_query_1", assets=["o365_rldevelopment"], callback=get_email_1) + + return + + +@phantom.playbook_block() +def get_email_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, loop_state_json=None, **kwargs): + phantom.debug("get_email_1() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + run_query_1_result_data = phantom.collect2(container=container, datapath=["run_query_1:action_result.data.*.id","run_query_1:action_result.parameter.context.artifact_id"], action_results=results) + + parameters = [] + + # build parameters list for 'get_email_1' call + for run_query_1_result_item in run_query_1_result_data: + if run_query_1_result_item[0] is not None: + parameters.append({ + "id": run_query_1_result_item[0], + "email_address": "secops@company.com", + "download_attachments": True, + "download_email": False, + "context": {'artifact_id': run_query_1_result_item[1]}, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("get email", parameters=parameters, name="get_email_1", assets=["o365_rldevelopment"], callback=detonate_file_1) + + return + + +@phantom.playbook_block() +def detonate_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, loop_state_json=None, **kwargs): + phantom.debug("detonate_file_1() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + get_email_1_result_data = phantom.collect2(container=container, datapath=["get_email_1:action_result.data.*.attachments.*.vaultId","get_email_1:action_result.data.*.attachments.*.name","get_email_1:action_result.parameter.context.artifact_id"], action_results=results) + + parameters = [] + + # build parameters list for 'detonate_file_1' call + for get_email_1_result_item in get_email_1_result_data: + if get_email_1_result_item[0] is not None: + parameters.append({ + "vault_id": get_email_1_result_item[0], + "file_name": get_email_1_result_item[1], + "context": {'artifact_id': get_email_1_result_item[2]}, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("detonate file", parameters=parameters, name="detonate_file_1", assets=["a1000-techalc1"], callback=get_summary_report_1) + + return + + +@phantom.playbook_block() +def get_summary_report_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, loop_state_json=None, **kwargs): + phantom.debug("get_summary_report_1() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + detonate_file_1_result_data = phantom.collect2(container=container, datapath=["detonate_file_1:action_result.parameter.vault_id","detonate_file_1:action_result.parameter.context.artifact_id"], action_results=results) + + parameters = [] + + # build parameters list for 'get_summary_report_1' call + for detonate_file_1_result_item in detonate_file_1_result_data: + if detonate_file_1_result_item[0] is not None: + parameters.append({ + "retry": True, + "include_network_threat_intelligence": True, + "hash": detonate_file_1_result_item[0], + "skip_reanalysis": True, + "context": {'artifact_id': detonate_file_1_result_item[1]}, + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("get summary report", parameters=parameters, name="get_summary_report_1", assets=["a1000-techalc1"]) + + return + + +@phantom.playbook_block() +def filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, loop_state_json=None, **kwargs): + phantom.debug("filter_2() called") + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["artifact:*.name", "==", "Email reported by user as malware or phish"] + ], + name="filter_2:condition_1", + delimiter=None) + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + run_query_1(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + return \ No newline at end of file