def Make_List(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None):
    phantom.debug('Make_List() called')
    results_data_1 = phantom.collect2(container=container, datapath=['run_query_1:action_result.data'], action_results=results)
    results_item_1_0 = [item[0] for item in results_data_1]

    ################################################################################
    ## Custom Code Start
    ################################################################################

    # Write your custom code here...
    list_name = "temp_peer_list_%s" % container['id']
    
    # Store list name in container data
    data = phantom.get_container(container['id'])['data']
    data.update({"peer_list":list_name})
    phantom.update(container, {'data':data} )
    
    phantom.remove_list(list_name)
    
    #phantom.debug(results_item_1_0)
    for row in results_item_1_0[0]:
        phantom.add_list(list_name, [row["peer"],row["count"], row["priority"]])

    ################################################################################
    ## Custom Code End
    ################################################################################
    add_comment_1(container=container)

    return
def write_container_data(action=None,
                         success=None,
                         container=None,
                         results=None,
                         handle=None,
                         filtered_artifacts=None,
                         filtered_results=None):
    phantom.debug('write_container_data() called')
    input_parameter_0 = "my_data_2"
    input_parameter_1 = "More Stuff"

    ################################################################################
    ## Custom Code Start
    ################################################################################

    # Write your custom code here...
    #input_parameter_0 is the key
    #input_parameter_1 is the value
    data = phantom.get_container(container['id'])['data']
    data.update({input_parameter_0: input_parameter_1})
    phantom.update(container, {'data': data})

    ################################################################################
    ## Custom Code End
    ################################################################################
    get_container_data(container=container)

    return
def pin_1(action=None,
          success=None,
          container=None,
          results=None,
          handle=None,
          filtered_artifacts=None,
          filtered_results=None):
    import random
    phantom.debug('pin_1() called')

    # collect data for 'pin_to_hud_6' call
    dest_ip_artifacts = filter(
        lambda x: x[0],
        phantom.collect2(container=container,
                         datapath=['artifact:*.cef.destinationAddress']))
    sorc_ip_artifacts = filter(
        lambda x: x[0],
        phantom.collect2(container=container,
                         datapath=['artifact:*.cef.sourceAddress']))

    styles = set(["white", "red", "purple"])

    pin_name = pin_name_mangle("pin_1", container)
    pin_id = phantom.get_data(pin_name)

    if not pin_id:
        ret_val, message, pin_id = phantom.pin(
            container=container,
            message="Affected IPs",
            data=str(len(dest_ip_artifacts) + len(sorc_ip_artifacts)),
            pin_type="card_medium",
            pin_style="white")
        phantom.debug("new pin_1")
    else:
        style = random.sample(styles, 1)[0]
        phantom.debug(style)
        ret_val, message = phantom.update_pin(
            pin_id,
            message="Affected IPs",
            data=str(len(dest_ip_artifacts) + len(sorc_ip_artifacts)),
            pin_style=style)

    if ret_val:
        phantom.save_data(pin_id, pin_name)

    # set container properties for:
    update_data = {}

    phantom.update(container, update_data)

    return
def L5_CF_Get_Query_Results_py3_SOAR53(peer=None,
                                       priority=None,
                                       count=None,
                                       container=None,
                                       **kwargs):
    """
    created with SOAR 5.3
    
    Args:
        peer
        priority
        count
        container (CEF type: phantom container id)
    
    Returns a JSON-serializable object that implements the configured data paths:
        results_list_name
    """
    ############################ Custom Code Goes Below This Line #################################
    import json
    import phantom.rules as phantom

    outputs = {}

    # Write your custom code here...
    phantom.debug(container)
    phantom.debug(type(container))
    list_name = "temp_peer_list_%s" % container

    # You need the container object in order to update it.
    update_container = phantom.get_container(container)

    # Get the data node of the container
    data = phantom.get_container(container)['data']
    data.update({"peer_list": list_name})
    phantom.update(update_container, {'data': data})
    phantom.remove_list(list_name)

    for i in range(0, len(peer)):
        phantom.add_list(list_name, [peer[i], priority[i], count[i]])

    # The actual list is in slot 3 of the tuple returned by phantom.get_list()
    results_list = phantom.get_list(list_name)[2]
    phantom.debug(results_list)
    outputs = {'results_list_name': list_name}

    # Return a JSON-serializable object
    assert json.dumps(
        outputs
    )  # Will raise an exception if the :outputs: object is not JSON-serializable
    return outputs
def pin_2(action=None,
          success=None,
          container=None,
          results=None,
          handle=None,
          filtered_artifacts=None,
          filtered_results=None):
    import random
    phantom.debug('pin_2() called')

    # collect data for 'pin_to_hud_6' call
    dest_username = filter(
        lambda x: x[0],
        phantom.collect2(container=container,
                         datapath=['artifact:*.cef.destinationUserName']))
    sorc_username = filter(
        lambda x: x[0],
        phantom.collect2(container=container,
                         datapath=['artifact:*.cef.sourceUserName']))

    styles = set(["white", "red", "purple"])
    pin_name = pin_name_mangle("pin_2", container)
    pin_id = phantom.get_data(pin_name)

    if not pin_id:
        ret_val, message, pin_id = phantom.pin(
            container=container,
            message="Affected Users",
            data=str(len(dest_username) + len(sorc_username)),
            pin_type="card_medium",
            pin_style="purple")
        phantom.debug("new pin_2")
    else:
        # Delete and remake this one, for the sake of demonstration
        ret_val, message = phantom.delete_pin(pin_id)
        ret_val, message, pin_id = phantom.pin(
            container=container,
            message="Affected Users",
            data=str(len(dest_username) + len(sorc_username)),
            pin_type="card_medium",
            pin_style=random.sample(styles, 1)[0])

    if ret_val:
        phantom.save_data(pin_id, pin_name)
    # set container properties for:
    update_data = {}

    phantom.update(container, update_data)

    return
def pin_3(action=None,
          success=None,
          container=None,
          results=None,
          handle=None,
          filtered_artifacts=None,
          filtered_results=None):
    import random
    phantom.debug('pin_3() called')

    # collect data for 'pin_to_hud_6' call
    dest_domain = filter(
        lambda x: x[0],
        phantom.collect2(container=container,
                         datapath=['artifact:*.cef.destinationDnsDomain']))

    pin_name = pin_name_mangle("pin_3", container)

    try:
        most_rcnt_domain = dest_domain[0][0]
    except:
        pass
    else:
        pin_id = phantom.get_data(pin_name)
        if not pin_id:
            ret_val, message, pin_id = phantom.pin(
                container=container,
                message="Most Recent Domain",
                data=most_rcnt_domain,
                pin_type="card_medium",
                pin_style="red")
            phantom.debug("new pin_3")
        else:
            ret_val, message = phantom.update_pin(pin_id,
                                                  message="Most Recent Domain",
                                                  data=most_rcnt_domain,
                                                  pin_type="card_medium",
                                                  pin_style="red")
        if ret_val:
            phantom.save_data(pin_id, pin_name)

    # set container properties for:
    update_data = {}

    phantom.update(container, update_data)
    return
예제 #7
0
def resolve_container(action=None,
                      success=None,
                      container=None,
                      results=None,
                      handle=None,
                      filtered_artifacts=None,
                      filtered_results=None):
    phantom.debug('resolve_container() called')

    # Closing out the container
    phantom.set_severity(container, "low")
    my_add_tags(tags=["automation"])
    # Updating required fields
    resolution_data = {"Resolution": "Trivial True Positive"}
    custom_fields = {"custom_fields": resolution_data}
    phantom.update(container, custom_fields)
    phantom.set_status(container, "closed")
    return
def on_start(container):
    phantom.debug('on_start() called')

    # get the _raw data from splunk
    data = phantom.collect2(container=container,
                            datapath=['artifact:*.cef._raw'])
    data = data[0][0]

    phantom.debug(data)
    split_data = data.split(',')
    data_dict = {}
    custom_dict = {}
    # get a name for the container to update
    container_name = split_data[0]
    del (split_data[0])
    counter = 1

    # breaks out the data into items with k,v or additional items with multiple :
    for i in split_data:
        if len(i.split(":")) == 2:
            data_key = i.split(":")[0]
            data_value = i.split(":")[1]
            data_dict[data_key.replace(" ", "")] = data_value
        else:
            custom_dict["cs" + str(counter)] = i
            counter = counter + 1

    phantom.debug(container_name)
    phantom.debug(data_dict)
    phantom.debug(custom_dict)

    raw = {}
    # add our artifacts that were easily parsed
    phantom.add_artifact(container=container,
                         raw_data=raw,
                         cef_data=data_dict,
                         label='event',
                         name='splunk data',
                         severity='low',
                         identifier=None,
                         artifact_type='network')

    # everything else
    phantom.add_artifact(container=container,
                         raw_data=raw,
                         cef_data=custom_dict,
                         label='event',
                         name='splunk data',
                         severity='low',
                         identifier=None,
                         artifact_type='network')

    # update the name of the container
    update_data = {"name": container_name}
    success, message = phantom.update(container, update_data)
    return
예제 #9
0
def custom_function_1(action=None,
                      success=None,
                      container=None,
                      results=None,
                      handle=None,
                      filtered_artifacts=None,
                      filtered_results=None,
                      custom_function=None,
                      **kwargs):
    phantom.debug('custom_function_1() called')

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

    ################################################################################
    ## Custom Code Start
    ################################################################################

    phantom.debug(phantom.update(container, json.loads(formatted_data_1)))

    ################################################################################
    ## Custom Code End
    ################################################################################

    return
예제 #10
0
def container_merge(target_container=None,
                    container_list=None,
                    workbook=None,
                    close_containers=None,
                    **kwargs):
    """
    An alternative to the add-to-case API call. This function will copy all artifacts, automation, notes and comments over from every container within the container_list into the target_container. The target_container will be upgraded to a case.
    
    The notes will be copied over with references to the child containers from where they came. A note will be left in the child containers with a link to the target container. The child containers will be marked as evidence within the target container. 
    
    Any notes left as a consequence of the merge process will be skipped in subsequent merges.
    
    Args:
        target_container (CEF type: phantom container id): The target container to copy the information over. Supports container dictionary or container id.
        container_list: A list of container IDs to copy into the target container.
        workbook: Name or ID of the workbook to add if the container does not have a workbook yet. If no workbook is provided, the system default workbook will be added.
        close_containers: True or False to close the child containers in the container_list after merge. Defaults to False.
    
    Returns a JSON-serializable object that implements the configured data paths:
        
    """
    ############################ Custom Code Goes Below This Line #################################
    import json
    import phantom.rules as phantom

    outputs = {}

    # Check if valid target_container input was provided
    if isinstance(target_container, int):
        container = phantom.get_container(target_container)
    elif isinstance(target_container, dict):
        container = target_container
    else:
        raise TypeError(
            f"target_container '{target_container}' is neither a int or a dictionary"
        )

    container_url = phantom.build_phantom_rest_url('container',
                                                   container['id'])

    # Check if container_list input is a list of IDs
    if isinstance(container_list, list) and (all(
            isinstance(x, int)
            for x in container_list) or all(x.isnumeric()
                                            for x in container_list)):
        pass
    else:
        raise TypeError(
            f"container_list '{container_list}' is not a list of integers")

    ## Prep parent container as case with workbook ##
    workbook_name = phantom.requests.get(
        container_url, verify=False).json().get('workflow_name')
    # If workbook already exists, proceed to promote to case
    if workbook_name:
        phantom.debug(
            "workbook already exists. adding [Parent] to container name and promoting to case"
        )
        update_data = {'container_type': 'case'}
        if not '[Parent]' in container['name']:
            update_data['name'] = "[Parent] {}".format(container['name'])
            phantom.update(container, update_data)
        else:
            phantom.update(container, update_data)
    # If no workbook exists, add one
    else:
        phantom.debug(
            "no workbook in container. adding one by name or using the default"
        )
        # If workbook ID was provided, add it
        if isinstance(workbook, int):
            workbook_id = workbook
            phantom.add_workbook(container=container['id'],
                                 workbook_id=workbook_id)
        # elif workbook name was provided, attempt to translate it to an id
        elif isinstance(workbook, str):
            workbook_url = phantom.build_phantom_rest_url(
                'workbook_template') + '?_filter_name="{}"'.format(workbook)
            response = phantom.requests.get(workbook_url, verify=False).json()
            if response['count'] > 1:
                raise RuntimeError(
                    'Unable to add workbook - more than one ID matches workbook name'
                )
            elif response['data'][0]['id']:
                workbook_id = response['data'][0]['id']
                phantom.add_workbook(container=container['id'],
                                     workbook_id=workbook_id)
        else:
            # Adding default workbook
            phantom.promote(container=container['id'])
        # Check again to see if a workbook now exists
        workbook_name = phantom.requests.get(
            container_url, verify=False).json().get('workflow_name')
        # If workbook is now present, promote to case
        if workbook_name:
            update_data = {'container_type': 'case'}
            if not '[Parent]' in container['name']:
                update_data['name'] = "[Parent] {}".format(container['name'])
                phantom.update(container, update_data)
            else:
                phantom.update(container, update_data)
        else:
            raise RuntimeError(
                f"Error occurred during workbook add for workbook '{workbook_name}'"
            )

    ## Check if current phase is set. If not, set the current phase to the first available phase to avoid artifact merge error ##
    if not container.get('current_phase_id'):
        phantom.debug(
            "no current phase, so setting first available phase to current")
        workbook_phase_url = phantom.build_phantom_rest_url(
            'workbook_phase') + "?_filter_container={}".format(container['id'])
        request_json = phantom.requests.get(workbook_phase_url,
                                            verify=False).json()
        update_data = {'current_phase_id': request_json['data'][0]['id']}
        phantom.update(container, update_data)

    child_container_list = []
    child_container_name_list = []
    # Iterate through child containers
    for child_container_id in container_list:

        ### Begin child container processing ###
        phantom.debug(
            "Processing Child Container ID: {}".format(child_container_id))

        child_container = phantom.get_container(child_container_id)
        child_container_list.append(child_container_id)
        child_container_name_list.append(child_container['name'])
        child_container_url = phantom.build_phantom_rest_url(
            'container', child_container_id)

        ## Update container name with parent relationship
        if not "[Parent:" in child_container['name']:
            update_data = {
                'name':
                "[Parent: {0}] {1}".format(container['id'],
                                           child_container['name'])
            }
            phantom.update(child_container, update_data)

        ## Gather and add notes ##
        for note in phantom.get_notes(container=child_container_id):
            # Avoid copying any notes related to the merge process.
            if note['success'] and not note['data']['title'] in (
                    '[Auto-Generated] Related Containers',
                    '[Auto-Generated] Parent Container',
                    '[Auto-Generated] Child Containers'):
                phantom.add_note(container=container['id'],
                                 note_type='general',
                                 note_format=note['data']['note_format'],
                                 title="[From Event {0}] {1}".format(
                                     note['data']['container'],
                                     note['data']['title']),
                                 content=note['data']['content'])

        ## Copy information and add to case
        data = {
            'add_to_case': True,
            'container_id': child_container_id,
            'copy_artifacts': True,
            'copy_automation': True,
            'copy_files': True,
            'copy_comments': True
        }
        phantom.requests.post(container_url, json=data, verify=False)

        ## Leave a note with a link to the parent container
        phantom.debug(
            "Adding parent relationship note to child container '{}'".format(
                child_container_id))
        data_row = "{0} | [{1}]({2}/mission/{0}) |".format(
            container['id'], container['name'], phantom.get_base_url())
        phantom.add_note(
            container=child_container_id,
            note_type="general",
            note_format="markdown",
            title="[Auto-Generated] Parent Container",
            content="| Container_ID | Container_Name |\n| --- | --- |\n| {}".
            format(data_row))

        ## Mark child container as evidence in target_container
        data = {
            "container_id": container['id'],
            "object_id": child_container_id,
            "content_type": "container"
        }
        evidence_url = phantom.build_phantom_rest_url('evidence')
        response = phantom.requests.post(evidence_url, json=data,
                                         verify=False).json()

        ## Close child container
        if isinstance(close_containers,
                      str) and close_containers.lower() == 'true':
            phantom.set_status(container=child_container_id, status="closed")

        ### End child container processing ###

    ## Format and add note for link back to child_containers in parent_container
    note_title = "[Auto-Generated] Child Containers"
    note_format = "markdown"
    format_list = []
    # Build new note
    for child_container_id, child_container_name in zip(
            child_container_list, child_container_name_list):
        format_list.append("| {0} | [{1}]({2}/mission/{0}) |\n".format(
            child_container_id, child_container_name, phantom.get_base_url()))
    # Fetch any previous merge note
    params = {
        '_filter_container': '"{}"'.format(container['id']),
        '_filter_title': '"[Auto-Generated] Child Containers"'
    }
    note_url = phantom.build_phantom_rest_url('note')
    response_data = phantom.requests.get(note_url, verify=False).json()
    # If an old note was found, proceed to overwrite it
    if response_data['count'] > 0:
        note_item = response_data['data'][0]
        note_content = note_item['content']
        # Append new information to existing note
        for c_note in format_list:
            note_content += c_note
        data = {
            "note_type": "general",
            "title": note_title,
            "content": note_content,
            "note_format": note_format
        }
        # Overwrite note
        response_data = phantom.requests.post(note_url +
                                              "/{}".format(note_item['id']),
                                              json=data,
                                              verify=False).json()
    # If no old note was found, add new with header
    else:
        template = "| Container ID | Container Name |\n| --- | --- |\n"
        for c_note in format_list:
            template += c_note
        success, message, process_container_merge__note_id = phantom.add_note(
            container=container,
            note_type="general",
            title=note_title,
            content=template,
            note_format=note_format)

    # Return a JSON-serializable object
    assert json.dumps(
        outputs
    )  # Will raise an exception if the :outputs: object is not JSON-serializable
    return outputs
예제 #11
0
def container_update(container_input=None,
                     name=None,
                     description=None,
                     label=None,
                     owner=None,
                     sensitivity=None,
                     severity=None,
                     status=None,
                     tags=None,
                     input_json=None,
                     **kwargs):
    """
    Allows updating various attributes of a container in a single custom function. Any attributes of a container not listed can be updated via the input_json parameter. 
    
    Args:
        container_input (CEF type: phantom container id): Supports a container id or container dictionary
        name: Optional parameter to change container name
        description: Optional parameter to change the container description
        label (CEF type: phantom container label): Optional parameter to change the container label
        owner: Optional parameter to change the container owner. Accepts a username or role name or keyword "current" to set the currently running playbook user as the owner.
        sensitivity: Optional parameter to change the container sensitivity. 
        severity: Optional parameter to change the container severity.
        status: Optional parameter to change the container status.
        tags: Optional parameter to change the container tags. Must be in the format of a comma separated list.
        input_json: Optional parameter to modify any extra attributes of a container. Input_json will be merged with other inputs. In the event of a conflict, input_json will take precedence.
    
    Returns a JSON-serializable object that implements the configured data paths:
        
    """
    ############################ Custom Code Goes Below This Line #################################
    import json
    import phantom.rules as phantom

    outputs = {}
    update_dict = {}

    if isinstance(container_input, int):
        container = phantom.get_container(container_input)
    elif isinstance(container_input, dict):
        container = container_input
    else:
        raise TypeError("container_input is neither a int or a dictionary")

    if name:
        update_dict['name'] = name
    if description:
        update_dict['description'] = description
    if label:
        update_dict['label'] = label
    if owner:
        # If keyword 'current' entered then translate effective_user id to a username
        if owner.lower() == 'current':
            update_dict['owner_id'] = phantom.get_effective_user()
        else:
            # Attempt to translate name to owner_id
            url = phantom.build_phantom_rest_url(
                'ph_user') + f'?_filter_username="******"'
            data = phantom.requests.get(url, verify=False).json().get('data')
            if data and len(data) == 1:
                update_dict['owner_id'] = data[0]['id']
            elif data and len(data) > 1:
                phantom.error(f'Multiple matches for owner "{owner}"')
            else:
                # Attempt to translate name to role_id
                url = phantom.build_phantom_rest_url(
                    'role') + f'?_filter_name="{owner}"'
                data = phantom.requests.get(url,
                                            verify=False).json().get('data')
                if data and len(data) == 1:
                    update_dict['role_id'] = data[0]['id']
                elif data and len(data) > 1:
                    phantom.error(f'Multiple matches for role "{owner}"')
                else:
                    phantom.error(f'"{owner}" is not a valid username or role')
    if sensitivity:
        update_dict['sensitivity'] = sensitivity
    if severity:
        update_dict['severity'] = severity
    if status:
        update_dict['status'] = status
    if tags:
        tags = tags.replace(" ", "").split(",")
        update_dict['tags'] = tags
    if input_json:
        json_dict = json.loads(input_json)
        # Merge dictionaries together. The second argument, "**json_dict" will take precedence and overwrite any duplicate parameters.
        update_dict = {**update_dict, **json_dict}

    if update_dict:
        phantom.debug(
            'Updating container {0} with the following information: "{1}"'.
            format(container['id'], update_dict))
        phantom.update(container, update_dict)
    else:
        phantom.debug(
            "Valid container entered but no valid container changes provided.")

    # Return a JSON-serializable object
    assert json.dumps(
        outputs
    )  # Will raise an exception if the :outputs: object is not JSON-serializable
    return outputs