Can You See Me Now? Ensure SOAR Playbook Visibility Into Artifact Data Regardless of Scope 

By Marvin Martinez, Team Lead of Security Automation Operations

Splunk SOAR, formerly known as Phantom, is essentially a canvas on which to build out your automation solutions. One particular aspect of how Splunk SOAR works behind the scenes can sometimes be beneficial, or somewhat of a hindrance, depending your use case. As you know, Splunk SOAR has this notion of “scope” when determining whether an artifact is “visible” to a playbook while it is running. This is not normally an issue if you’re manually executing a playbook and are able to select the scope before executing the playbook, as displayed below.

There are use cases, however, where you may want to be able to repeatedly execute playbooks and ensure that some, or all, artifacts are always visible to the playbook. For example, you may have a workbook attached to the container with playbook references and analysts/users may need to run the same playbook more than once. In cases like this, the only usual option is to ensure you manually set the scope on each playbook block in your playbook to “All Artifacts” as you develop it. Depending on the length of your playbook, this may be unnecessarily tedious, particularly if you’re doing it repeatedly for multiple playbooks!

A SOAR Hack

In use cases like this, there is a clever SOAR hack you could employ that will ensure your playbook always has the artifact information available. You can leverage the REST API to retrieve the artifact data using a custom function and then it will be available as output variables in a utility block within your playbook.

Creating a custom function ensures that you can re-use this piece of code any time you need it and for any artifact that’s in your container. A basic introduction to this custom function is below. In your SOAR environment, go to “Custom Functions” and click to create a new one.

Inputs

  • artifact_name (item) – This will be the name of artifact in your container that you want to retrieve the values for.
  • container_id (item) – The container id of the container where the desired artifact is. This can easily be referenced by selecting “event” -> “id” in the parameter select screen when populating the inputs for the custom function call.

Outputs

  • artifact_cef_values (item) – This will be a dictionary field that will contain all of the cef values in the artifact.

As for the code, insert the following code snippet after the “Write your custom code here…” line in your custom function.

    #Create dictionary for results 

    artifact_cef_values_dict = {} 

    found_values = False 
    #Generate REST API call with filters to get artifact data 

    artifact_url = phantom.build_phantom_rest_url('artifact') 

    artifact_url = f'{artifact_url}/?_filter_container_id=

{container_id}&_filter_name=\'{artifact_name}\'' 

    response = phantom.requests.get(artifact_url, verify=False) 

    content = json.loads(response.text) 
    #Iterate through results and convert fields/values to dictionary keys 

    if content['count'] > 0: 

        found_values = True 

        artifact_cef_values = content['data'][0]['cef'] 

        keys = list(artifact_cef_values.keys()) 

        values = list(artifact_cef_values.values()) 

        counter = 0 

        for key in keys: 

            value = values[counter] 

            artifact_cef_values_dict[key] = value 

            counter = counter + 1 
    if not found_values: 

        comment = "NOTE: no field values found!" 

        phantom.comment(comment=comment) 

    else: 

        pass 
    #Assign output variable with internal results dictionary 

    outputs['artifact_cef_values'] = artifact_cef_values_dict 

Results

Once implemented, this custom function can now be called from your playbook (preferably at the top of it as one of your first blocks) and you can then reference the outputs of that block for any fields from your desired artifact, no matter what scope it’s running in. Below is a sample playbook that shows how this custom function could be utilized:

The container this playbook will run on has one artifact named “test_artifact” with a few fields, one of which is a “destinationAddress”.

In the playbook above, the custom function is called as the first block and retrieves all the values for “test_artifact” in the current container. The configuration for the custom function is as shown below:

In the format output block immediately after, select the “artifact_cef_values” output from the custom function block and then just add the desired field at the end in object notation (i.e. add “destinationAddress” like get_artifact_cef_values_26:custom_function_result.data.artifact_cef_values.destinationAddress). In this case, we are just preparing a quick comment to show how the field retrieval works.

Now, just use the output of the format block in the comment block after that to output a comment to the container showing the data. The output of the comment block will display as shown below.

As you can see, once implemented, it’s that easy to reference any values from your artifact at any point in your playbook with no need to worry about scopes or references at any point. If you have multiple artifacts, you could easily string together various of these blocks and just name them accordingly for use within your playbook.