Files
splunk-security_content/playbooks/VirusTotal_v3_Identifier_Reputation_Analysis.json
2026-04-28 10:47:57 -04:00

1083 lines
61 KiB
JSON

{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Identifier Reputation Analysis",
"coa": {
"data": {
"description": "Accepts a URL, IP, Domain, or File_Hash and does reputation 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_5_to_port_6",
"sourceNode": "5",
"sourcePort": "5_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"id": "port_13_to_port_17",
"sourceNode": "13",
"sourcePort": "13_out",
"targetNode": "17",
"targetPort": "17_in"
},
{
"id": "port_15_to_port_18",
"sourceNode": "15",
"sourcePort": "15_out",
"targetNode": "18",
"targetPort": "18_in"
},
{
"id": "port_16_to_port_19",
"sourceNode": "16",
"sourcePort": "16_out",
"targetNode": "19",
"targetPort": "19_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_21_to_port_2",
"sourceNode": "21",
"sourcePort": "21_out",
"targetNode": "2",
"targetPort": "2_in"
},
{
"conditions": [
{
"index": 1
}
],
"id": "port_21_to_port_10",
"sourceNode": "21",
"sourcePort": "21_out",
"targetNode": "10",
"targetPort": "10_in"
},
{
"conditions": [
{
"index": 2
}
],
"id": "port_21_to_port_11",
"sourceNode": "21",
"sourcePort": "21_out",
"targetNode": "11",
"targetPort": "11_in"
},
{
"conditions": [
{
"index": 3
}
],
"id": "port_21_to_port_12",
"sourceNode": "21",
"sourcePort": "21_out",
"targetNode": "12",
"targetPort": "12_in"
},
{
"id": "port_17_to_port_22",
"sourceNode": "17",
"sourcePort": "17_out",
"targetNode": "22",
"targetPort": "22_in"
},
{
"id": "port_18_to_port_23",
"sourceNode": "18",
"sourcePort": "18_out",
"targetNode": "23",
"targetPort": "23_in"
},
{
"id": "port_19_to_port_24",
"sourceNode": "19",
"sourcePort": "19_out",
"targetNode": "24",
"targetPort": "24_in"
},
{
"id": "port_6_to_port_1",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_22_to_port_1",
"sourceNode": "22",
"sourcePort": "22_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_23_to_port_1",
"sourceNode": "23",
"sourcePort": "23_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_24_to_port_1",
"sourceNode": "24",
"sourcePort": "24_out",
"targetNode": "1",
"targetPort": "1_in"
},
{
"id": "port_0_to_port_21",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "21",
"targetPort": "21_in"
},
{
"id": "port_2_to_port_27",
"sourceNode": "2",
"sourcePort": "2_out",
"targetNode": "27",
"targetPort": "27_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_27_to_port_9",
"sourceNode": "27",
"sourcePort": "27_out",
"targetNode": "9",
"targetPort": "9_in"
},
{
"id": "port_9_to_port_5",
"sourceNode": "9",
"sourcePort": "9_out",
"targetNode": "5",
"targetPort": "5_in"
},
{
"id": "port_10_to_port_29",
"sourceNode": "10",
"sourcePort": "10_out",
"targetNode": "29",
"targetPort": "29_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_29_to_port_13",
"sourceNode": "29",
"sourcePort": "29_out",
"targetNode": "13",
"targetPort": "13_in"
},
{
"id": "port_11_to_port_30",
"sourceNode": "11",
"sourcePort": "11_out",
"targetNode": "30",
"targetPort": "30_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_30_to_port_15",
"sourceNode": "30",
"sourcePort": "30_out",
"targetNode": "15",
"targetPort": "15_in"
},
{
"id": "port_12_to_port_31",
"sourceNode": "12",
"sourcePort": "12_out",
"targetNode": "31",
"targetPort": "31_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_31_to_port_16",
"sourceNode": "31",
"sourcePort": "31_out",
"targetNode": "16",
"targetPort": "16_in"
}
],
"globalCustomCode": "from math import log",
"hash": "a8238a3c739344494a1e62969d380c8f4791d45f",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"warnings": {},
"x": 530,
"y": -6.394884621840902e-13
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionId": 1,
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"userCode": "\n # This function is called after all actions are completed.\n # summary of all the action and/or all details of actions\n # can be collected here.\n\n # summary_json = phantom.get_summary()\n # if 'result' in summary_json:\n # for action_result in summary_json['result']:\n # if 'action_run_id' in action_result:\n # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)\n # phantom.debug(action_results)\n\n",
"warnings": {},
"x": 530,
"y": 1236
},
"10": {
"data": {
"action": "domain reputation",
"actionType": "investigate",
"advanced": {
"customName": "domain reputation",
"customNameId": 0,
"description": "Queries VirusTotal for information about the provided Domain(s)",
"join": [],
"note": "Queries VirusTotal for information about the provided Domain(s)"
},
"connector": "VirusTotal v3",
"connectorConfigs": [
"virustotal_v3"
],
"connectorId": "3fe4875d-a4a7-47d3-9ef1-f9e63a6653a4",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "domain_reputation",
"id": "10",
"parameters": {
"domain": "filtered-data:inputs_filter:condition_2:playbook_input:domain"
},
"requiredParameters": [
{
"data_type": "string",
"field": "domain"
}
],
"type": "action"
},
"errors": {},
"id": "10",
"type": "action",
"warnings": {},
"x": 340,
"y": 328
},
"11": {
"data": {
"action": "ip reputation",
"actionType": "investigate",
"advanced": {
"customName": "ip reputation",
"customNameId": 0,
"description": "Queries VirusTotal for information about the provided IP(s)",
"join": [],
"note": "Queries VirusTotal for information about the provided IP(s)"
},
"connector": "VirusTotal v3",
"connectorConfigs": [
"virustotal_v3"
],
"connectorId": "3fe4875d-a4a7-47d3-9ef1-f9e63a6653a4",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "ip_reputation",
"id": "11",
"parameters": {
"ip": "filtered-data:inputs_filter:condition_3:playbook_input:ip"
},
"requiredParameters": [
{
"data_type": "string",
"field": "ip"
}
],
"type": "action"
},
"errors": {},
"id": "11",
"type": "action",
"warnings": {},
"x": 680,
"y": 328
},
"12": {
"data": {
"action": "file reputation",
"actionType": "investigate",
"advanced": {
"customName": "file hash reputation",
"customNameId": 0,
"description": "Queries VirusTotal for information about the provided File Hash(es)",
"join": [],
"note": "Queries VirusTotal for information about the provided File Hash(es)"
},
"connector": "VirusTotal v3",
"connectorConfigs": [
"virustotal_v3"
],
"connectorId": "3fe4875d-a4a7-47d3-9ef1-f9e63a6653a4",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "file_hash_reputation",
"id": "12",
"parameters": {
"hash": "filtered-data:inputs_filter:condition_4:playbook_input:file_hash"
},
"requiredParameters": [
{
"data_type": "string",
"field": "hash"
}
],
"type": "action"
},
"errors": {},
"id": "12",
"type": "action",
"warnings": {},
"x": 1020,
"y": 328
},
"13": {
"data": {
"advanced": {
"customName": "normalize score domain",
"customNameId": 0,
"description": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections.",
"join": [],
"note": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections."
},
"functionId": 4,
"functionName": "normalize_score_domain",
"id": "13",
"inputParameters": [
"filtered-data:domain_result_filter:condition_1:domain_reputation:action_result.data.*.attributes.categories",
"filtered-data:domain_result_filter:condition_1:domain_reputation:action_result.summary"
],
"outputVariables": [
"domain_score_object",
"score",
"categories"
],
"type": "code"
},
"errors": {},
"id": "13",
"type": "code",
"userCode": "\n # Reference for scores: https://schema.ocsf.io/objects/reputation\n score_table = {\n \"0\":\"Unknown\",\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 # Assign Variables\n domain_categories_list = filtered_result_0_data___attributes_categories\n domain_summary_list = filtered_result_0_summary\n normalize_score_domain__domain_score_object = []\n normalize_score_domain__score = []\n normalize_score_domain__categories = []\n \n # VirusTotal v3 URL Data\n # Adjust logic as desired\n for category, summary_data in zip(domain_categories_list, domain_summary_list):\n \n # Set confidence based on percentage of vendors undetected\n # Reduce the confidence by percentage of vendors undetected.\n vendors = summary_data['harmless'] + summary_data['undetected'] + summary_data['malicious'] + summary_data['suspicious']\n confidence = 100 - int((summary_data['undetected']/vendors) * 100)\n \n # Normalize reputation on a 10 point scale based on number of malicious and suspicious divided by harmless vendors\n # This can be adjusted to include whatever logic is desired.\n suspect = summary_data['malicious'] + summary_data['suspicious']\n # If there are only harmless verdicts and no suspicious entries, set score_id to 1.\n if summary_data['harmless'] and not suspect:\n score_id = 1\n else:\n if suspect and vendors:\n # customize score calculation as desired\n log_result = log((suspect/vendors) * 100, 100) # log imported from math in global code block\n score_id = int(log_result * 10) + 3\n \n if score_id > 10:\n score_id = 10\n \n elif suspect == 0:\n score_id = 0\n \n categories = [cat.lower() for cat in category.values()]\n categories = list(set(categories))\n score = score_table[str(score_id)]\n \n # Attach final object\n normalize_score_domain__domain_score_object.append({'score': score, 'score_id': score_id, 'confidence': confidence, 'categories': categories})\n normalize_score_domain__score.append(score)\n normalize_score_domain__categories.append(categories)\n\n\n",
"warnings": {},
"x": 340,
"y": 700
},
"15": {
"data": {
"advanced": {
"customName": "normalize score ip",
"customNameId": 0,
"description": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections.",
"join": [],
"note": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections."
},
"functionId": 5,
"functionName": "normalize_score_ip",
"id": "15",
"inputParameters": [
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.summary"
],
"outputVariables": [
"ip_score_object",
"scores"
],
"type": "code"
},
"errors": {},
"id": "15",
"type": "code",
"userCode": "\n # Reference for scores: https://schema.ocsf.io/objects/reputation\n score_table = {\n \"0\":\"Unknown\",\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 ip_summary_list = filtered_result_0_summary\n normalize_score_ip__ip_score_object = []\n normalize_score_ip__scores = []\n \n for summary_data in ip_summary_list:\n # Set confidence based on percentage of vendors undetected\n # Reduce the confidence by percentage of vendors undetected.\n vendors = summary_data['harmless'] + summary_data['undetected'] + summary_data['malicious'] + summary_data['suspicious']\n confidence = 100 - int((summary_data['undetected']/vendors) * 100)\n \n # Normalize reputation on a 10 point scale based on number of malicious and suspicious divided by harmless vendors\n # This can be adjusted to include whatever logic is desired.\n suspect = summary_data['malicious'] + summary_data['suspicious']\n # If there are only harmless verdicts and no suspicious entries, set score_id to 1.\n if summary_data['harmless'] and not suspect:\n score_id = 1\n else:\n if suspect and vendors:\n # customize score calculation as desired\n log_result = log((suspect/vendors) * 100, 100) # log imported from math in global code block\n score_id = int(log_result * 10) + 3\n \n if score_id > 10:\n score_id = 10\n \n elif suspect == 0:\n score_id = 0\n \n score = score_table[str(score_id)]\n\n normalize_score_ip__ip_score_object.append({'score': score, 'score_id': score_id, 'confidence': confidence})\n normalize_score_ip__scores.append(score)\n \n",
"warnings": {},
"x": 680,
"y": 700
},
"16": {
"data": {
"advanced": {
"customName": "normalize score file",
"customNameId": 0,
"description": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections.",
"join": [],
"note": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections."
},
"functionId": 6,
"functionName": "normalize_score_file",
"id": "16",
"inputParameters": [
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.summary"
],
"outputVariables": [
"file_score_object",
"scores"
],
"type": "code"
},
"errors": {},
"id": "16",
"type": "code",
"userCode": "\n # Reference for scores: https://schema.ocsf.io/objects/reputation\n score_table = {\n \"0\":\"Unknown\",\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 file_summary_list = filtered_result_0_summary\n normalize_score_file__file_score_object = []\n normalize_score_file__scores = []\n \n for summary_data in file_summary_list:\n # Set confidence based on percentage of vendors undetected\n # Reduce the confidence by percentage of vendors undetected.\n vendors = summary_data['harmless'] + summary_data['undetected'] + summary_data['malicious'] + summary_data['suspicious']\n confidence = 100 - int((summary_data['undetected']/vendors) * 100)\n \n # Normalize reputation on a 10 point scale based on number of malicious and suspicious divided by harmless vendors\n # This can be adjusted to include whatever logic is desired.\n suspect = summary_data['malicious'] + summary_data['suspicious']\n # If there are only harmless verdicts and no suspicious entries, set score_id to 1.\n if summary_data['harmless'] and not suspect:\n score_id = 1\n else:\n if suspect and vendors:\n # customize score calculation as desired\n log_result = log((suspect/vendors) * 100, 100) # log imported from math in global code block\n score_id = int(log_result * 10) + 3\n \n if score_id > 10:\n score_id = 10\n \n elif suspect == 0:\n score_id = 0\n \n score = score_table[str(score_id)]\n\n normalize_score_file__file_score_object.append({'score': score, 'score_id': score_id, 'confidence': confidence})\n normalize_score_file__scores.append(score)\n",
"warnings": {},
"x": 1020,
"y": 680
},
"17": {
"data": {
"advanced": {
"customName": "format report domain",
"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": "format_report_domain",
"id": "17",
"parameters": [
"filtered-data:domain_result_filter:condition_1:domain_reputation:action_result.parameter.domain",
"normalize_score_domain:custom_function:score",
"normalize_score_domain:custom_function:categories"
],
"template": "SOAR analyzed Domain(s) using VirusTotal. The table below shows a summary of the information gathered.\n\n| Domain | Normalized Data | Categories | Report Link | Source |\n| --- | --- | --- | --- | --- |\n%%\n| `{0}` | {1} | {2} | https://www.virustotal.com/gui/domain/{0} | VirusTotal v3 |\n%%",
"type": "format"
},
"errors": {},
"id": "17",
"type": "format",
"warnings": {},
"x": 340,
"y": 880
},
"18": {
"data": {
"advanced": {
"customName": "format report ip",
"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": 3,
"functionName": "format_report_ip",
"id": "18",
"parameters": [
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.parameter.ip",
"normalize_score_ip:custom_function:scores"
],
"template": "SOAR analyzed IP(s) using VirusTotal. The table below shows a summary of the information gathered.\n\n| IP Address | Normalized Score | Report Link | Source |\n| --- | --- | --- | --- |\n%%\n| `{0}` | {1} | https://www.virustotal.com/gui/ip-address/{0} | VirusTotal v3 |\n%%",
"type": "format"
},
"errors": {},
"id": "18",
"type": "format",
"warnings": {},
"x": 680,
"y": 880
},
"19": {
"data": {
"advanced": {
"customName": "format report file",
"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": 4,
"functionName": "format_report_file",
"id": "19",
"parameters": [
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.parameter.hash",
"normalize_score_file:custom_function:scores",
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.data.*.attributes.meaningful_name",
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.data.*.attributes.magic"
],
"template": "SOAR analyzed file(s) using VirusTotal. The table below shows a summary of the information gathered.\n\n| File | VT Name | VT Decription | Normalized Score | Report Link | Source |\n| --- | --- | --- | --- | --- | --- |\n%%\n| `{0}` | {2} | {3} | {1} | https://www.virustotal.com/gui/file/{0} | VirusTotal v3 |\n%%\n\n",
"type": "format"
},
"errors": {},
"id": "19",
"type": "format",
"warnings": {},
"x": 1020,
"y": 880
},
"2": {
"data": {
"action": "url reputation",
"actionType": "investigate",
"advanced": {
"customName": "url reputation",
"customNameId": 0,
"description": "Queries VirusTotal for information about the provided URL(s)",
"join": [],
"note": "Queries VirusTotal for information about the provided URL(s)"
},
"connector": "VirusTotal v3",
"connectorConfigs": [
"virustotal_v3"
],
"connectorId": "3fe4875d-a4a7-47d3-9ef1-f9e63a6653a4",
"connectorVersion": "v1",
"functionId": 1,
"functionName": "url_reputation",
"id": "2",
"parameters": {
"url": "filtered-data:inputs_filter:condition_1:playbook_input:url"
},
"requiredParameters": [
{
"data_type": "string",
"field": "url"
}
],
"type": "action"
},
"errors": {},
"id": "2",
"type": "action",
"warnings": {},
"x": 0,
"y": 328
},
"21": {
"data": {
"advanced": {
"customName": "inputs filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"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",
"logic": "and"
},
{
"comparisons": [
{
"conditionIndex": 1,
"op": "!=",
"param": "playbook_input:domain",
"value": ""
}
],
"conditionIndex": 1,
"customName": "domain",
"logic": "and"
},
{
"comparisons": [
{
"conditionIndex": 2,
"op": "!=",
"param": "playbook_input:ip",
"value": ""
}
],
"conditionIndex": 2,
"customName": "ip",
"logic": "and"
},
{
"comparisons": [
{
"conditionIndex": 3,
"op": "!=",
"param": "playbook_input:file_hash",
"value": ""
}
],
"conditionIndex": 3,
"customName": "file_hash",
"logic": "and"
}
],
"functionId": 1,
"functionName": "inputs_filter",
"id": "21",
"type": "filter"
},
"errors": {},
"id": "21",
"type": "filter",
"warnings": {},
"x": 570,
"y": 148
},
"22": {
"data": {
"advanced": {
"customName": "build domain output",
"customNameId": 0,
"description": "Generate an observable dictionary to output into the observables data path.",
"join": [],
"note": "Generate an observable dictionary to output into the observables data path."
},
"functionId": 3,
"functionName": "build_domain_output",
"id": "22",
"inputParameters": [
"filtered-data:domain_result_filter:condition_1:domain_reputation:action_result.parameter.domain",
"normalize_score_domain:custom_function:domain_score_object"
],
"outputVariables": [
"observable_array"
],
"type": "code"
},
"errors": {},
"id": "22",
"type": "code",
"userCode": "\n build_domain_output__observable_array = []\n\n # Build URL\n for domain, domain_object in zip(filtered_result_0_parameter_domain, normalize_score_domain__domain_score_object):\n observable_object = {\n \"value\": domain,\n \"type\": \"domain\",\n \"reputation\": {\n \"score_id\": domain_object['score_id'],\n \"score\": domain_object['score'],\n \"confidence\": domain_object['confidence']\n },\n \"categories\": domain_object['categories'],\n \"source\": \"VirusTotal v3\",\n \"source_link\": f\"https://www.virustotal.com/gui/domain/{domain}\"\n }\n build_domain_output__observable_array.append(observable_object)\n \n\n",
"warnings": {},
"x": 340,
"y": 1060
},
"23": {
"data": {
"advanced": {
"customName": "build ip output",
"customNameId": 0,
"description": "Generate an observable dictionary to output into the observables data path.",
"join": [],
"note": "Generate an observable dictionary to output into the observables data path."
},
"functionId": 7,
"functionName": "build_ip_output",
"id": "23",
"inputParameters": [
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.parameter.ip",
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.data.*.attributes.country",
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.data.*.attributes.network",
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.data.*.attributes.as_owner",
"filtered-data:ip_result_filter:condition_1:ip_reputation:action_result.data.*.attributes.continent",
"normalize_score_ip:custom_function:ip_score_object"
],
"outputVariables": [
"observable_array"
],
"type": "code"
},
"errors": {},
"id": "23",
"type": "code",
"userCode": "\n build_ip_output__observable_array = []\n \n # Build IP\n for ip, country, network, as_owner, continent, ip_object in zip(\n filtered_result_0_parameter_ip, \n filtered_result_0_data___attributes_country,\n filtered_result_0_data___attributes_network,\n filtered_result_0_data___attributes_as_owner,\n filtered_result_0_data___attributes_continent,\n normalize_score_ip__ip_score_object\n ):\n observable_object = {\n \"value\": ip,\n \"type\": \"ip\",\n \"reputation\": {\n \"score_id\": ip_object['score_id'],\n \"score\": ip_object['score'],\n \"confidence\": ip_object['confidence']\n },\n \"enrichment\": {\n \"provider\": \"VirusTotal v3\",\n \"type\": \"whois\",\n \"data\": {\n \"country\": country,\n \"network\": network,\n \"as_owner\": as_owner,\n \"continent\": continent\n }\n },\n \"source\": \"VirusTotal v3\",\n \"source_link\": f\"https://www.virustotal.com/gui/ip-address/{ip}\"\n }\n build_ip_output__observable_array.append(observable_object)\n \n \n",
"warnings": {},
"x": 680,
"y": 1060
},
"24": {
"data": {
"advanced": {
"customName": "build file hash output",
"customNameId": 0,
"description": "Generate an observable dictionary to output into the observables data path.",
"join": [],
"note": "Generate an observable dictionary to output into the observables data path."
},
"functionId": 8,
"functionName": "build_file_hash_output",
"id": "24",
"inputParameters": [
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.parameter.hash",
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.data.*.attributes.meaningful_name",
"filtered-data:file_result_filter:condition_1:file_hash_reputation:action_result.data.*.attributes.type_description",
"normalize_score_file:custom_function:file_score_object"
],
"outputVariables": [
"observable_array"
],
"type": "code"
},
"errors": {},
"id": "24",
"type": "code",
"userCode": " \n build_file_hash_output__observable_array = []\n # Build file_hash\n for file_hash, file_name, file_type, file_object in zip(filtered_result_0_parameter_hash, filtered_result_0_data___attributes_meaningful_name, filtered_result_0_data___attributes_type_description, normalize_score_file__file_score_object):\n observable_object = {\n \"value\": file_hash,\n \"type\": \"hash\",\n \"reputation\": {\n \"score_id\": file_object['score_id'],\n \"score\": file_object['score'],\n \"confidence\": file_object['confidence']\n },\n \"enrichment\": {\n \"provider\": \"VirusTotal v3\",\n \"type\": \"file\",\n \"data\": {\n \"meaningful_name\": file_name,\n \"magic\": file_type\n }\n },\n \"source\": \"VirusTotal v3\",\n \"source_link\": f\"https://www.virustotal.com/gui/file/{file_hash}\"\n }\n \n build_file_hash_output__observable_array.append(observable_object)\n\n",
"warnings": {},
"x": 1020,
"y": 1060
},
"27": {
"data": {
"advanced": {
"customName": "url result filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"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",
"logic": "and"
}
],
"functionId": 2,
"functionName": "url_result_filter",
"id": "27",
"type": "filter"
},
"errors": {},
"id": "27",
"type": "filter",
"warnings": {},
"x": 60,
"y": 506
},
"29": {
"data": {
"advanced": {
"customName": "domain result filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"description": "Filters successful domain reputation results.",
"join": [],
"note": "Filters successful domain reputation results."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "==",
"param": "domain_reputation:action_result.status",
"value": "success"
}
],
"conditionIndex": 0,
"customName": "success",
"logic": "and"
}
],
"functionId": 3,
"functionName": "domain_result_filter",
"id": "29",
"type": "filter"
},
"errors": {},
"id": "29",
"type": "filter",
"warnings": {},
"x": 400,
"y": 506
},
"30": {
"data": {
"advanced": {
"customName": "ip result filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"description": "Filters successful ip reputation results.",
"join": [],
"note": "Filters successful ip reputation results."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "==",
"param": "ip_reputation:action_result.status",
"value": "success"
}
],
"conditionIndex": 0,
"customName": "success",
"logic": "and"
}
],
"functionId": 4,
"functionName": "ip_result_filter",
"id": "30",
"type": "filter"
},
"errors": {},
"id": "30",
"type": "filter",
"warnings": {},
"x": 740,
"y": 506
},
"31": {
"data": {
"advanced": {
"customName": "file result filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"description": "Filters successful file reputation results.",
"join": [],
"note": "Filters successful file reputation results."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "==",
"param": "file_hash_reputation:action_result.status",
"value": "success"
}
],
"conditionIndex": 0,
"customName": "success",
"logic": "and"
}
],
"functionId": 5,
"functionName": "file_result_filter",
"id": "31",
"type": "filter"
},
"errors": {},
"id": "31",
"type": "filter",
"warnings": {},
"x": 1080,
"y": 506
},
"5": {
"data": {
"advanced": {
"customName": "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": "format_report_url",
"id": "5",
"parameters": [
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.parameter.url",
"normalize_score_url:custom_function:score",
"normalize_score_url:custom_function:categories",
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.data.*.id"
],
"template": "SOAR analyzed URL(s) using VirusTotal. 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} | https://www.virustotal.com/gui/url/{3} | VirusTotal v3 |\n%%",
"type": "format"
},
"errors": {},
"id": "5",
"type": "format",
"warnings": {},
"x": 0,
"y": 880
},
"6": {
"data": {
"advanced": {
"customName": "build url output",
"customNameId": 0,
"description": "Generate an observable dictionary to output into the observables data path.",
"join": [],
"note": "Generate an observable dictionary to output into the observables data path."
},
"functionId": 1,
"functionName": "build_url_output",
"id": "6",
"inputParameters": [
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.parameter.url",
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.data.*.id",
"normalize_score_url:custom_function:url_score_object"
],
"outputVariables": [
"observable_array"
],
"type": "code"
},
"errors": {},
"id": "6",
"type": "code",
"userCode": " from urllib.parse import urlparse\n build_url_output__observable_array = []\n\n # Build URL\n for url, external_id, url_object in zip(filtered_result_0_parameter_url, filtered_result_0_data___id, normalize_score_url__url_score_object):\n parsed_url = urlparse(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 \"source\": \"VirusTotal v3\",\n \"source_link\": f\"https://www.virustotal.com/gui/url/{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 \n",
"warnings": {},
"x": 0,
"y": 1060
},
"9": {
"data": {
"advanced": {
"customName": "normalize score url",
"customNameId": 0,
"description": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections.",
"join": [],
"note": "Contains custom code for normalizing score. Adjust the logic as desired in the documented sections."
},
"functionId": 2,
"functionName": "normalize_score_url",
"id": "9",
"inputParameters": [
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.data.*.attributes.categories",
"filtered-data:url_result_filter:condition_1:url_reputation:action_result.summary"
],
"outputVariables": [
"url_score_object",
"score",
"categories"
],
"type": "code"
},
"errors": {},
"id": "9",
"type": "code",
"userCode": " \n # Reference for scores: https://schema.ocsf.io/objects/reputation\n score_table = {\n \"0\":\"Unknown\",\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 # Assign Variables\n url_categories_list = filtered_result_0_data___attributes_categories\n url_summary_list = filtered_result_0_summary\n normalize_score_url__url_score_object = []\n normalize_score_url__score = []\n normalize_score_url__categories = []\n \n # VirusTotal v3 URL Data\n # Adjust logic as desired\n for category, summary_data in zip(url_categories_list, url_summary_list):\n\n # Set confidence based on percentage of vendors undetected\n # Reduce the confidence by percentage of vendors undetected.\n vendors = summary_data['harmless'] + summary_data['undetected'] + summary_data['malicious'] + summary_data['suspicious']\n confidence = 100 - int((summary_data['undetected']/vendors) * 100)\n \n # Normalize reputation on a 10 point scale based on number of malicious and suspicious divided by harmless vendors\n # This can be adjusted to include whatever logic is desired.\n suspect = summary_data['malicious'] + summary_data['suspicious']\n # If there are only harmless verdicts and no suspicious entries, set score_id to 1.\n if summary_data['harmless'] and not suspect:\n score_id = 1\n else:\n if suspect and vendors:\n # customize score calculation as desired\n log_result = log((suspect/vendors) * 100, 100) # log imported from math in global code block\n score_id = int(log_result * 10) + 3\n \n if score_id > 10:\n score_id = 10\n \n elif suspect == 0:\n score_id = 0\n \n categories = [cat.lower() for cat in category.values()]\n categories = list(set(categories))\n \n score = score_table[str(score_id)]\n \n # Attach final object\n normalize_score_url__url_score_object.append({'score': score, 'score_id': score_id, 'confidence': confidence, 'categories': categories})\n normalize_score_url__score.append(score)\n normalize_score_url__categories.append(categories)\n\n",
"warnings": {},
"x": 0,
"y": 694
}
},
"notes": "Inputs: url, ip, domain, file_hash\nInteractions: VirusTotal v3\nActions: url reputation, ip reputation, domain reputation, file reputation\nOutputs: report, observables"
},
"input_spec": [
{
"contains": [
"url"
],
"description": "A URL provided for reputation analysis",
"name": "url"
},
{
"contains": [
"domain"
],
"description": "A Domain provided for reputation analysis",
"name": "domain"
},
{
"contains": [
"ip"
],
"description": "A IP provided for reputation analysis",
"name": "ip"
},
{
"contains": [
"hash",
"sha1",
"sha256",
"sha512",
"md5"
],
"description": "A file_hash provided for reputation analysis",
"name": "file_hash"
}
],
"output_spec": [
{
"contains": [],
"datapaths": [
"build_url_output:custom_function:observable_array",
"build_domain_output:custom_function:observable_array",
"build_ip_output:custom_function:observable_array",
"build_file_hash_output:custom_function:observable_array"
],
"deduplicate": false,
"description": "An array of observable dictionaries with value, type, score, score_id, and categories.",
"metadata": {},
"name": "observable"
},
{
"contains": [],
"datapaths": [
"format_report_url:formatted_data",
"format_report_domain:formatted_data",
"format_report_ip:formatted_data",
"format_report_file:formatted_data"
],
"deduplicate": false,
"description": "An array of reports. One report per reputation category.",
"metadata": {},
"name": "markdown_report"
}
],
"playbook_type": "data",
"python_version": "3.13",
"schema": "5.0.10",
"version": "6.0.1.123902"
},
"create_time": "2023-06-07T18:53:28.722388+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"reputation",
"url",
"ip",
"domain",
"file_hash",
"D3-IRA",
"D3-URA",
"D3-DNRA",
"D3-IPRA",
"D3-FHRA",
"VirusTotal_v3"
]
}