mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Merge pull request #1919 from splunk/playbook_mig_remcos
Playbook migration for remcos
This commit is contained in:
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
@@ -0,0 +1,297 @@
|
||||
"""
|
||||
This playbook retrieves IP addresses, domains, and file hashes, blocks them on various services, and adds them to specific blocklists as custom lists.
|
||||
"""
|
||||
|
||||
import phantom.rules as phantom
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
def on_start(container):
|
||||
phantom.debug('on_start() called')
|
||||
|
||||
# call 'filter_1' block
|
||||
filter_1(container=container)
|
||||
|
||||
# call 'filter_2' block
|
||||
filter_2(container=container)
|
||||
|
||||
# call 'filter_3' block
|
||||
filter_3(container=container)
|
||||
|
||||
return
|
||||
|
||||
def block_ip_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('block_ip_1() called')
|
||||
|
||||
# collect data for 'block_ip_1' call
|
||||
filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_4:condition_1:artifact:*.cef.destinationAddress', 'filtered-data:filter_4:condition_1:artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'block_ip_1' call
|
||||
for filtered_artifacts_item_1 in filtered_artifacts_data_1:
|
||||
if filtered_artifacts_item_1[0]:
|
||||
parameters.append({
|
||||
'ip': filtered_artifacts_item_1[0],
|
||||
'vsys': "",
|
||||
'is_source_address': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_artifacts_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="block ip", parameters=parameters, assets=['pan'], callback=add_to_IP_blocklist, name="block_ip_1")
|
||||
|
||||
return
|
||||
|
||||
def block_hash_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('block_hash_2() called')
|
||||
|
||||
# collect data for 'block_hash_2' call
|
||||
filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_6:condition_1:artifact:*.cef.fileHash', 'filtered-data:filter_6:condition_1:artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'block_hash_2' call
|
||||
for filtered_artifacts_item_1 in filtered_artifacts_data_1:
|
||||
if filtered_artifacts_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_artifacts_item_1[0],
|
||||
'comment': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_artifacts_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="block hash", parameters=parameters, assets=['carbonblack'], callback=add_to_hash_blocklist, name="block_hash_2")
|
||||
|
||||
return
|
||||
|
||||
def block_domain_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('block_domain_1() called')
|
||||
|
||||
# collect data for 'block_domain_1' call
|
||||
filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_5:condition_1:artifact:*.cef.destinationDnsDomain', 'filtered-data:filter_5:condition_1:artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'block_domain_1' call
|
||||
for filtered_artifacts_item_1 in filtered_artifacts_data_1:
|
||||
if filtered_artifacts_item_1[0]:
|
||||
parameters.append({
|
||||
'domain': filtered_artifacts_item_1[0],
|
||||
'disable_safeguards': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_artifacts_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="block domain", parameters=parameters, assets=['opendns_umbrella'], callback=add_to_domain_blocklist, name="block_domain_1")
|
||||
|
||||
return
|
||||
|
||||
def filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_2() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["artifact:*.cef.destinationDnsDomain", "!=", ""],
|
||||
],
|
||||
name="filter_2:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
filter_5(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
def filter_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_3() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["artifact:*.cef.fileHash", "!=", ""],
|
||||
],
|
||||
name="filter_3:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
filter_6(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Checking to see if this domain address is in the custom list called "domain_blocklist"
|
||||
"""
|
||||
def filter_5(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_5() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["filtered-data:filter_2:condition_1:artifact:*.cef.destinationDnsDomain", "in", "custom_list:domain_blocklist"],
|
||||
],
|
||||
name="filter_5:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
block_domain_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Checking to see if this filehash is in the custom list called "filehash_blocklist"
|
||||
"""
|
||||
def filter_6(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_6() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["filtered-data:filter_3:condition_1:artifact:*.cef.fileHash", "in", "custom_list:filehash_blocklist"],
|
||||
],
|
||||
name="filter_6:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
block_hash_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
The file hash is added to the custom list 'filehash_blocklist' in order to prevent the Playbook from attempting to block a file hash that has already been blocked.
|
||||
"""
|
||||
def add_to_hash_blocklist(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('add_to_hash_blocklist() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'add_to_hash_blocklist' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['block_hash_2:action_result.parameter.hash', 'block_hash_2:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'add_to_hash_blocklist' call
|
||||
for results_item_1 in results_data_1:
|
||||
if results_item_1[0]:
|
||||
parameters.append({
|
||||
'list': "custom_list:filehash_blocklist",
|
||||
'create': True,
|
||||
'new_row': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="add listitem", parameters=parameters, assets=['phantom'], name="add_to_hash_blocklist", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
The domain is added to the custom list 'domain_blocklist' in order to prevent the Playbook from attempting to block a domain that has already been blocked.
|
||||
"""
|
||||
def add_to_domain_blocklist(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('add_to_domain_blocklist() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'add_to_domain_blocklist' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['block_domain_1:action_result.parameter.domain', 'block_domain_1:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'add_to_domain_blocklist' call
|
||||
for results_item_1 in results_data_1:
|
||||
if results_item_1[0]:
|
||||
parameters.append({
|
||||
'list': "custom_list:domain_blocklist",
|
||||
'create': True,
|
||||
'new_row': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="add listitem", parameters=parameters, assets=['phantom'], name="add_to_domain_blocklist", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
The IP address is added to the custom list 'ip_address_blocklist' in order to prevent the Playbook from attempting to block an IP address that has already been blocked.
|
||||
"""
|
||||
def add_to_IP_blocklist(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('add_to_IP_blocklist() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'add_to_IP_blocklist' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['block_ip_1:action_result.parameter.ip', 'block_ip_1:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'add_to_IP_blocklist' call
|
||||
for results_item_1 in results_data_1:
|
||||
if results_item_1[0]:
|
||||
parameters.append({
|
||||
'list': "custom_list:ip_address_blocklist",
|
||||
'create': True,
|
||||
'new_row': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="add listitem", parameters=parameters, assets=['phantom'], name="add_to_IP_blocklist", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def filter_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_1() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["artifact:*.cef.destinationAddress", "!=", ""],
|
||||
],
|
||||
name="filter_1:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
filter_4(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Checking to see if this IP address is in the custom list called "ip_address_blocklist"
|
||||
"""
|
||||
def filter_4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_4() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["filtered-data:filter_1:condition_1:artifact:*.cef.destinationAddress", "not in", "custom_list:ip_address_blocklist"],
|
||||
],
|
||||
name="filter_4:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
block_ip_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
def on_finish(container, summary):
|
||||
phantom.debug('on_finish() called')
|
||||
# This function is called after all actions are completed.
|
||||
# summary of all the action and/or all details of actions
|
||||
# can be collected here.
|
||||
|
||||
# summary_json = phantom.get_summary()
|
||||
# if 'result' in summary_json:
|
||||
# for action_result in summary_json['result']:
|
||||
# if 'action_run_id' in action_result:
|
||||
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
|
||||
# phantom.debug(action_results)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Block Indicators
|
||||
id: fc0edc76-ff2b-48b0-5f6f-63da6783fd63
|
||||
version: 1
|
||||
date: '2021-01-21'
|
||||
author: Philip Royer, Splunk
|
||||
type: Response
|
||||
description: This playbook retrieves IP addresses, domains, and file hashes, blocks them on various services, and adds them to specific blocklists as custom lists.
|
||||
playbook: block_indicators
|
||||
how_to_implement: "This playbook uses the following custom lists: ip_address_blocklist, domain_blocklist, filehash_blocklist. This playbook provides an easy, automated, and straightforward solution to maintaining up-to-date IP address, file, and domain blocklists. The playbook looks for any of the required CEF fields within the container. The CEF value is then cross-referenced with their respective Custom Lists. IP addresses are blocked on a Firewall, while domains are blocked using a blocklist service. The blocking of these two will prevent access to the IOCs. Finally, file hashes are blocked using an endpoint protection service, which will prevent the process from running on affected endpoints within a network. After the IOCs are blocked using various apps, they are added to their respective custom lists as to maintain a running blocklist record."
|
||||
references: []
|
||||
app_list:
|
||||
- "Palo Alto Networks Firewall"
|
||||
- "CarbonBlack Response"
|
||||
- "OpenDNS Umbrella"
|
||||
tags:
|
||||
platform_tags:
|
||||
- Response
|
||||
playbook_fields:
|
||||
- destinationDnsDomain
|
||||
- destinationAddress
|
||||
- fileHash
|
||||
product:
|
||||
- Splunk SOAR
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
@@ -0,0 +1,338 @@
|
||||
"""
|
||||
This playbook tries to determine if a file is malware and whether or not the file is present on any managed machines. VirusTotal "file reputation" and PAN WildFire "detonate file" are used to determine if a file is malware, and CarbonBlack Response "hunt file" is used to search managed machines for the file. The results of these investigations are summarized in an email to the incident response team.
|
||||
"""
|
||||
|
||||
import phantom.rules as phantom
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
def on_start(container):
|
||||
phantom.debug('on_start() called')
|
||||
|
||||
# call 'filter_1' block
|
||||
filter_1(container=container)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Run a reputation lookup on the fileHash to determine how many antivirus engines recognize it as malware.
|
||||
"""
|
||||
def file_reputation_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('file_reputation_1() called')
|
||||
|
||||
# collect data for 'file_reputation_1' call
|
||||
filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_1:condition_1:artifact:*.cef.fileHash', 'filtered-data:filter_1:condition_1:artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'file_reputation_1' call
|
||||
for filtered_artifacts_item_1 in filtered_artifacts_data_1:
|
||||
if filtered_artifacts_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_artifacts_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_artifacts_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="file reputation", parameters=parameters, assets=['virustotal'], callback=filter_2, name="file_reputation_1")
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Hunt for binaries with the malicious fileHash across endpoints.
|
||||
"""
|
||||
def hunt_file_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('hunt_file_2() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'hunt_file_2' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_5:condition_1:detonate_file_1:action_result.data.*.file_info.md5", "filtered-data:filter_5:condition_1:detonate_file_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'hunt_file_2' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
if filtered_results_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'type': "",
|
||||
'range': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="hunt file", parameters=parameters, assets=['carbonblack'], callback=join_format_for_emailer, name="hunt_file_2")
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Detonate file requires a Vault file, so only proceed if vaultId is not null.
|
||||
"""
|
||||
def filter_4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_4() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["filtered-data:filter_3:condition_1:artifact:*.cef.vaultId", "!=", ""],
|
||||
],
|
||||
name="filter_4:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
detonate_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Only hunt files that are considered malware per the sandbox (malware == yes).
|
||||
"""
|
||||
def filter_5(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_5() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["detonate_file_1:action_result.summary.malware", "==", "yes"],
|
||||
],
|
||||
name="filter_5:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
hunt_file_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Match hashes with less than 10 positives to artifacts to identify filtered_artifacts.
|
||||
"""
|
||||
def filter_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_3() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["filtered-data:filter_2:condition_2:file_reputation_1:action_result.parameter.hash", "==", "artifact:*.cef.fileHash"],
|
||||
],
|
||||
name="filter_3:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
filter_4(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
If 10 or more antivirus engines flagged the hash, proceed directly to hunt for the file. Else, use a sandbox to detonate the executable first.
|
||||
"""
|
||||
def filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_2() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", ">=", 10],
|
||||
],
|
||||
name="filter_2:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
hunt_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 2
|
||||
matched_artifacts_2, matched_results_2 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", "<", 10],
|
||||
],
|
||||
name="filter_2:condition_2")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_2 or matched_results_2:
|
||||
filter_3(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Hunt for binaries with the malicious fileHash across endpoints.
|
||||
"""
|
||||
def hunt_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('hunt_file_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'hunt_file_1' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_2:condition_1:file_reputation_1:action_result.parameter.hash", "filtered-data:filter_2:condition_1:file_reputation_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'hunt_file_1' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
if filtered_results_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'type': "",
|
||||
'range': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="hunt file", parameters=parameters, assets=['carbonblack'], callback=join_format_for_emailer, name="hunt_file_1")
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Only process artifacts that have a CEF fileHash.
|
||||
"""
|
||||
def filter_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_1() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
conditions=[
|
||||
["artifact:*.cef.fileHash", "!=", ""],
|
||||
],
|
||||
name="filter_1:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
file_reputation_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Detonate the file(s) in the vault.
|
||||
"""
|
||||
def detonate_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('detonate_file_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'detonate_file_1' call
|
||||
filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_4:condition_1:artifact:*.cef.vaultId', 'filtered-data:filter_4:condition_1:artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'detonate_file_1' call
|
||||
for filtered_artifacts_item_1 in filtered_artifacts_data_1:
|
||||
if filtered_artifacts_item_1[0]:
|
||||
parameters.append({
|
||||
'vault_id': filtered_artifacts_item_1[0],
|
||||
'file_name': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_artifacts_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="detonate file", parameters=parameters, assets=['wildfire'], callback=filter_5, name="detonate_file_1")
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Send the formatted string as an email.
|
||||
"""
|
||||
def send_email_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('send_email_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'send_email_1' call
|
||||
formatted_data_1 = phantom.get_format_data(name='format_for_emailer')
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'send_email_1' call
|
||||
parameters.append({
|
||||
'cc': "",
|
||||
'to': "recipient@phantom.localhost",
|
||||
'bcc': "",
|
||||
'body': formatted_data_1,
|
||||
'from': "automation@phantom.localhost",
|
||||
'headers': "",
|
||||
'subject': "Malware event confirmed",
|
||||
'attachments': "",
|
||||
})
|
||||
|
||||
phantom.act(action="send email", parameters=parameters, assets=['smtp'], name="send_email_1")
|
||||
|
||||
return
|
||||
|
||||
"""
|
||||
Format all results for an email.
|
||||
"""
|
||||
def format_for_emailer(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('format_for_emailer() called')
|
||||
|
||||
template = """Malware in a security event has been confirmed using file reputation and/or file detonation services.
|
||||
|
||||
Reputation Results:
|
||||
Using file reputation services, the following file hashes have been identified as malware:
|
||||
{0}
|
||||
|
||||
EDR tool detects that the above file hashes are present on the following endpoints:
|
||||
{1}
|
||||
|
||||
Detonation Results:
|
||||
Using sandboxing services, the following file hashes have been identified as malware:
|
||||
{2}
|
||||
|
||||
The Phantom Vault ID for the malicious files, as determined by the sandbox service, are as follows:
|
||||
{3}
|
||||
|
||||
EDR tool detects that the file hashes indicated as positives per the sandbox service are present on the following endpoints:
|
||||
{4}
|
||||
|
||||
Container id: {5}
|
||||
|
||||
[EOM]"""
|
||||
|
||||
# parameter list for template variable replacement
|
||||
parameters = [
|
||||
"hunt_file_1:action_result.parameter.hash",
|
||||
"hunt_file_1:action_result.data.*.process.results.*.hostname",
|
||||
"filtered-data:filter_5:condition_1:detonate_file_1:action_result.data.*.file_info.md5",
|
||||
"filtered-data:filter_5:condition_1:detonate_file_1:action_result.parameter.vault_id",
|
||||
"hunt_file_2:action_result.data.*.process.results.*.hostname",
|
||||
"container:id",
|
||||
]
|
||||
|
||||
phantom.format(container=container, template=template, parameters=parameters, name="format_for_emailer")
|
||||
|
||||
send_email_1(container=container)
|
||||
|
||||
return
|
||||
|
||||
def join_format_for_emailer(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
|
||||
phantom.debug('join_format_for_emailer() called')
|
||||
|
||||
# check if all connected incoming playbooks, actions, or custom functions are done i.e. have succeeded or failed
|
||||
if phantom.completed(action_names=['hunt_file_1', 'hunt_file_2']):
|
||||
|
||||
# call connected block "format_for_emailer"
|
||||
format_for_emailer(container=container, handle=handle)
|
||||
|
||||
return
|
||||
|
||||
def on_finish(container, summary):
|
||||
phantom.debug('on_finish() called')
|
||||
# This function is called after all actions are completed.
|
||||
# summary of all the action and/or all details of actions
|
||||
# can be collected here.
|
||||
|
||||
# summary_json = phantom.get_summary()
|
||||
# if 'result' in summary_json:
|
||||
# for action_result in summary_json['result']:
|
||||
# if 'action_run_id' in action_result:
|
||||
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
|
||||
# phantom.debug(action_results)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Email Notification for Malware
|
||||
id: fb3edc76-ff2b-48b0-5f6f-63da6483fd63
|
||||
version: 1
|
||||
date: '2021-01-19'
|
||||
author: Philip Royer, Splunk
|
||||
type: Response
|
||||
description: This playbook tries to determine if a file is malware and whether or not the file is present on any managed machines. VirusTotal "file reputation" and PAN WildFire "detonate file" are used to determine if a file is malware, and CarbonBlack Response "hunt file" is used to search managed machines for the file. The results of these investigations are summarized in an email to the incident response team.
|
||||
playbook: email_notification_for_malware
|
||||
how_to_implement: "Be sure to update asset naming to reflect the asset names configured in your environment."
|
||||
references: []
|
||||
app_list:
|
||||
- "VirusTotal"
|
||||
- "WildFire"
|
||||
- "CarbonBlack Response"
|
||||
- "SMTP"
|
||||
tags:
|
||||
platform_tags:
|
||||
- Response
|
||||
playbook_fields:
|
||||
- fileHash
|
||||
- vaultId
|
||||
product:
|
||||
- Splunk SOAR
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 375 KiB |
@@ -0,0 +1,456 @@
|
||||
"""
|
||||
This playbook investigates and remediates malware infections on the endpoint.
|
||||
"""
|
||||
|
||||
import phantom.rules as phantom
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
##############################
|
||||
# Start - Global Code Block
|
||||
|
||||
"""Malicous file detected on endpoint"""
|
||||
|
||||
# End - Global Code block
|
||||
##############################
|
||||
|
||||
def on_start(container):
|
||||
phantom.debug('on_start() called')
|
||||
|
||||
# call 'file_reputation_1' block
|
||||
file_reputation_1(container=container)
|
||||
|
||||
return
|
||||
|
||||
def filter_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_3() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", ">", 5],
|
||||
["file_reputation_1:action_result.summary.positives", "<=", 10],
|
||||
],
|
||||
logical_operator='and',
|
||||
name="filter_3:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
create_ticket_3(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
def shutdown_system_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('shutdown_system_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'shutdown_system_1' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_2:action_result.data.*.process.results.*.hostname', 'hunt_file_2:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'shutdown_system_1' call
|
||||
for results_item_1 in results_data_1:
|
||||
parameters.append({
|
||||
'ph': "",
|
||||
'message': "",
|
||||
'wait_time': "",
|
||||
'ip_hostname': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="shutdown system", parameters=parameters, assets=['domainctrl1'], callback=join_filter_2, name="shutdown_system_1", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def create_ticket_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'create_ticket_2' call
|
||||
|
||||
disabled_users = set(phantom.collect2(datapath='disable_user_1:action_result.parameter.username'))
|
||||
blocked_hashes = set(phantom.collect2(datapath='block_hash_3:action_result.parameter.hash'))
|
||||
loggedoff_users = set(phantom.collect2(datapath='logoff_user_1:action_result.parameter.username'))
|
||||
shutdown_systems = set(phantom.collect2(datapath='shutdown_system_1:action_result.parameter.ip_hostname'))
|
||||
file_reputation = phantom.collect2(datapath=['file_reputation_1:filtered-action_result.parameter.hash',
|
||||
'file_reputation_1:filtered-action_result.summary.positives'])
|
||||
detected_users = set(phantom.collect2(datapath='hunt_file_2:action_result.data.*.process.results.*.username'))
|
||||
detected_systems = set(phantom.collect2(datapath='hunt_file_2:action_result.data.*.process.results.*.hostname'))
|
||||
|
||||
title = "Virus Detected on {0} devices".format(len(detected_systems))
|
||||
|
||||
description = "Hashes sumbitted with detections:\n{0}\n\n".format(", ".join(["{0} ({1})".format(*fr) for fr in file_reputation]))
|
||||
description += "File was found on {0} devices:\n{1}\n\n".format(len(detected_systems), ', '.join(detected_systems))
|
||||
description += "This impacts at least {0} users:\n{1}\n\n".format(len(detected_users), ', '.join(detected_users))
|
||||
if len(blocked_hashes):
|
||||
description += "{0} hashes were submitted for blocking:\n{1}\n\n".format(len(blocked_hashes), ", ".join(blocked_hashes))
|
||||
if len(loggedoff_users):
|
||||
description += "{0} users were forced to logoff:\n{1}\n\n".format(len(loggedoff_users), ", ".join(loggedoff_users))
|
||||
if len(disabled_users):
|
||||
description += "{0} user accounts were disabled:\n{1}\n\n".format(len(disabled_users), ", ".join(disabled_users))
|
||||
if len(shutdown_systems):
|
||||
description += "{0} systems were shutdown:\n{1}\n\n".format(len(shutdown_systems), ", ".join(shutdown_systems))
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'create_ticket_2' call
|
||||
parameters.append({
|
||||
'short_description': title,
|
||||
'description': description,
|
||||
'fields': "",
|
||||
})
|
||||
|
||||
if parameters:
|
||||
phantom.act("create ticket", parameters=parameters, assets=['servicenow'], name="create_ticket_2", parent_action=action)
|
||||
else:
|
||||
phantom.error("'create_ticket_2' will not be executed due to lack of parameters")
|
||||
|
||||
return
|
||||
|
||||
def filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_2() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", ">", 10],
|
||||
],
|
||||
name="filter_2:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
create_ticket_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
return
|
||||
|
||||
def join_filter_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
|
||||
phantom.debug('join_filter_2() called')
|
||||
|
||||
# check if all connected incoming playbooks, actions, or custom functions are done i.e. have succeeded or failed
|
||||
if phantom.completed(action_names=['logoff_user_1', 'shutdown_system_1', 'disable_user_1', 'block_hash_3']):
|
||||
|
||||
# call connected block "filter_2"
|
||||
filter_2(container=container, handle=handle)
|
||||
|
||||
return
|
||||
|
||||
def logoff_user_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('logoff_user_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'logoff_user_1' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_2:action_result.data.*.process.results.*.hostname', 'hunt_file_2:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'logoff_user_1' call
|
||||
for results_item_1 in results_data_1:
|
||||
parameters.append({
|
||||
'username': "",
|
||||
'ip_hostname': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="logoff user", parameters=parameters, assets=['domainctrl1'], callback=join_filter_2, name="logoff_user_1", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def filter_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('filter_1() called')
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 1
|
||||
matched_artifacts_1, matched_results_1 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", ">", 5],
|
||||
["file_reputation_1:action_result.summary.positives", "<=", 10],
|
||||
],
|
||||
logical_operator='and',
|
||||
name="filter_1:condition_1")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_1 or matched_results_1:
|
||||
hunt_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
get_file_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1)
|
||||
|
||||
# collect filtered artifact ids for 'if' condition 2
|
||||
matched_artifacts_2, matched_results_2 = phantom.condition(
|
||||
container=container,
|
||||
action_results=results,
|
||||
conditions=[
|
||||
["file_reputation_1:action_result.summary.positives", ">", 10],
|
||||
],
|
||||
name="filter_1:condition_2")
|
||||
|
||||
# call connected blocks if filtered artifacts or results
|
||||
if matched_artifacts_2 or matched_results_2:
|
||||
hunt_file_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2)
|
||||
get_file_3(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function, filtered_artifacts=matched_artifacts_2, filtered_results=matched_results_2)
|
||||
|
||||
return
|
||||
|
||||
def hunt_file_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('hunt_file_2() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'hunt_file_2' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_2:file_reputation_1:action_result.parameter.hash", "filtered-data:filter_1:condition_2:file_reputation_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'hunt_file_2' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
if filtered_results_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'type': "",
|
||||
'range': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="hunt file", parameters=parameters, assets=['carbonblack'], callback=hunt_file_2_callback, name="hunt_file_2")
|
||||
|
||||
return
|
||||
|
||||
def hunt_file_2_callback(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
|
||||
phantom.debug('hunt_file_2_callback() called')
|
||||
|
||||
disable_user_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
|
||||
logoff_user_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
|
||||
shutdown_system_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
|
||||
block_hash_3(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
|
||||
|
||||
return
|
||||
|
||||
def get_file_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('get_file_3() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'get_file_3' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_2:file_reputation_1:action_result.parameter.hash", "filtered-data:filter_1:condition_2:file_reputation_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'get_file_3' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'ph_0': "",
|
||||
'offset': "",
|
||||
'get_count': "",
|
||||
'sensor_id': "",
|
||||
'file_source': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="get file", parameters=parameters, assets=['carbonblack'], name="get_file_3")
|
||||
|
||||
return
|
||||
|
||||
def get_file_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('get_file_2() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'get_file_2' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_1:file_reputation_1:action_result.parameter.hash", "filtered-data:filter_1:condition_1:file_reputation_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'get_file_2' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'ph_0': "",
|
||||
'offset': "",
|
||||
'get_count': "",
|
||||
'sensor_id': "",
|
||||
'file_source': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="get file", parameters=parameters, assets=['carbonblack'], name="get_file_2")
|
||||
|
||||
return
|
||||
|
||||
def create_ticket_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'create_ticket_2' call
|
||||
|
||||
file_reputation = phantom.collect2(datapath=['file_reputation_1:filtered-action_result.parameter.hash',
|
||||
'file_reputation_1:filtered-action_result.summary.positives'])
|
||||
blocked_hashes = set(phantom.collect2(datapath='block_hash_2:action_result.parameter.hash'))
|
||||
detected_users = set(phantom.collect2(datapath='hunt_file_1:action_result.data.*.process.results.*.username'))
|
||||
detected_systems = set(phantom.collect2(datapath='hunt_file_1:action_result.data.*.process.results.*.hostname'))
|
||||
|
||||
title = "Virus Detected on {0} devices".format(len(detected_systems))
|
||||
|
||||
description = "Hashes sumbitted with detections:\n{0}\n\n".format(", ".join(["{0} ({1})".format(*fr) for fr in file_reputation]))
|
||||
description += "File was found on {0} devices:\n{1}\n\n".format(len(detected_systems), ', '.join(detected_systems))
|
||||
description += "This impacts at least {0} users:\n{1}\n\n".format(len(detected_users), ', '.join(detected_users))
|
||||
if len(blocked_hashes):
|
||||
description += "{0} hashes were submitted for blocking:\n{1}\n\n".format(len(blocked_hashes), ", ".join(blocked_hashes))
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'create_ticket_2' call
|
||||
parameters.append({
|
||||
'short_description': title,
|
||||
'description': description,
|
||||
'fields': "",
|
||||
})
|
||||
|
||||
if parameters:
|
||||
phantom.act("create ticket", parameters=parameters, assets=['servicenow'], name="create_ticket_3", parent_action=action)
|
||||
else:
|
||||
phantom.error("'create_ticket_3' will not be executed due to lack of parameters")
|
||||
|
||||
return
|
||||
|
||||
def disable_user_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('disable_user_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'disable_user_1' call
|
||||
results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_2:action_result.data.*.process.results.*.username', 'hunt_file_2:action_result.parameter.context.artifact_id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'disable_user_1' call
|
||||
for results_item_1 in results_data_1:
|
||||
if results_item_1[0]:
|
||||
parameters.append({
|
||||
'username': results_item_1[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="disable user", parameters=parameters, assets=['domainctrl1'], callback=join_filter_2, name="disable_user_1", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def block_hash_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('block_hash_3() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'block_hash_3' call
|
||||
inputs_data_1 = phantom.collect2(container=container, datapath=['hunt_file_2:artifact:*.cef.fileHash', 'hunt_file_2:artifact:*.id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'block_hash_3' call
|
||||
for inputs_item_1 in inputs_data_1:
|
||||
if inputs_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': inputs_item_1[0],
|
||||
'comment': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': inputs_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="block hash", parameters=parameters, assets=['carbonblack'], callback=join_filter_2, name="block_hash_3", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def hunt_file_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('hunt_file_1() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'hunt_file_1' call
|
||||
filtered_results_data_1 = phantom.collect2(container=container, datapath=["filtered-data:filter_1:condition_1:file_reputation_1:action_result.parameter.hash", "filtered-data:filter_1:condition_1:file_reputation_1:action_result.parameter.context.artifact_id"])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'hunt_file_1' call
|
||||
for filtered_results_item_1 in filtered_results_data_1:
|
||||
if filtered_results_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': filtered_results_item_1[0],
|
||||
'type': "binary",
|
||||
'range': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': filtered_results_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="hunt file", parameters=parameters, assets=['carbonblack'], callback=block_hash_2, name="hunt_file_1")
|
||||
|
||||
return
|
||||
|
||||
def block_hash_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('block_hash_2() called')
|
||||
|
||||
#phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
|
||||
|
||||
# collect data for 'block_hash_2' call
|
||||
inputs_data_1 = phantom.collect2(container=container, datapath=['hunt_file_1:artifact:*.cef.fileHash', 'hunt_file_1:artifact:*.id'], action_results=results)
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'block_hash_2' call
|
||||
for inputs_item_1 in inputs_data_1:
|
||||
if inputs_item_1[0]:
|
||||
parameters.append({
|
||||
'hash': inputs_item_1[0],
|
||||
'comment': "",
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': inputs_item_1[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="block hash", parameters=parameters, assets=['carbonblack'], callback=filter_3, name="block_hash_2", parent_action=action)
|
||||
|
||||
return
|
||||
|
||||
def file_reputation_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
|
||||
phantom.debug('file_reputation_1() called')
|
||||
|
||||
# collect data for 'file_reputation_1' call
|
||||
container_data = phantom.collect2(container=container, datapath=['artifact:*.cef.fileHash', 'artifact:*.id'])
|
||||
|
||||
parameters = []
|
||||
|
||||
# build parameters list for 'file_reputation_1' call
|
||||
for container_item in container_data:
|
||||
if container_item[0]:
|
||||
parameters.append({
|
||||
'hash': container_item[0],
|
||||
# context (artifact id) is added to associate results with the artifact
|
||||
'context': {'artifact_id': container_item[1]},
|
||||
})
|
||||
|
||||
phantom.act(action="file reputation", parameters=parameters, assets=['virustotal'], callback=filter_1, name="file_reputation_1")
|
||||
|
||||
return
|
||||
|
||||
def on_finish(container, summary):
|
||||
phantom.debug('on_finish() called')
|
||||
# This function is called after all actions are completed.
|
||||
# summary of all the action and/or all details of actions
|
||||
# can be collected here.
|
||||
|
||||
# summary_json = phantom.get_summary()
|
||||
# if 'result' in summary_json:
|
||||
# for action_result in summary_json['result']:
|
||||
# if 'action_run_id' in action_result:
|
||||
# action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False)
|
||||
# phantom.debug(action_results)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Malware Hunt and Contain
|
||||
id: fb3edc76-ff2b-43c0-5f6f-63da4483fd63
|
||||
version: 1
|
||||
date: '2021-01-21'
|
||||
author: Philip Royer, Splunk
|
||||
type: Response
|
||||
description: This playbook investigates and remediates malware infections on the endpoint.
|
||||
playbook: malware_hunt_and_contain
|
||||
how_to_implement: "Be sure to update asset naming to reflect the asset names configured in your environment."
|
||||
references: []
|
||||
app_list:
|
||||
- "LDAP"
|
||||
- "ServiceNow"
|
||||
- "CarbonBlack Response"
|
||||
- "VirusTotal"
|
||||
tags:
|
||||
platform_tags:
|
||||
- Response
|
||||
playbook_fields:
|
||||
- fileHash
|
||||
product:
|
||||
- Splunk SOAR
|
||||
Reference in New Issue
Block a user