From c1f94d8f10e24a14c1e360532fd13208df339fb0 Mon Sep 17 00:00:00 2001 From: tccontre Date: Thu, 23 Mar 2023 11:41:42 +0100 Subject: [PATCH 1/8] urlscan_io_dynamic_analysis_playbook --- playbooks/UrlScan_IO_Dynamic_Analysis.json | 540 +++++++++++++++++++ playbooks/UrlScan_IO_Dynamic_Analysis.png | Bin 0 -> 72693 bytes playbooks/UrlScan_IO_Dynamic_Analysis.py | 598 +++++++++++++++++++++ 3 files changed, 1138 insertions(+) create mode 100644 playbooks/UrlScan_IO_Dynamic_Analysis.json create mode 100644 playbooks/UrlScan_IO_Dynamic_Analysis.png create mode 100644 playbooks/UrlScan_IO_Dynamic_Analysis.py diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.json b/playbooks/UrlScan_IO_Dynamic_Analysis.json new file mode 100644 index 0000000000..c62e170974 --- /dev/null +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.json @@ -0,0 +1,540 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Uncategorized", + "coa": { + "data": { + "description": "Accepts a URL for detonation analysis on the objects. Generates a global report and a per observable sub-report and normalized score. The score can be customized based on a variety of factors.\n\nRef: https://d3fend.mitre.org/technique/d3f:IdentifierReputationAnalysis/", + "edges": [ + { + "id": "port_0_to_port_2", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_2_to_port_3", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "3", + "targetPort": "3_in" + }, + { + "id": "port_3_to_port_4", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "4", + "targetPort": "4_in" + }, + { + "id": "port_5_to_port_6", + "sourceNode": "5", + "sourcePort": "5_out", + "targetNode": "6", + "targetPort": "6_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_4_to_port_7", + "sourceNode": "4", + "sourcePort": "4_out", + "targetNode": "7", + "targetPort": "7_in" + }, + { + "conditions": [ + { + "index": 1 + } + ], + "id": "port_7_to_port_8", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "8", + "targetPort": "8_in" + }, + { + "id": "port_8_to_port_9", + "sourceNode": "8", + "sourcePort": "8_out", + "targetNode": "9", + "targetPort": "9_in" + }, + { + "id": "port_11_to_port_1", + "sourceNode": "11", + "sourcePort": "11_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_10_to_port_1", + "sourceNode": "10", + "sourcePort": "10_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_6_to_port_10", + "sourceNode": "6", + "sourcePort": "6_out", + "targetNode": "10", + "targetPort": "10_in" + }, + { + "id": "port_9_to_port_11", + "sourceNode": "9", + "sourcePort": "9_out", + "targetNode": "11", + "targetPort": "11_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_7_to_port_5", + "sourceNode": "7", + "sourcePort": "7_out", + "targetNode": "5", + "targetPort": "5_in" + } + ], + "hash": "ac357dc4e4f5e34662927be84d2d1e67f2161c61", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 190, + "y": 0 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 190, + "y": 1448 + }, + "10": { + "data": { + "advanced": { + "customName": "build url output with error code", + "customNameId": 0, + "description": "This block uses custom code to generate an observable dictionary to output into the observables data path.", + "join": [], + "note": "This block uses custom code to generate an observable dictionary to output into the observables data path." + }, + "functionId": 3, + "functionName": "build_url_output_with_error_code", + "id": "10", + "inputParameters": [ + "url_reputation:action_result.parameter.url", + "normalize_score_url_with_error_code:custom_function:url_score_object", + "url_reputation:action_result.data.*.task.reportURL" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "10", + "type": "code", + "userCode": "\n # Write your custom code here...\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1]\n url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url]\n url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object]\n \n #phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_result_item_1: {}\".format(url_reputation_result_item_1))\n #phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n \n for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object):\n #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"reputation\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "warnings": {}, + "x": 340, + "y": 1254 + }, + "11": { + "data": { + "advanced": { + "customName": "build url output with no error code", + "customNameId": 0, + "description": "This block uses custom code to generate an observable dictionary to output into the observables data path.", + "join": [], + "note": "This block uses custom code to generate an observable dictionary to output into the observables data path." + }, + "functionId": 4, + "functionName": "build_url_output_with_no_error_code", + "id": "11", + "inputParameters": [ + "url_reputation:action_result.parameter.url", + "normalize_score_url_with_no_error_code:custom_function:url_score_object", + "filtered-data:urlscan_detections_error_code_filter:condition_2:url_reputation:action_result.data.*.task.reportURL" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "11", + "type": "code", + "userCode": "\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"reputation\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "warnings": {}, + "x": 0, + "y": 1260 + }, + "2": { + "data": { + "advanced": { + "customName": "url input filter", + "customNameId": 0, + "description": "Determine branches based on provided inputs.", + "join": [], + "note": "Determine branches based on provided inputs." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:url", + "value": "" + } + ], + "conditionIndex": 0, + "customName": "url input filter", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "url_input_filter", + "id": "2", + "type": "filter" + }, + "errors": {}, + "id": "2", + "type": "filter", + "warnings": {}, + "x": 230, + "y": 148 + }, + "3": { + "data": { + "action": "detonate url", + "actionType": "investigate", + "advanced": { + "customName": "url reputation", + "customNameId": 0, + "description": "Queries urlscan.io for information about the provided URL(s)", + "join": [], + "note": "Queries urlscan.io for information about the provided URL(s)" + }, + "connector": "urlscan.io", + "connectorConfigs": [ + "urlscan.io" + ], + "connectorId": "c46c00cd-7231-4dd3-8d8e-02b9fa0e14a2", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "url_reputation", + "id": "3", + "parameters": { + "get_result": true, + "private": true, + "url": "playbook_input:url" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "url" + }, + { + "data_type": "boolean", + "default": true, + "field": "private" + }, + { + "data_type": "boolean", + "default": true, + "field": "get_result" + } + ], + "type": "action" + }, + "errors": {}, + "id": "3", + "type": "action", + "warnings": {}, + "x": 170, + "y": 328 + }, + "4": { + "data": { + "advanced": { + "customName": "urlscanio summary filter", + "customNameId": 0, + "description": "Filters successful url reputation results.", + "join": [], + "note": "Filters successful url reputation results." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "==", + "param": "url_reputation:action_result.status", + "value": "success" + } + ], + "conditionIndex": 0, + "customName": "success_urlscan_query", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "urlscanio_summary_filter", + "id": "4", + "type": "filter" + }, + "errors": {}, + "id": "4", + "type": "filter", + "warnings": {}, + "x": 240, + "y": 500 + }, + "5": { + "customCode": null, + "data": { + "advanced": { + "customName": "normalize score url with error code", + "customNameId": 0, + "description": "This block uses custom code for normalizing score. Adjust the logic as desired in the documented sections.", + "join": [], + "note": "This block uses custom code for normalizing score. Adjust the logic as desired in the documented sections." + }, + "functionId": 1, + "functionName": "normalize_score_url_with_error_code", + "id": "5", + "inputParameters": [ + "url_reputation:action_result.parameter.url", + "url_reputation:action_result.data.*.message", + "url_reputation:action_result.data.*.status", + "url_reputation:action_result.data.*.description" + ], + "outputVariables": [ + "url_score_object", + "scores", + "categories" + ], + "type": "code" + }, + "errors": {}, + "id": "5", + "type": "code", + "userCode": "\n # Write your custom code here...\n url_reputation_data_message = [str(i or '') for i in url_reputation_result_item_1] \n url_reputation_data_status = [str(i or '') for i in url_reputation_result_item_2] \n url_reputation_data_description = [str(i or '') for i in url_reputation_result_item_3] \n\n \n normalize_score_url_with_error_code__url_score_object = []\n normalize_score_url_with_error_code__scores = []\n normalize_score_url_with_error_code__categories = []\n\n \n #phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_data_message: {}\".format(url_reputation_data_message))\n #phantom.debug(\"url_reputation_data_status: {}\".format(url_reputation_data_status))\n #phantom.debug(\"url_reputation_data_description: {}\".format(url_reputation_data_description))\n\n \n\n \n urlscan_score_table = {\n \"0\":\"Legitimate\",\n \"1\":\"Very_Safe\",\n \"2\":\"Safe\",\n \"3\":\"Probably_Safe\",\n \"4\":\"Leans_Safe\",\n \"5\":\"May_not_be_Safe\",\n \"6\":\"Exercise_Caution\",\n \"7\":\"Suspicious_or_Risky\",\n \"8\":\"Possibly_Malicious\",\n \"9\":\"Probably_Malicious\",\n \"10\":\"Malicious\",\n \"error_code_query\" : \"error code return, check the error code descriptions\"\n\n }\n \n url_scan_io_error_code ={\n \"blacklist\" : \"Blacklisted URL or Domain\",\n \"spam\" : \"Spammy URL or Domain\",\n \"invalid_hostname\" : \"Invalid Hostname URL or Domain\",\n \"missing_url\" : \"Missing URL OR Domain Property\",\n \"auth\" : \"HTTP basic auth information\",\n \"not_be_resolved\" : \"Non-resolvable hostname (A, AAAA, CNAME)\"\n }\n ## URLSCAN.io return error code especially if the url or domain was already in their blacklist database. \n ## below are the common error code message base on their\n ## - \"Blacklisted domains and URLs\" : requested to be blacklisted by their respective owners.\n ## - \"Spammy submissions\" : of URLs known to be used only for spamming this service.\n ## - \"Invalid hostnames\" : or invalid protocol schemes (FTP etc).\n ## - \"Missing URL property\" : ... yes, it does happen.\n ## - \"Contains HTTP basic auth information\" : ... yes, that happens as well.\n ## - \"Non-resolvable hostnames (A, AAAA, CNAME)\" : which we will not even try to scan.\n \n blank_result = \"--\"\n category = \"\"\n score = \"\"\n error_message = \"\"\n \n ## check if there is error code return upon URL reputation query\n \n for url_descp in url_reputation_data_description:\n \n for key, value in url_scan_io_error_code.items():\n if key.replace(\"_\",\" \").lower() in url_descp.lower():\n error_message = url_scan_io_error_code[key]\n \n # Attach final object\n normalize_score_url_with_error_code__categories.append(error_message) \n normalize_score_url_with_error_code__url_score_object.append({'score': urlscan_score_table['error_code_query'], 'confidence':\"\", 'score_id': \"\", \"malicious_tag_verdicts\": \"\", 'categories': error_message, \"description\": url_descp})\n normalize_score_url_with_error_code__scores.append(urlscan_score_table['error_code_query'])\n \n phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n phantom.debug(\"normalize_score_url_with_error_code__scores: {}\".format(normalize_score_url_with_error_code__scores))\n phantom.debug(\"normalize_score_url_with_error_code__categories: {}\".format(normalize_score_url_with_error_code__categories))\n \n \n", + "warnings": {}, + "x": 340, + "y": 860 + }, + "6": { + "data": { + "advanced": { + "customName": "error code format report url", + "customNameId": 0, + "description": "Format a summary table with the information gathered from the playbook.", + "join": [], + "note": "Format a summary table with the information gathered from the playbook." + }, + "functionId": 1, + "functionName": "error_code_format_report_url", + "id": "6", + "parameters": [ + "url_reputation:action_result.parameter.url", + "normalize_score_url_with_error_code:custom_function:scores", + "normalize_score_url_with_error_code:custom_function:categories", + "url_reputation:action_result.data.*.task.reportURL" + ], + "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n\n", + "type": "format" + }, + "errors": {}, + "id": "6", + "type": "format", + "userCode": "\n # Write your custom code here...\n #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"error_code_format_report_url\"))\n", + "warnings": {}, + "x": 340, + "y": 1060 + }, + "7": { + "data": { + "advanced": { + "customName": "urlscanio error code filter", + "customNameId": 0, + "description": "This filter is designed to avoid nonetype value in some list and dictionary object due to error code return value of urlscan.io especially if the URL or domain is in their blacklist database", + "join": [], + "note": "This filter is designed to avoid nonetype value in some list and dictionary object due to error code return value of urlscan.io especially if the URL or domain is in their blacklist database" + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "==", + "param": "filtered-data:urlscanio_summary_filter:condition_1:url_reputation:action_result.data.*.status", + "value": "400" + } + ], + "conditionIndex": 0, + "customName": "error_code", + "logic": "and" + }, + { + "comparisons": [ + { + "conditionIndex": 1, + "op": "!=", + "param": "filtered-data:urlscanio_summary_filter:condition_1:url_reputation:action_result.data.*.status", + "value": "400" + } + ], + "conditionIndex": 1, + "customName": "no_error_code", + "logic": "or" + } + ], + "functionId": 3, + "functionName": "urlscanio_error_code_filter", + "id": "7", + "type": "filter" + }, + "errors": {}, + "id": "7", + "type": "filter", + "warnings": {}, + "x": 240, + "y": 680 + }, + "8": { + "data": { + "advanced": { + "customName": "normalize score url with no error code", + "customNameId": 0, + "description": "This block uses custom code for normalizing score. Adjust the logic as desired in the documented sections.", + "join": [], + "note": "This block uses custom code for normalizing score. Adjust the logic as desired in the documented sections." + }, + "functionId": 2, + "functionName": "normalize_score_url_with_no_error_code", + "id": "8", + "inputParameters": [ + "url_reputation:action_result.data.*.verdicts.overall", + "url_reputation:action_result.data.*.verdicts.urlscan", + "url_reputation:action_result.data.*.verdicts.engines", + "url_reputation:action_result.data.*.verdicts.community" + ], + "outputVariables": [ + "url_score_object", + "scores", + "categories" + ], + "type": "code" + }, + "errors": {}, + "id": "8", + "type": "code", + "userCode": "\n # Write your custom code here...\n \n normalize_score_url_with_no_error_code__url_score_object = []\n normalize_score_url_with_no_error_code__scores = []\n normalize_score_url_with_no_error_code__categories = []\n \n url_reputation_verdicts_overall_dict = [(i or {}) for i in url_reputation_result_item_0] \n url_reputation_verdicts_urlscan_dict = [(i or {}) for i in url_reputation_result_item_1] \n url_reputation_verdicts_engine_dict = [(i or {}) for i in url_reputation_result_item_2] \n url_reputation_verdicts_community_dict = [(i or {}) for i in url_reputation_result_item_3] \n \n #phantom.debug(\"url_reputation_verdicts_overall_dict: {}\".format(url_reputation_verdicts_overall_dict))\n #phantom.debug(\"url_reputation_verdicts_urlscan_dict: {}\".format(url_reputation_verdicts_urlscan_dict))\n #phantom.debug(\"url_reputation_verdicts_engine_dict: {}\".format(url_reputation_verdicts_engine_dict))\n #phantom.debug(\"url_reputation_verdicts_community_dict: {}\".format(url_reputation_verdicts_community_dict))\n \n \n urlscan_score_table = {\n \"0\":\"Legitimate\",\n \"1\":\"Very_Safe\",\n \"2\":\"Safe\",\n \"3\":\"Probably_Safe\",\n \"4\":\"Leans_Safe\",\n \"5\":\"May_not_be_Safe\",\n \"6\":\"Exercise_Caution\",\n \"7\":\"Suspicious_or_Risky\",\n \"8\":\"Possibly_Malicious\",\n \"9\":\"Probably_Malicious\",\n \"10\":\"Malicious\"\n }\n \n ## if there is no error code, urlscan.io will continue to detonate the URL and query scores in several verdicts object\n \n ## Normalize reputation on a -100 (legitimate) to 100 point scale based on number of malicious and suspicious divided by different urlscan.io verdict objects.\n ## This can be adjusted to include whatever logic is desired.\n \n for i in range(0,len(url_reputation_verdicts_overall_dict)):\n if url_reputation_verdicts_overall_dict[i] != {} or url_reputation_verdicts_urlscan_dict[i] != {} or url_reputation_verdicts_engine_dict[i] != {} or url_reputation_verdicts_community_dict[i] != {}:\n summary_score = url_reputation_verdicts_overall_dict[i]['score'] + url_reputation_verdicts_urlscan_dict[i]['score'] + url_reputation_verdicts_engine_dict[i]['score'] + url_reputation_verdicts_community_dict[i]['score']\n summary_malicious_verdicts = url_reputation_verdicts_overall_dict[i]['malicious'] or url_reputation_verdicts_urlscan_dict[i]['malicious'] or url_reputation_verdicts_engine_dict[i]['malicious'] or url_reputation_verdicts_community_dict[i]['malicious']\n summary_of_malicious_tag = int(url_reputation_verdicts_overall_dict[i]['malicious']) + int(url_reputation_verdicts_urlscan_dict[i]['malicious']) + int(url_reputation_verdicts_engine_dict[i]['malicious']) + int(url_reputation_verdicts_community_dict[i]['malicious'])\n summary_categories = url_reputation_verdicts_overall_dict[i]['categories'] + url_reputation_verdicts_urlscan_dict[i]['categories'] + url_reputation_verdicts_engine_dict[i]['categories'] + url_reputation_verdicts_community_dict[i]['categories']\n \n \n ## customized score id calculation\n \n log_result = (summary_score/4) # avg score from different urlscan.io score object (engine_score, overall_verdict_score, urlscan_verdicts_score and community score)\n score_id = int(log_result) \n \n\n if score_id < -50:\n score_id = \"0\"\n elif score_id < 0 and score_id >= -50:\n score_id = \"1\"\n elif score_id >= 0 and score_id <= 10:\n score_id = \"2\"\n elif score_id > 10 and score_id <= 20:\n score_id = \"3\"\n elif score_id > 20 and score_id <= 30:\n score_id = \"4\"\n elif score_id > 30 and score_id <= 40:\n score_id = \"5\"\n elif score_id > 40 and score_id <= 50:\n score_id = \"6\"\n elif score_id > 50 and score_id <= 60:\n score_id = \"7\"\n elif score_id > 70 and score_id <= 80:\n score_id = \"8\"\n elif score_id > 80 and score_id <= 90:\n score_id = \"9\"\n elif score_id > 90 and score_id <= 100:\n score_id = \"10\"\n\n score = urlscan_score_table[str(score_id)]\n\n malicious_tag_stats = (summary_of_malicious_tag, 4)\n\n # Attach final object\n normalize_score_url_with_no_error_code__categories.append(summary_categories) \n normalize_score_url_with_no_error_code__url_score_object.append({'score': score, 'confidence':log_result, 'score_id': score_id, \"malicious_tag_verdicts\": summary_malicious_verdicts, \"malicious_tag_stats\": malicious_tag_stats , 'categories': summary_categories, \"description\": \"\"})\n normalize_score_url_with_no_error_code__scores.append(score)\n \n phantom.debug(\"normalize_score_url_with_no_error_code__categories: {}\".format(normalize_score_url_with_no_error_code__categories))\n phantom.debug(\"normalize_score_url_with_no_error_code__url_score_object: {}\".format(normalize_score_url_with_no_error_code__url_score_object))\n phantom.debug(\"normalize_score_url_with_no_error_code__scores: {}\".format(normalize_score_url_with_no_error_code__scores))\n", + "warnings": {}, + "x": 0, + "y": 860 + }, + "9": { + "data": { + "advanced": { + "customName": "no error code format report url ", + "customNameId": 0, + "description": "Format a summary table with the information gathered from the playbook.", + "join": [], + "note": "Format a summary table with the information gathered from the playbook." + }, + "functionId": 2, + "functionName": "no_error_code_format_report_url", + "id": "9", + "parameters": [ + "url_reputation:action_result.parameter.url", + "normalize_score_url_with_no_error_code:custom_function:scores", + "normalize_score_url_with_no_error_code:custom_function:categories", + "url_reputation:action_result.data.*.task.reportURL" + ], + "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n", + "type": "format" + }, + "errors": {}, + "id": "9", + "type": "format", + "userCode": "\n # Write your custom code here...\n #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"no_error_code_format_report_url\"))\n", + "warnings": {}, + "x": 0, + "y": 1060 + } + }, + "notes": "Inputs: url\nInteractions: UrlScan.io\nActions: url detonation\nOutputs: report, observables" + }, + "input_spec": [ + { + "contains": [ + "url", + "domain", + "ip" + ], + "description": "A URL provided for reputation analysis - urlscan.io", + "name": "url" + } + ], + "output_spec": null, + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.8", + "version": "5.5.0.108488" + }, + "create_time": "2023-03-23T10:34:24.990317+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "reputation", + "url", + "domain", + "ip", + "sandbox", + "D3-URA", + "D3-DNRA", + "D3-IPRA", + "D3-IRA" + ] +} \ No newline at end of file diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.png b/playbooks/UrlScan_IO_Dynamic_Analysis.png new file mode 100644 index 0000000000000000000000000000000000000000..eae57860f466769cfdff3da50bb9d5fa31b2fe2d GIT binary patch literal 72693 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

`=Ww5EajGFn8ho4{%-@_^wj6EdMXoE&>7x`wv>D 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 -50: + score_id = "1" + elif score_id >= 0 and score_id <= 10: + score_id = "2" + elif score_id > 10 and score_id <= 20: + score_id = "3" + elif score_id > 20 and score_id <= 30: + score_id = "4" + elif score_id > 30 and score_id <= 40: + score_id = "5" + elif score_id > 40 and score_id <= 50: + score_id = "6" + elif score_id > 50 and score_id <= 60: + score_id = "7" + elif score_id > 70 and score_id <= 80: + score_id = "8" + elif score_id > 80 and score_id <= 90: + score_id = "9" + elif score_id > 90 and score_id <= 100: + score_id = "10" + + score = urlscan_score_table[str(score_id)] + + malicious_tag_stats = (summary_of_malicious_tag, 4) + + # Attach final object + normalize_score_url_with_no_error_code__categories.append(summary_categories) + normalize_score_url_with_no_error_code__url_score_object.append({'score': score, 'confidence':log_result, 'score_id': score_id, "malicious_tag_verdicts": summary_malicious_verdicts, "malicious_tag_stats": malicious_tag_stats , 'categories': summary_categories, "description": ""}) + normalize_score_url_with_no_error_code__scores.append(score) + + phantom.debug("normalize_score_url_with_no_error_code__categories: {}".format(normalize_score_url_with_no_error_code__categories)) + phantom.debug("normalize_score_url_with_no_error_code__url_score_object: {}".format(normalize_score_url_with_no_error_code__url_score_object)) + phantom.debug("normalize_score_url_with_no_error_code__scores: {}".format(normalize_score_url_with_no_error_code__scores)) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="normalize_score_url_with_no_error_code:url_score_object", value=json.dumps(normalize_score_url_with_no_error_code__url_score_object)) + phantom.save_run_data(key="normalize_score_url_with_no_error_code:scores", value=json.dumps(normalize_score_url_with_no_error_code__scores)) + phantom.save_run_data(key="normalize_score_url_with_no_error_code:categories", value=json.dumps(normalize_score_url_with_no_error_code__categories)) + + no_error_code_format_report_url(container=container) + + return + + +@phantom.playbook_block() +def no_error_code_format_report_url(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("no_error_code_format_report_url() called") + + ################################################################################ + # Format a summary table with the information gathered from the playbook. + ################################################################################ + + template = """SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n""" + + # parameter list for template variable replacement + parameters = [ + "url_reputation:action_result.parameter.url", + "normalize_score_url_with_no_error_code:custom_function:scores", + "normalize_score_url_with_no_error_code:custom_function:categories", + "url_reputation:action_result.data.*.task.reportURL" + ] + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url")) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url") + + build_url_output_with_no_error_code(container=container) + + return + + +@phantom.playbook_block() +def build_url_output_with_error_code(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_url_output_with_error_code() called") + + ################################################################################ + # This block uses custom code to generate an observable dictionary to output into + # the observables data path. + ################################################################################ + + url_reputation_result_data = phantom.collect2(container=container, datapath=["url_reputation:action_result.parameter.url","url_reputation:action_result.data.*.task.reportURL"], action_results=results) + normalize_score_url_with_error_code__url_score_object = json.loads(_ if (_ := phantom.get_run_data(key="normalize_score_url_with_error_code:url_score_object")) != "" else "null") # pylint: disable=used-before-assignment + + url_reputation_parameter_url = [item[0] for item in url_reputation_result_data] + url_reputation_result_item_1 = [item[1] for item in url_reputation_result_data] + + build_url_output_with_error_code__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + # Write your custom code here... + from urllib.parse import urlparse + build_url_output__observable_array = [] + + # Build URL + url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1] + url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url] + url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object] + + #phantom.debug("url_reputation_parameter_url: {}".format(url_reputation_parameter_url)) + #phantom.debug("url_reputation_result_item_1: {}".format(url_reputation_result_item_1)) + #phantom.debug("normalize_score_url_with_error_code__url_score_object: {}".format(normalize_score_url_with_error_code__url_score_object)) + + for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object): + #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object): + parsed_url = urlparse(url) + phantom.debug("parsed_url: {}".format(parsed_url)) + observable_object = { + "value": url, + "type": "url", + "reputation": { + "score_id": url_object['score_id'], + "score": url_object['score'], + "confidence": url_object['confidence'] + }, + "attributes": { + "hostname": parsed_url.hostname, + "scheme": parsed_url.scheme + }, + "categories": url_object['categories'], + "description" :url_object['description'], + "source": "urlscan.io", + "source_link": f"{external_id}" + } + if parsed_url.path: + observable_object['attributes']['path'] = parsed_url.path + if parsed_url.query: + observable_object['attributes']['query'] = parsed_url.query + if parsed_url.port: + observable_object['attributes']['port'] = parsed_url.port + + build_url_output__observable_array.append(observable_object) + phantom.debug("build_url_output__observable_array: {}".format(build_url_output__observable_array)) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_url_output_with_error_code:observable_array", value=json.dumps(build_url_output_with_error_code__observable_array)) + + return + + +@phantom.playbook_block() +def build_url_output_with_no_error_code(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("build_url_output_with_no_error_code() called") + + ################################################################################ + # This block uses custom code to generate an observable dictionary to output into + # the observables data path. + ################################################################################ + + url_reputation_result_data = phantom.collect2(container=container, datapath=["url_reputation:action_result.parameter.url"], action_results=results) + filtered_result_0_data_urlscan_detections_error_code_filter = phantom.collect2(container=container, datapath=["filtered-data:urlscan_detections_error_code_filter:condition_2:url_reputation:action_result.data.*.task.reportURL"]) + normalize_score_url_with_no_error_code__url_score_object = json.loads(_ if (_ := phantom.get_run_data(key="normalize_score_url_with_no_error_code:url_score_object")) != "" else "null") # pylint: disable=used-before-assignment + + url_reputation_parameter_url = [item[0] for item in url_reputation_result_data] + filtered_result_0_data___task_reporturl = [item[0] for item in filtered_result_0_data_urlscan_detections_error_code_filter] + + build_url_output_with_no_error_code__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + from urllib.parse import urlparse + build_url_output__observable_array = [] + + # Build URL + for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object): + parsed_url = urlparse(url) + phantom.debug("parsed_url: {}".format(parsed_url)) + observable_object = { + "value": url, + "type": "url", + "reputation": { + "score_id": url_object['score_id'], + "score": url_object['score'], + "confidence": url_object['confidence'] + }, + "attributes": { + "hostname": parsed_url.hostname, + "scheme": parsed_url.scheme + }, + "categories": url_object['categories'], + "description" :url_object['description'], + "source": "urlscan.io", + "source_link": f"{external_id}" + } + if parsed_url.path: + observable_object['attributes']['path'] = parsed_url.path + if parsed_url.query: + observable_object['attributes']['query'] = parsed_url.query + if parsed_url.port: + observable_object['attributes']['port'] = parsed_url.port + + build_url_output__observable_array.append(observable_object) + phantom.debug("build_url_output__observable_array: {}".format(build_url_output__observable_array)) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="build_url_output_with_no_error_code:observable_array", value=json.dumps(build_url_output_with_no_error_code__observable_array)) + + 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 From ff1f7e66284896775de41df26de72eaecf8ea175 Mon Sep 17 00:00:00 2001 From: tccontre Date: Thu, 23 Mar 2023 11:51:01 +0100 Subject: [PATCH 2/8] urlscan_io_dynamic_analysis_playbook --- playbooks/UrlScan_IO_Dynamic_Analysis.yml | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 playbooks/UrlScan_IO_Dynamic_Analysis.yml diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.yml b/playbooks/UrlScan_IO_Dynamic_Analysis.yml new file mode 100644 index 0000000000..ca2dcc8fa0 --- /dev/null +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.yml @@ -0,0 +1,26 @@ +name: UrlScan IO Dynamic Analysis +id: a1173c28-7b33-4a56-9d7f-5dbbca595cb0 +version: 1 +date: '2023-03-23' +author: Teoderick Contreras, Splunk +type: Investigation +description: "Accepts a url link, IP, or domain to be detonated using urlscan.io API connector." +playbook: UrlScan_IO_Dynamic_Analysis +how_to_implement: This input playbook requires the urlscan.io API connector to be configured. + It is designed to work in conjunction with the Dynamic Attribute Lookup playbook or other playbooks in the same style. +references: [] +app_list: + - urlscan.io +tags: + platform_tags: + - reputation + - url + - domain + - sandbox + - ip + - urlscan.io + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR \ No newline at end of file From 63f4a10ae3b2110b97b46a17a028b3ae523f3669 Mon Sep 17 00:00:00 2001 From: tccontre <26181693+tccontre@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:01:02 +0100 Subject: [PATCH 3/8] Update UrlScan_IO_Dynamic_Analysis.yml --- playbooks/UrlScan_IO_Dynamic_Analysis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.yml b/playbooks/UrlScan_IO_Dynamic_Analysis.yml index ca2dcc8fa0..e68eab1e7e 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.yml +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.yml @@ -18,9 +18,8 @@ tags: - domain - sandbox - ip - - urlscan.io playbook_type: Input vpe_type: Modern playbook_fields: [] product: - - Splunk SOAR \ No newline at end of file + - Splunk SOAR From 31aaeba573557eef32524f42de1747a02cdf705d Mon Sep 17 00:00:00 2001 From: tccontre Date: Fri, 24 Mar 2023 15:18:50 +0100 Subject: [PATCH 4/8] urlscan_io_dynamic_analysis_playbook --- playbooks/UrlScan_IO_Dynamic_Analysis.json | 36 +++++++++++++++------- playbooks/UrlScan_IO_Dynamic_Analysis.py | 20 ++++++++++-- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.json b/playbooks/UrlScan_IO_Dynamic_Analysis.json index c62e170974..09a8dd7012 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.json +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.json @@ -1,7 +1,7 @@ { "blockly": false, "blockly_xml": "", - "category": "Uncategorized", + "category": "Dynamic Analysis", "coa": { "data": { "description": "Accepts a URL for detonation analysis on the objects. Generates a global report and a per observable sub-report and normalized score. The score can be customized based on a variety of factors.\n\nRef: https://d3fend.mitre.org/technique/d3f:IdentifierReputationAnalysis/", @@ -111,7 +111,7 @@ "targetPort": "5_in" } ], - "hash": "ac357dc4e4f5e34662927be84d2d1e67f2161c61", + "hash": "6c0864d678b617e9406a8eced20d9e41957ed064", "nodes": { "0": { "data": { @@ -127,7 +127,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": 0 + "y": -6.394884621840902e-14 }, "1": { "data": { @@ -141,9 +141,10 @@ "errors": {}, "id": "1", "type": "end", + "userCode": "\n # Write your custom code here...\n no_error_code_format_report_url = phantom.get_format_data(name=\"no_error_code_format_report_url\")\n error_code_format_report_url = phantom.get_format_data(name=\"error_code_format_report_url\")\n markdown_report_combined_value = phantom.concatenate(no_error_code_format_report_url, error_code_format_report_url)\n output['markdown_report'] = markdown_report_combined_value\n", "warnings": {}, - "x": 190, - "y": 1448 + "x": 200, + "y": 1440 }, "10": { "data": { @@ -170,7 +171,7 @@ "errors": {}, "id": "10", "type": "code", - "userCode": "\n # Write your custom code here...\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1]\n url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url]\n url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object]\n \n #phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_result_item_1: {}\".format(url_reputation_result_item_1))\n #phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n \n for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object):\n #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"reputation\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "userCode": "\n # Write your custom code here...\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1]\n url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url]\n url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object]\n \n #phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_result_item_1: {}\".format(url_reputation_result_item_1))\n #phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n \n for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object):\n #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", "warnings": {}, "x": 340, "y": 1254 @@ -200,7 +201,7 @@ "errors": {}, "id": "11", "type": "code", - "userCode": "\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"reputation\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "userCode": "\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", "warnings": {}, "x": 0, "y": 1260 @@ -515,19 +516,30 @@ "name": "url" } ], - "output_spec": null, + "output_spec": [ + { + "contains": [], + "datapaths": [ + "build_url_output_with_error_code:custom_function:observable_array", + "build_url_output_with_no_error_code:custom_function:observable_array" + ], + "deduplicate": false, + "description": "An array of observable dictionaries with value, type, score, score_id, and categories.", + "metadata": {}, + "name": "observable" + } + ], "playbook_type": "data", "python_version": "3", "schema": "5.0.8", "version": "5.5.0.108488" }, - "create_time": "2023-03-23T10:34:24.990317+00:00", + "create_time": "2023-03-24T14:08:30.332219+00:00", "draft_mode": false, "labels": [ "*" ], "tags": [ - "reputation", "url", "domain", "ip", @@ -535,6 +547,8 @@ "D3-URA", "D3-DNRA", "D3-IPRA", - "D3-IRA" + "D3-IRA", + "urlscan.io", + "file_hash" ] } \ No newline at end of file diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.py b/playbooks/UrlScan_IO_Dynamic_Analysis.py index 9199998aa9..8c10618867 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.py +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.py @@ -484,7 +484,7 @@ def build_url_output_with_error_code(action=None, success=None, container=None, observable_object = { "value": url, "type": "url", - "reputation": { + "sandbox": { "score_id": url_object['score_id'], "score": url_object['score'], "confidence": url_object['confidence'] @@ -549,7 +549,7 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non observable_object = { "value": url, "type": "url", - "reputation": { + "sandbox": { "score_id": url_object['score_id'], "score": url_object['score'], "confidence": url_object['confidence'] @@ -585,14 +585,28 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non def on_finish(container, summary): phantom.debug("on_finish() called") + build_url_output_with_error_code__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_url_output_with_error_code:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + build_url_output_with_no_error_code__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="build_url_output_with_no_error_code:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + observable_combined_value = phantom.concatenate(build_url_output_with_error_code__observable_array, build_url_output_with_no_error_code__observable_array) + + output = { + "observable": observable_combined_value, + } + ################################################################################ ## Custom Code Start ################################################################################ # Write your custom code here... - + no_error_code_format_report_url = phantom.get_format_data(name="no_error_code_format_report_url") + error_code_format_report_url = phantom.get_format_data(name="error_code_format_report_url") + markdown_report_combined_value = phantom.concatenate(no_error_code_format_report_url, error_code_format_report_url) + output['markdown_report'] = markdown_report_combined_value ################################################################################ ## Custom Code End ################################################################################ + phantom.save_playbook_output_data(output=output) + return \ No newline at end of file From 1e5e09218900ada3df5acc3b6c0c09d32322a2ab Mon Sep 17 00:00:00 2001 From: tccontre Date: Mon, 27 Mar 2023 14:24:17 +0200 Subject: [PATCH 5/8] urlscan_io_dynamic_analysis_playbook --- playbooks/UrlScan_IO_Dynamic_Analysis.json | 30 +++++++------ playbooks/UrlScan_IO_Dynamic_Analysis.py | 52 ++++++++++++---------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.json b/playbooks/UrlScan_IO_Dynamic_Analysis.json index 09a8dd7012..a2e99d63c6 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.json +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.json @@ -111,7 +111,7 @@ "targetPort": "5_in" } ], - "hash": "6c0864d678b617e9406a8eced20d9e41957ed064", + "hash": "662e0c1ead292892eb76490c42919b482032f0a2", "nodes": { "0": { "data": { @@ -127,7 +127,7 @@ "type": "start", "warnings": {}, "x": 190, - "y": -6.394884621840902e-14 + "y": -1.2789769243681803e-13 }, "1": { "data": { @@ -171,10 +171,10 @@ "errors": {}, "id": "10", "type": "code", - "userCode": "\n # Write your custom code here...\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1]\n url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url]\n url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object]\n \n #phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_result_item_1: {}\".format(url_reputation_result_item_1))\n #phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n \n for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object):\n #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "userCode": "\n # Write your custom code here...\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output_with_error_code__observable_array = []\n\n # Build URL\n url_scan_io_task_reporturl = [str(i or 'no report url') for i in url_reputation_result_item_1]\n url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url]\n url_scan_io_url_score_object = normalize_score_url_with_error_code__url_score_object\n \n phantom.debug(\"url_reputation_parameter_url: {}\".format(url_reputation_parameter_url))\n #phantom.debug(\"url_reputation_result_item_1: {}\".format(url_reputation_result_item_1))\n #phantom.debug(\"normalize_score_url_with_error_code__url_score_object: {}\".format(normalize_score_url_with_error_code__url_score_object))\n for url, external_id, url_object in zip(url_scan_io_parameter_url, url_scan_io_task_reporturl, url_scan_io_url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"{} {} {} parsed_url: {}\".format(url, external_id, url_object, parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n }, \n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n\n \n build_url_output_with_error_code__observable_array.append(observable_object)\n phantom.debug(\"build_url_output_with_error_code__observable_array: {}\".format(build_url_output_with_error_code__observable_array))\n", "warnings": {}, "x": 340, - "y": 1254 + "y": 1260 }, "11": { "data": { @@ -191,7 +191,7 @@ "inputParameters": [ "url_reputation:action_result.parameter.url", "normalize_score_url_with_no_error_code:custom_function:url_score_object", - "filtered-data:urlscan_detections_error_code_filter:condition_2:url_reputation:action_result.data.*.task.reportURL" + "url_reputation:action_result.data.*.task.reportURL" ], "outputVariables": [ "observable_array" @@ -201,7 +201,7 @@ "errors": {}, "id": "11", "type": "code", - "userCode": "\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"parsed_url: {}\".format(parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output__observable_array.append(observable_object)\n phantom.debug(\"build_url_output__observable_array: {}\".format(build_url_output__observable_array))\n", + "userCode": "\n # Write your custom code here...\n from urllib.parse import urlparse\n build_url_output_with_no_error_code__observable_array = []\n\n # Build URL\n phantom.debug(url_reputation_parameter_url)\n for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_no_error_code__url_score_object):\n parsed_url = urlparse(url)\n phantom.debug(\"{} {} {} parsed_url: {}\".format(url, external_id, url_object, parsed_url))\n observable_object = {\n \"value\": url,\n \"type\": \"url\",\n \"sandbox\": {\n \"score_id\": url_object['score_id'],\n \"score\": url_object['score'],\n \"confidence\": url_object['confidence']\n },\n \"attributes\": {\n \"hostname\": parsed_url.hostname,\n \"scheme\": parsed_url.scheme\n },\n \"categories\": url_object['categories'],\n \"description\" :url_object['description'],\n \"source\": \"urlscan.io\",\n \"source_link\": f\"{external_id}\"\n }\n if parsed_url.path:\n observable_object['attributes']['path'] = parsed_url.path\n if parsed_url.query:\n observable_object['attributes']['query'] = parsed_url.query\n if parsed_url.port:\n observable_object['attributes']['port'] = parsed_url.port\n \n build_url_output_with_no_error_code__observable_array.append(observable_object)\n phantom.debug(\"build_url_output_with_no_error_code__observable_array: {}\".format(build_url_output_with_no_error_code__observable_array))\n", "warnings": {}, "x": 0, "y": 1260 @@ -350,7 +350,8 @@ "outputVariables": [ "url_score_object", "scores", - "categories" + "categories", + "confidence" ], "type": "code" }, @@ -376,17 +377,18 @@ "id": "6", "parameters": [ "url_reputation:action_result.parameter.url", + "normalize_score_url_with_error_code:custom_function:confidence", "normalize_score_url_with_error_code:custom_function:scores", "normalize_score_url_with_error_code:custom_function:categories", "url_reputation:action_result.data.*.task.reportURL" ], - "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n\n", + "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Confidence |Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | urlscan.io |\n\n", "type": "format" }, "errors": {}, "id": "6", "type": "format", - "userCode": "\n # Write your custom code here...\n #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"error_code_format_report_url\"))\n", + "userCode": "\n # Write your custom code here...\n phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"error_code_format_report_url\"))\n", "warnings": {}, "x": 340, "y": 1060 @@ -461,7 +463,8 @@ "outputVariables": [ "url_score_object", "scores", - "categories" + "categories", + "confidence" ], "type": "code" }, @@ -488,16 +491,17 @@ "parameters": [ "url_reputation:action_result.parameter.url", "normalize_score_url_with_no_error_code:custom_function:scores", + "normalize_score_url_with_no_error_code:custom_function:confidence", "normalize_score_url_with_no_error_code:custom_function:categories", "url_reputation:action_result.data.*.task.reportURL" ], - "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n", + "template": "SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score |Confidence | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} |{4} | urlscan.io |\n", "type": "format" }, "errors": {}, "id": "9", "type": "format", - "userCode": "\n # Write your custom code here...\n #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"no_error_code_format_report_url\"))\n", + "userCode": "\n # Write your custom code here...\n phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name=\"no_error_code_format_report_url\"))\n", "warnings": {}, "x": 0, "y": 1060 @@ -534,7 +538,7 @@ "schema": "5.0.8", "version": "5.5.0.108488" }, - "create_time": "2023-03-24T14:08:30.332219+00:00", + "create_time": "2023-03-27T12:19:43.255588+00:00", "draft_mode": false, "labels": [ "*" diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.py b/playbooks/UrlScan_IO_Dynamic_Analysis.py index 8c10618867..c692a8fac6 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.py +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.py @@ -120,6 +120,7 @@ def normalize_score_url_with_error_code(action=None, success=None, container=Non normalize_score_url_with_error_code__url_score_object = None normalize_score_url_with_error_code__scores = None normalize_score_url_with_error_code__categories = None + normalize_score_url_with_error_code__confidence = None ################################################################################ ## Custom Code Start @@ -207,6 +208,7 @@ def normalize_score_url_with_error_code(action=None, success=None, container=Non phantom.save_run_data(key="normalize_score_url_with_error_code:url_score_object", value=json.dumps(normalize_score_url_with_error_code__url_score_object)) phantom.save_run_data(key="normalize_score_url_with_error_code:scores", value=json.dumps(normalize_score_url_with_error_code__scores)) phantom.save_run_data(key="normalize_score_url_with_error_code:categories", value=json.dumps(normalize_score_url_with_error_code__categories)) + phantom.save_run_data(key="normalize_score_url_with_error_code:confidence", value=json.dumps(normalize_score_url_with_error_code__confidence)) error_code_format_report_url(container=container) @@ -221,11 +223,12 @@ def error_code_format_report_url(action=None, success=None, container=None, resu # Format a summary table with the information gathered from the playbook. ################################################################################ - template = """SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n\n""" + template = """SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Confidence |Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | {4} | urlscan.io |\n\n""" # parameter list for template variable replacement parameters = [ "url_reputation:action_result.parameter.url", + "normalize_score_url_with_error_code:custom_function:confidence", "normalize_score_url_with_error_code:custom_function:scores", "normalize_score_url_with_error_code:custom_function:categories", "url_reputation:action_result.data.*.task.reportURL" @@ -236,7 +239,7 @@ def error_code_format_report_url(action=None, success=None, container=None, resu ################################################################################ # Write your custom code here... - #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="error_code_format_report_url")) + phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="error_code_format_report_url")) ################################################################################ ## Custom Code End ################################################################################ @@ -304,6 +307,7 @@ def normalize_score_url_with_no_error_code(action=None, success=None, container= normalize_score_url_with_no_error_code__url_score_object = None normalize_score_url_with_no_error_code__scores = None normalize_score_url_with_no_error_code__categories = None + normalize_score_url_with_no_error_code__confidence = None ################################################################################ ## Custom Code Start @@ -401,6 +405,7 @@ def normalize_score_url_with_no_error_code(action=None, success=None, container= phantom.save_run_data(key="normalize_score_url_with_no_error_code:url_score_object", value=json.dumps(normalize_score_url_with_no_error_code__url_score_object)) phantom.save_run_data(key="normalize_score_url_with_no_error_code:scores", value=json.dumps(normalize_score_url_with_no_error_code__scores)) phantom.save_run_data(key="normalize_score_url_with_no_error_code:categories", value=json.dumps(normalize_score_url_with_no_error_code__categories)) + phantom.save_run_data(key="normalize_score_url_with_no_error_code:confidence", value=json.dumps(normalize_score_url_with_no_error_code__confidence)) no_error_code_format_report_url(container=container) @@ -415,12 +420,13 @@ def no_error_code_format_report_url(action=None, success=None, container=None, r # Format a summary table with the information gathered from the playbook. ################################################################################ - template = """SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} | urlscan.io |\n""" + template = """SOAR analyzed URL(s) using urlscan.io. The table below shows a summary of the information gathered.\n\n| URL | Normalized Score |Confidence | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | {3} |{4} | urlscan.io |\n""" # parameter list for template variable replacement parameters = [ "url_reputation:action_result.parameter.url", "normalize_score_url_with_no_error_code:custom_function:scores", + "normalize_score_url_with_no_error_code:custom_function:confidence", "normalize_score_url_with_no_error_code:custom_function:categories", "url_reputation:action_result.data.*.task.reportURL" ] @@ -430,7 +436,7 @@ def no_error_code_format_report_url(action=None, success=None, container=None, r ################################################################################ # Write your custom code here... - #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url")) + phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url")) ################################################################################ ## Custom Code End ################################################################################ @@ -466,21 +472,19 @@ def build_url_output_with_error_code(action=None, success=None, container=None, # Write your custom code here... # Write your custom code here... from urllib.parse import urlparse - build_url_output__observable_array = [] + build_url_output_with_error_code__observable_array = [] # Build URL - url_scan_io_task_reporturl = [str(i or '') for i in url_reputation_result_item_1] + url_scan_io_task_reporturl = [str(i or 'no report url') for i in url_reputation_result_item_1] url_scan_io_parameter_url = [str(i or '') for i in url_reputation_parameter_url] - url_scan_io_url_score_object = [str(i or '') for i in normalize_score_url_with_error_code__url_score_object] + url_scan_io_url_score_object = normalize_score_url_with_error_code__url_score_object - #phantom.debug("url_reputation_parameter_url: {}".format(url_reputation_parameter_url)) + phantom.debug("url_reputation_parameter_url: {}".format(url_reputation_parameter_url)) #phantom.debug("url_reputation_result_item_1: {}".format(url_reputation_result_item_1)) #phantom.debug("normalize_score_url_with_error_code__url_score_object: {}".format(normalize_score_url_with_error_code__url_score_object)) - - for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_error_code__url_score_object): - #for url, external_id, url_object in zip(url_scan_io_task_reporturl, url_scan_io_task_reporturl, url_scan_io_url_score_object): + for url, external_id, url_object in zip(url_scan_io_parameter_url, url_scan_io_task_reporturl, url_scan_io_url_score_object): parsed_url = urlparse(url) - phantom.debug("parsed_url: {}".format(parsed_url)) + phantom.debug("{} {} {} parsed_url: {}".format(url, external_id, url_object, parsed_url)) observable_object = { "value": url, "type": "url", @@ -488,7 +492,7 @@ def build_url_output_with_error_code(action=None, success=None, container=None, "score_id": url_object['score_id'], "score": url_object['score'], "confidence": url_object['confidence'] - }, + }, "attributes": { "hostname": parsed_url.hostname, "scheme": parsed_url.scheme @@ -498,15 +502,17 @@ def build_url_output_with_error_code(action=None, success=None, container=None, "source": "urlscan.io", "source_link": f"{external_id}" } + if parsed_url.path: observable_object['attributes']['path'] = parsed_url.path if parsed_url.query: observable_object['attributes']['query'] = parsed_url.query if parsed_url.port: observable_object['attributes']['port'] = parsed_url.port + - build_url_output__observable_array.append(observable_object) - phantom.debug("build_url_output__observable_array: {}".format(build_url_output__observable_array)) + build_url_output_with_error_code__observable_array.append(observable_object) + phantom.debug("build_url_output_with_error_code__observable_array: {}".format(build_url_output_with_error_code__observable_array)) ################################################################################ ## Custom Code End ################################################################################ @@ -525,12 +531,11 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non # the observables data path. ################################################################################ - url_reputation_result_data = phantom.collect2(container=container, datapath=["url_reputation:action_result.parameter.url"], action_results=results) - filtered_result_0_data_urlscan_detections_error_code_filter = phantom.collect2(container=container, datapath=["filtered-data:urlscan_detections_error_code_filter:condition_2:url_reputation:action_result.data.*.task.reportURL"]) + url_reputation_result_data = phantom.collect2(container=container, datapath=["url_reputation:action_result.parameter.url","url_reputation:action_result.data.*.task.reportURL"], action_results=results) normalize_score_url_with_no_error_code__url_score_object = json.loads(_ if (_ := phantom.get_run_data(key="normalize_score_url_with_no_error_code:url_score_object")) != "" else "null") # pylint: disable=used-before-assignment url_reputation_parameter_url = [item[0] for item in url_reputation_result_data] - filtered_result_0_data___task_reporturl = [item[0] for item in filtered_result_0_data_urlscan_detections_error_code_filter] + url_reputation_result_item_1 = [item[1] for item in url_reputation_result_data] build_url_output_with_no_error_code__observable_array = None @@ -540,12 +545,13 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non # Write your custom code here... from urllib.parse import urlparse - build_url_output__observable_array = [] + build_url_output_with_no_error_code__observable_array = [] # Build URL - for url, external_id, url_object in zip(url_reputation_parameter_url, filtered_result_0_data___task_reporturl, normalize_score_url_with_no_error_code__url_score_object): + phantom.debug(url_reputation_parameter_url) + for url, external_id, url_object in zip(url_reputation_parameter_url, url_reputation_result_item_1, normalize_score_url_with_no_error_code__url_score_object): parsed_url = urlparse(url) - phantom.debug("parsed_url: {}".format(parsed_url)) + phantom.debug("{} {} {} parsed_url: {}".format(url, external_id, url_object, parsed_url)) observable_object = { "value": url, "type": "url", @@ -570,8 +576,8 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non if parsed_url.port: observable_object['attributes']['port'] = parsed_url.port - build_url_output__observable_array.append(observable_object) - phantom.debug("build_url_output__observable_array: {}".format(build_url_output__observable_array)) + build_url_output_with_no_error_code__observable_array.append(observable_object) + phantom.debug("build_url_output_with_no_error_code__observable_array: {}".format(build_url_output_with_no_error_code__observable_array)) ################################################################################ ## Custom Code End ################################################################################ From dbeda2da7582690273014330657582bea69306af Mon Sep 17 00:00:00 2001 From: tccontre <26181693+tccontre@users.noreply.github.com> Date: Mon, 27 Mar 2023 15:21:05 +0200 Subject: [PATCH 6/8] Update UrlScan_IO_Dynamic_Analysis.json --- playbooks/UrlScan_IO_Dynamic_Analysis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.json b/playbooks/UrlScan_IO_Dynamic_Analysis.json index a2e99d63c6..259106649b 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.json +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.json @@ -555,4 +555,4 @@ "urlscan.io", "file_hash" ] -} \ No newline at end of file +} From 6e26c42a907909ac3df430ccf41466c3c5c904ef Mon Sep 17 00:00:00 2001 From: tccontre <26181693+tccontre@users.noreply.github.com> Date: Mon, 27 Mar 2023 15:22:00 +0200 Subject: [PATCH 7/8] Update UrlScan_IO_Dynamic_Analysis.py --- playbooks/UrlScan_IO_Dynamic_Analysis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.py b/playbooks/UrlScan_IO_Dynamic_Analysis.py index c692a8fac6..e9159aee80 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.py +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.py @@ -615,4 +615,5 @@ def on_finish(container, summary): phantom.save_playbook_output_data(output=output) - return \ No newline at end of file + return + From d5b4bc84b0440a52443784693e5581357f875d4c Mon Sep 17 00:00:00 2001 From: tccontre <26181693+tccontre@users.noreply.github.com> Date: Tue, 28 Mar 2023 09:58:57 +0200 Subject: [PATCH 8/8] Update UrlScan_IO_Dynamic_Analysis.py --- playbooks/UrlScan_IO_Dynamic_Analysis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/playbooks/UrlScan_IO_Dynamic_Analysis.py b/playbooks/UrlScan_IO_Dynamic_Analysis.py index e9159aee80..4c38350830 100644 --- a/playbooks/UrlScan_IO_Dynamic_Analysis.py +++ b/playbooks/UrlScan_IO_Dynamic_Analysis.py @@ -239,7 +239,7 @@ def error_code_format_report_url(action=None, success=None, container=None, resu ################################################################################ # Write your custom code here... - phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="error_code_format_report_url")) + #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="error_code_format_report_url")) ################################################################################ ## Custom Code End ################################################################################ @@ -436,7 +436,7 @@ def no_error_code_format_report_url(action=None, success=None, container=None, r ################################################################################ # Write your custom code here... - phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url")) + #phantom.debug(phantom.format(container=container, template=template, parameters=parameters, name="no_error_code_format_report_url")) ################################################################################ ## Custom Code End ################################################################################ @@ -512,7 +512,7 @@ def build_url_output_with_error_code(action=None, success=None, container=None, build_url_output_with_error_code__observable_array.append(observable_object) - phantom.debug("build_url_output_with_error_code__observable_array: {}".format(build_url_output_with_error_code__observable_array)) + #phantom.debug("build_url_output_with_error_code__observable_array: {}".format(build_url_output_with_error_code__observable_array)) ################################################################################ ## Custom Code End ################################################################################ @@ -577,7 +577,7 @@ def build_url_output_with_no_error_code(action=None, success=None, container=Non observable_object['attributes']['port'] = parsed_url.port build_url_output_with_no_error_code__observable_array.append(observable_object) - phantom.debug("build_url_output_with_no_error_code__observable_array: {}".format(build_url_output_with_no_error_code__observable_array)) + #phantom.debug("build_url_output_with_no_error_code__observable_array: {}".format(build_url_output_with_no_error_code__observable_array)) ################################################################################ ## Custom Code End ################################################################################