"""
Enrich and respond to a CrowdStrike Falcon detection involving a potentially malicious executable on an endpoint. Check for previous sightings of the same executable, hunt across other endpoints for the file, gather details about all processes associated with the file, and collect all the gathered information into a prompt for an analyst to review. Based on the analyst's choice, the file can be added to the custom indicators list in CrowdStrike with a detection policy of "detect" or "none", and the endpoint can be optionally quarantined from the network.
"""

import phantom.rules as phantom
import json
from datetime import datetime, timedelta
def on_start(container):
    phantom.debug('on_start() called')
    
    # call 'if_sha256_exists' block
    if_sha256_exists(container=container)

    return

"""
List all machines where the file hash has been seen.
"""
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_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'hunt_file_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],
                'count_only': False,
                # context (artifact id) is added to associate results with the artifact
                'context': {'artifact_id': filtered_artifacts_item_1[1]},
            })

    phantom.act(action="hunt file", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_system_info_1, name="hunt_file_1")

    return

"""
Ensure that the event has at least one artifact with a SHA256 file hash before attempting to process the event.
"""
def if_sha256_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('if_sha256_exists() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        conditions=[
            ["artifact:*.cef.fileHashSha256", "!=", ""],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        filter_main_artifact(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # call connected blocks for 'else' condition 2
    ignore_if_no_sha256(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
End the playbook if no SHA256 file hash is found in any of the artifacts.
"""
def ignore_if_no_sha256(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('ignore_if_no_sha256() called')

    phantom.comment(container=container, comment="Ignoring alert because no SHA256 file hash was found")

    return

"""
Fetch the CrowdStrike indicator for the SHA256 file hash, if there is one. This action will fail if there is no matching indicator in CrowdStrike, but the playbook will check for the failure and continue.
"""
def get_indicator_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('get_indicator_2() called')

    # collect data for 'get_indicator_2' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'get_indicator_2' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        if filtered_artifacts_item_1[0]:
            parameters.append({
                'indicator_type': "sha256",
                'indicator_value': 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="get indicator", parameters=parameters, assets=['crowdstrike_oauth'], callback=if_indicator_exists, name="get_indicator_2")

    return

"""
Determine which response to take based on whether an Indicator exists in CrowdStrike for the SHA256 file hash.
"""
def if_indicator_exists(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('if_indicator_exists() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["Resource Not Found", "in", "get_indicator_2:action_result.message"],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        hunt_file_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        list_processes_with_hash(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # call connected blocks for 'else' condition 2
    indicator_policy_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
Escalate the event because the Indicator policy is "detect", meaning the event is a true positive.
"""
def escalate_severity_to_high(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('escalate_severity_to_high() called')

    phantom.set_severity(container=container, severity="High")

    return

"""
Format a note to summarize all known information about the event.
"""
def format_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('format_repeat_note() called')
    
    template = """CrowdStrike detected a file on an endpoint which matched a previously detected file hash: 

| Field | Value |
|---|---|
| Host | {0} |
| Command Line | {1} |
| SHA 256 | {2} |
| File Path | {3}\\\\{4} |
| CrowdStrike Detection Link | {5} |  

---

This event will have the severity escalated to high, and should be investigated further."""

    # parameter list for template variable replacement
    parameters = [
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
    ]

    phantom.format(container=container, template=template, parameters=parameters, name="format_repeat_note")

    add_repeat_note(container=container)

    return

"""
Add a note to summarize the event information.
"""
def add_repeat_note(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('add_repeat_note() called')

    formatted_data_1 = phantom.get_format_data(name='format_repeat_note')

    note_title = "Known Malicious File"
    note_content = formatted_data_1
    note_format = "markdown"
    phantom.add_note(container=container, note_type="general", title=note_title, content=note_content, note_format=note_format)
    crowdstrike_known_file_quarantine(container=container)

    return

"""
Only process the main detection artifact, not any sub event artifacts.
"""
def filter_main_artifact(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('filter_main_artifact() called')

    # collect filtered artifact ids for 'if' condition 1
    matched_artifacts_1, matched_results_1 = phantom.condition(
        container=container,
        conditions=[
            ["artifact:*.label", "==", "event"],
        ],
        name="filter_main_artifact:condition_1")

    # call connected blocks if filtered artifacts or results
    if matched_artifacts_1 or matched_results_1:
        get_indicator_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

"""
Handle the Indicator differently if the policy is "detect", "none", or other.
"""
def indicator_policy_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('indicator_policy_decision() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["get_indicator_2:action_result.data.*.resources.*.policy", "==", "none"],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        detection_policy_none(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # check for 'elif' condition 2
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["get_indicator_2:action_result.data.*.resources.*.policy", "==", "detect"],
        ])

    # call connected blocks if condition 2 matched
    if matched:
        escalate_severity_to_high(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        format_repeat_note(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # call connected blocks for 'else' condition 3
    comment_unexpected_policy(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
End processing because this playbook only expects "none" or "detect" as the Indicator policy.
"""
def comment_unexpected_policy(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('comment_unexpected_policy() called')

    phantom.comment(container=container, comment="The playbook received an unexpected indicator policy and needs to be extended to handle this situation.")

    return

"""
Add a comment to explain why the event is being closed.
"""
def detection_policy_none(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('detection_policy_none() called')

    phantom.comment(container=container, comment="The file hash indicator has a detection policy of none, so previous investigations have found that the file is not harmful. This playbook will take no further action and the event will be closed.")
    close_event(container=container)

    return

"""
Fetch additional information about each machine listed in the previous step.
"""
def get_system_info_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('get_system_info_1() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'get_system_info_1' call
    results_data_1 = phantom.collect2(container=container, datapath=['hunt_file_1:action_result.data.*.device_id', 'hunt_file_1:action_result.parameter.context.artifact_id'], action_results=results)

    parameters = []
    
    # build parameters list for 'get_system_info_1' call
    for results_item_1 in results_data_1:
        if results_item_1[0]:
            parameters.append({
                'id': 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="get system info", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name="get_system_info_1", parent_action=action)

    return

"""
Summarize all the gathered information to help the analyst decide a response in the prompt.
"""
def format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('format_prompt() called')
    
    template = """CrowdStrike detected the following suspicious activity on an endpoint:

| Field | Value |
|---|---|
| Host | {0} |
| Command Line | {1} |
| SHA 256 | {2} |
| File Path | {3}\\\\{4}
| CrowdStrike Detection Link | {5} |
| Details of processes associated with the file hash | <see \"get process details\" action results> |
| Count of machines that have the file on disk | {6} |
| System information of machines that have the file on disk | <see \"get system info\" action results> |"""

    # parameter list for template variable replacement
    parameters = [
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sourceHostName",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.cmdLine",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.filePath",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileName",
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
        "hunt_file_1:action_result.summary.device_count",
    ]

    phantom.format(container=container, template=template, parameters=parameters, name="format_prompt")

    crowdstrike_new_file_detection(container=container)

    return

def join_format_prompt(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
    phantom.debug('join_format_prompt() called')
    
    # if the joined function has already been called, do nothing
    if phantom.get_run_data(key='join_format_prompt_called'):
        return

    # check if all connected incoming playbooks, actions, or custom functions are done i.e. have succeeded or failed
    if phantom.completed(action_names=['get_process_details']):
        
        # save the state that the joined function has now been called
        phantom.save_run_data(key='join_format_prompt_called', value='format_prompt')
        
        # call connected block "format_prompt"
        format_prompt(container=container, handle=handle)
    
    return

"""
Close the event because the Indicator policy is "none", meaning the detection is a false positive.
"""
def close_event(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('close_event() called')

    phantom.set_status(container=container, status="Closed")

    return

"""
List all processes seen on this host associated with this file hash.
"""
def list_processes_with_hash(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('list_processes_with_hash() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'list_processes_with_hash' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'list_processes_with_hash' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        if filtered_artifacts_item_1[0] and filtered_artifacts_item_1[1]:
            parameters.append({
                'id': filtered_artifacts_item_1[0],
                'ioc': filtered_artifacts_item_1[1],
                # context (artifact id) is added to associate results with the artifact
                'context': {'artifact_id': filtered_artifacts_item_1[2]},
            })

    phantom.act(action="list processes", parameters=parameters, assets=['crowdstrike_oauth'], callback=get_process_details, name="list_processes_with_hash")

    return

"""
Fetch additional information about each process listed in the previous step.
"""
def get_process_details(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('get_process_details() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'get_process_details' call
    results_data_1 = phantom.collect2(container=container, datapath=['list_processes_with_hash:action_result.data.*.falcon_process_id', 'list_processes_with_hash:action_result.parameter.context.artifact_id'], action_results=results)

    parameters = []
    
    # build parameters list for 'get_process_details' call
    for results_item_1 in results_data_1:
        if results_item_1[0]:
            parameters.append({
                'falcon_process_id': 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="get process detail", parameters=parameters, assets=['crowdstrike_oauth'], callback=join_format_prompt, name="get_process_details", parent_action=action)

    return

"""
Prompt the user to determine whether or not to create an Indicator for the file hash and whether or not to quarantine the endpoint.
"""
def crowdstrike_new_file_detection(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('crowdstrike_new_file_detection() called')
    
    # set user and message variables for phantom.prompt call
    user = "admin"
    message = """{0}"""

    # parameter list for template variable replacement
    parameters = [
        "format_prompt:formatted_data",
    ]

    #responses:
    response_types = [
        {
            "prompt": "Should Phantom create an Indicator in CrowdStrike to track this file hash from now on?",
            "options": {
                "type": "list",
                "choices": [
                    "No, do not create an Indicator in CrowdStrike at this time.",
                    "Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)",
                    "Yes, create a CrowdStrike Indicator to ignore this file hash from now on. (False Positive)",
                ]
            },
        },
        {
            "prompt": "Should Phantom quarantine the endpoint?",
            "options": {
                "type": "list",
                "choices": [
                    "Yes",
                    "No",
                ]
            },
        },
    ]

    phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="crowdstrike_new_file_detection", parameters=parameters, response_types=response_types, callback=crowdstrike_new_file_detection_callback)

    return

def crowdstrike_new_file_detection_callback(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None):
    phantom.debug('crowdstrike_new_file_detection_callback() called')
    
    indicator_decision(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
    quarantine_decision_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
Parse the prompt response to determine how to handle the indicator.
"""
def indicator_decision(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('indicator_decision() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["No, do not create an Indicator in CrowdStrike at this time.", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        comment_no_indicator(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # check for 'elif' condition 2
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["Yes, create a CrowdStrike Indicator to detect and block this file hash from now on. (True Positive)", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
        ])

    # call connected blocks if condition 2 matched
    if matched:
        format_detect_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # check for 'elif' condition 3
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["Yes, create a CrowdStrike Indicator to ignore this file hash going forward (False Positive)", "==", "crowdstrike_new_file_detection:action_result.summary.responses.0"],
        ])

    # call connected blocks if condition 3 matched
    if matched:
        format_ignore_description(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    return

"""
Check the quarantine device prompt response.
"""
def quarantine_decision_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('quarantine_decision_1() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["crowdstrike_new_file_detection:action_result.summary.responses.1", "==", "Yes"],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        quarantine_device_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # call connected blocks for 'else' condition 2
    comment_no_quarantine_1(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
Create an Indicator in CrowdStrike with a policy of "none" to ignore detections based on this file hash in the future.
"""
def create_ignore_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('create_ignore_indicator() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'create_ignore_indicator' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])
    formatted_data_1 = phantom.get_format_data(name='format_ignore_description')

    parameters = []
    
    # build parameters list for 'create_ignore_indicator' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        if filtered_artifacts_item_1[0]:
            parameters.append({
                'ioc': filtered_artifacts_item_1[0],
                'policy': "none",
                'source': "Phantom Playbook crowdstrike_malware_triage",
                'expiration': "",
                'description': formatted_data_1,
                'share_level': "red",
                # context (artifact id) is added to associate results with the artifact
                'context': {'artifact_id': filtered_artifacts_item_1[1]},
            })

    phantom.act(action="upload indicator", parameters=parameters, assets=['crowdstrike_oauth'], name="create_ignore_indicator")

    return

"""
Format a description to provide when creating an Indicator with a policy of "none".
"""
def format_ignore_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('format_ignore_description() called')
    
    template = """This indicator was created by Phantom in the playbook crowdstrike_malware_triage to ignore CrowdStrike detections based on the file hash first seen in {0} and processed in Phantom as {1}"""

    # parameter list for template variable replacement
    parameters = [
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
        "container:url",
    ]

    phantom.format(container=container, template=template, parameters=parameters, name="format_ignore_description")

    create_ignore_indicator(container=container)

    return

"""
Explain in a comment that no Indicator will be created.
"""
def comment_no_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('comment_no_indicator() called')

    phantom.comment(container=container, comment="The analyst decided not to create a custom indicator for the file hash.")

    return

"""
Format a description to provide when creating an Indicator with a policy of "detect".
"""
def format_detect_description(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('format_detect_description() called')
    
    template = """This indicator was created by Phantom in the playbook crowdstrike_malware_triage to detect and block process executions based on the file hash first seen in {0} and processed in Phantom as {1}"""

    # parameter list for template variable replacement
    parameters = [
        "filtered-data:filter_main_artifact:condition_1:artifact:*.cef.falconHostLink",
        "container:url",
    ]

    phantom.format(container=container, template=template, parameters=parameters, name="format_detect_description")

    create_detect_indicator(container=container)

    return

"""
Create an Indicator to detect and block this file hash.
"""
def create_detect_indicator(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('create_detect_indicator() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'create_detect_indicator' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.fileHashSha256', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'create_detect_indicator' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        if filtered_artifacts_item_1[0]:
            parameters.append({
                'ioc': filtered_artifacts_item_1[0],
                'policy': "detect",
                'source': "",
                'expiration': "",
                'description': "",
                'share_level': "red",
                # context (artifact id) is added to associate results with the artifact
                'context': {'artifact_id': filtered_artifacts_item_1[1]},
            })

    phantom.act(action="upload indicator", parameters=parameters, assets=['crowdstrike_oauth'], name="create_detect_indicator")

    return

"""
Do not quarantine the endpoint because the analyst responded No in the prompt.
"""
def comment_no_quarantine_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('comment_no_quarantine_1() called')

    phantom.comment(container=container, comment="The analyst decided not to quarantine the endpoint.")

    return

"""
Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.
"""
def quarantine_device_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('quarantine_device_1() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'quarantine_device_1' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'quarantine_device_1' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        parameters.append({
            'hostname': "",
            'device_id': 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="quarantine device", parameters=parameters, assets=['crowdstrike_oauth'], name="quarantine_device_1")

    return

"""
Ask the analyst if the endpoint should be quarantined.
"""
def crowdstrike_known_file_quarantine(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('crowdstrike_known_file_quarantine() called')
    
    # set user and message variables for phantom.prompt call
    user = "admin"
    message = """{0}

---

Should Phantom quarantine the device?"""

    # parameter list for template variable replacement
    parameters = [
        "format_repeat_note:formatted_data",
    ]

    #responses:
    response_types = [
        {
            "prompt": "",
            "options": {
                "type": "list",
                "choices": [
                    "Yes",
                    "No",
                ]
            },
        },
    ]

    phantom.prompt2(container=container, user=user, message=message, respond_in_mins=30, name="crowdstrike_known_file_quarantine", parameters=parameters, response_types=response_types, callback=quarantine_decision_2)

    return

"""
Check if the analyst responded Yes or No to the quarantine.
"""
def quarantine_decision_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('quarantine_decision_2() called')

    # check for 'if' condition 1
    matched = phantom.decision(
        container=container,
        action_results=results,
        conditions=[
            ["crowdstrike_known_file_quarantine:action_result.summary.responses.0", "==", "Yes"],
        ])

    # call connected blocks if condition 1 matched
    if matched:
        quarantine_device_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)
        return

    # call connected blocks for 'else' condition 2
    comment_no_quarantine_2(action=action, success=success, container=container, results=results, handle=handle, custom_function=custom_function)

    return

"""
Block the endpoint from everything but the configured allowlist of network addresses while the investigation is ongoing.
"""
def quarantine_device_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('quarantine_device_2() called')
        
    #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED')))
    
    # collect data for 'quarantine_device_2' call
    filtered_artifacts_data_1 = phantom.collect2(container=container, datapath=['filtered-data:filter_main_artifact:condition_1:artifact:*.cef.sensorId', 'filtered-data:filter_main_artifact:condition_1:artifact:*.id'])

    parameters = []
    
    # build parameters list for 'quarantine_device_2' call
    for filtered_artifacts_item_1 in filtered_artifacts_data_1:
        parameters.append({
            'hostname': "",
            'device_id': 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="quarantine device", parameters=parameters, assets=['crowdstrike_oauth'], name="quarantine_device_2")

    return

"""
Do not quarantine the endpoint because the analyst responded No in the prompt.
"""
def comment_no_quarantine_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs):
    phantom.debug('comment_no_quarantine_2() called')

    phantom.comment(container=container, comment="The analyst decided not to quarantine the endpoint.")

    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