Skip to content

Latest commit

 

History

History

fn_extrahop

ExtraHop for IBM SOAR

Table of Contents


Release Notes

Version Date Notes
1.0.0 06/2022 Initial Release

Overview

IBM Security SOAR app for ExtraHop

screenshot: main

ExtraHop is a cybersecurity cloud-native solution that provides AI-based network intelligence to help enterprises detect and respond to advanced threats.

The ExtraHop App for IBM SOAR escalates ExtraHop detections into IBM Security SOAR as an incident/case and facilitates manual enrichment and remediation actions against an ExtraHop RevealX 360 environment in the IBM SOAR Platform.

Key Features

The ExtraHop App provides the following functionality:

  • A poller which gathers current detections from ExtraHop and escalates to the SOAR platform as incidents.
  • Functions to get, search and update detections.
  • Functions to get and add detection notes.
  • Functions to get and search devices.
  • Functions to get, create and assign tags.
  • Functions get and set the watchlist.
  • A function to get activitymaps.

Requirements

This app supports the IBM Security QRadar SOAR Platform and the IBM Security QRadar SOAR for IBM Cloud Pak for Security.

SOAR platform

The SOAR platform supports two app deployment mechanisms, App Host and integration server.

If deploying to a SOAR platform with an App Host, the requirements are:

  • SOAR platform >= 41.2.41.
  • The app is in a container-based format (available from the AppExchange as a zip file).

If deploying to a SOAR platform with an integration server, the requirements are:

  • SOAR platform >= 41.2.41.
  • The app is in the older integration format (available from the AppExchange as a zip file which contains a tar.gz file).
  • Integration server is running resilient-circuits>=42.0.0.
  • If using an API key account, make sure the account provides the following minimum permissions:
    Name Permissions
    Org Data Read
    Function Read
    incident Create
    all_incidents Read
    all_incidents_fields Edit
    layouts Read, Edit

The following SOAR platform guides provide additional information:

  • App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
  • Integration Server Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
  • System Administrator Guide: provides the procedure to install, configure and deploy apps.

The above guides are available on the IBM Documentation website at ibm.biz/soar-docs. On this web page, select your SOAR platform version. On the follow-on page, you can find the App Host Deployment Guide or Integration Server Guide by expanding Apps in the Table of Contents pane. The System Administrator Guide is available by expanding System Administrator.

Cloud Pak for Security

If you are deploying to IBM Cloud Pak for Security, the requirements are:

  • IBM Cloud Pak for Security >= 1.4.
  • Cloud Pak is configured with an App Host.
  • The app is in a container-based format (available from the AppExchange as a zip file).

The following Cloud Pak guides provide additional information:

  • App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings. From the Table of Contents, select Case Management and Orchestration & Automation > Orchestration and Automation Apps.
  • System Administrator Guide: provides information to install, configure, and deploy apps. From the IBM Cloud Pak for Security IBM Documentation table of contents, select Case Management and Orchestration & Automation > System administrator.

These guides are available on the IBM Documentation website at ibm.biz/cp4s-docs. From this web page, select your IBM Cloud Pak for Security version. From the version-specific IBM Documentation page, select Case Management and Orchestration & Automation.

Proxy Server

The app does support a proxy server via the https_proxy and http_proxy app.config settings.

Python Environment

Both Python 3.6 and Python 3.9 are supported. Additional package dependencies may exist for each of these packages:

  • jinja2
  • resilient-circuits>=42.0.0
  • resilient-lib
  • retry2 ~= 0.9

Endpoint Developed With

This app has been implemented using:

Product Name Product Version API URL API Version
ExtraHop RevealX 360 8.8.31785 https://<extrahop_cloud_api_url> or https://<sensor_hostname_or_ip> v1

Prerequisites

  • An ExtraHop discover appliance/sensor must be deployed in the users environment.
  • The app user must have a user account on the ExtraHop standalone discover appliance or Cloud Services instance with REST API access enabled.
  • If the user wants to use the Function - Extrahop Reveal(x) search packets function a trace appliance must be deployed in the users environment.
  • ExtraHop detection tracking enables a user to connect ExtraHop detections back to SOAR incidents.

For deployments see: ExtraHop Deployment

For ticket tracking See: Ticket Tracking

NOTE: If the user environment is in AWS, a Reveal(x) Ultra sensor can be deployed which is a combination of a discover appliance and a trace appliance.

NOTE: If detection tracking is enabled on ExtraHop the app functions to get and add detection notes will not complete.

Configuration

ExtraHop standalone sensor
  • The ExtraHop system must be configured to allow API key generation for the user.
  • A valid API key must be generated for the ExtraHop app user.
ExtraHop Cloud Services
  • REST API access must be enabled for the user.
  • Create REST API credentials (key ID and key secret token) for the ExtraHop app user.

See: Cloud Service api setup

Permission

  • REST API access must be enabled for the account that IBM SOAR is communicating with as specified in the App configration file.

Installation

Install

  • To install or uninstall an App or Integration on the SOAR platform, see the documentation at ibm.biz/soar-docs.
  • To install or uninstall an App on IBM Cloud Pak for Security, see the documentation at ibm.biz/cp4s-docs and follow the instructions above to navigate to Orchestration and Automation.

App Configuration

The following table provides the settings you need to configure the app. These settings are made in the app.config file. See the documentation discussed in the Requirements section for the procedure.

Config Required Example Description
extrahop_rx_host_url Yes https://<extrahop-hostname-or-IP-api-address> Cloud api service url or sensor url.
extrahop_rx_api_version Yes v1 Version of (API) access to ExtraHop.
extrahop_rx_cloud_console_url *Yes https://<extrahop-hostname-or-IP-console-address> Cloud service console url for cloud-based ExtraHop instance.
extrahop_rx_key_id *Yes 1ab2ef34gh56ijklm012n3abc4 Key ID setting if ExtraHop cloud instance used by the integration.
extrahop_rx_key_secret *Yes ab2ef34gh56ijklm012n3abc41ab2ef34gh56ijklm012n3abc4 Key secret setting if ExtraHop cloud instance used by the integration.
extrahop_rx_api_key *Yes ab2ef34GH56ijkLM012n3abc41ab2ef34GH56ijklm4 API key setting if standalone sensor used by the integration.
polling_interval Yes 60 Interval to wait between polls of ExtraHop for detections.
polling_filters No polling_filters="risk_score_min": 80, "category": ["sec.exploit"], "types": ["interactive_traffic_ssh", "interactive_traffic_shell"], "status": [".none", "new", "in_progress", "acknowledged"], "resolution": [".none" ] Filter detection results returned to SOAR using key/value pairs.
extrahop_cafile No <path to cert file> or false TLS certificate setting. Can be a path to a CA bundle or 'false'
https_proxy No https://proxy:443 or proxy:443 Optional setting for an https proxy if required.
NOTE: The integration can use either the ExtraHop Cloud Service or an ExtraHop standalone sensor.

NOTE: If connecting to an ExtraHop cloud instance, the setting extrahop_rx_api_key should be set to a blank value or alteratively commented out.

NOTE: If connecting to a standalone sensor, the settings extrahop_rx_key_id and extrahop_rx_key_secret should be set to a blank value or alternatively commented out.

Custom Layout

When the poller starts running, a new incident tab is created as shown below. If the poller is not configured to run, the custom layout can be configured manually.

  • Import the Data Tables and Custom Fields like the screenshot below:
  • Create a new ExtraHop incident tab in Layouts as follows:
  1. Navigate to the ‘Customization Settings’ and select the Layouts tab.
  2. Click on ‘Incident Tabs’.
  3. Add a new incident tab named ‘ExtraHop’.
  4. Drag and Drop the 'ExtraHop Update Notification' custom property onto the ExtraHop tab.
  5. Create new heading 'ExtraHop Properties' in the ExtraHop tab.
  6. Drag and Drop the ExtraHop the remaining custom properties under the new heading as shown below.
  7. Create new heading 'ExtraHop Details' in the ExtraHop tab.
  8. Drag and drop the ExtraHop data tables under the new heading as shown below.
  9. Click Save.

The following screenshot shows the ExtraHop properties and data tables added to the ExtraHop tab:

screenshot: custom_layouts


Poller - ExtraHop Escalate Detections

The ExtraHop integration poller starts querying ExtraHop for detections as soon as the app begins running.

The poller provides the following functionality.

  • For any new detections discovered, creates a matching incident in the SOAR platform.
  • The ExtraHop detections Ticket ID is assigned the SOAR case value.
  • The workflow Example: Extrahop Reveal(x) update incident is triggered by an automatic rule.
  • The automatic rule Enhances the incidents by adding artifacts and data tables with detection and device information from the matching ExtraHop detection.
  • Can be configured to filter the detections which are escalated to the SOAR incidents.
  • Closes SOAR incidents if the corresponding ExtraHop detections are closed.
  • Closes ExtraHop detections if the corresponding SOAR incidents are closed.
  • Updates a notification property in the ExtraHop custom tab if information for a SOAR incident if the corresponding ExtraHop detection is updated.
  • Adds a note to an ExtraHop detection when a matching SOAR incident is created.

The following screenshot shows examples of SOAR incidents created by the poller from ExtraHop detections:

screenshot: fn-extrahop-revealx-incidents

The following screenshot shows an example of a SOAR incident Details tab created by the poller:

screenshot: fn-extrahop-revealx-incident-details

The following screenshot shows an example of custom properties in the ExtraHop tab of a SOAR incident created by the poller:

screenshot: fn-extrahop-revealx-incident-properties

The following screenshot shows an example of an ExtraHop detection update notification in the ExtraHop tab of a SOAR incident created by the poller:

screenshot: fn-extrahop-revealx-incident-notification

The following screenshot shows examples of artifacts added to a SOAR incident created by the poller:

screenshot: fn-extrahop-revealx-incident-artifacts

The following screenshot shows an example of a note added to a SOAR incident created by the poller:

screenshot: fn-extrahop-revealx-incident-note

NOTE: See the data tables section for examples of data tables added by the poller.


Function - Extrahop Reveal(x) add detection note

Add a note to an ExtraHop detection. Parameters detection_id, note. (Optional) update_time.

screenshot: fn-extrahop-revealx-add-detection-note

The function provides the following functionality.

  • Adds a note to a detection in the ExtraHop environment. The original note is overwritten.

NOTE: The original note is overwritten.

NOTE: Add detection note will fail if Detection Tracking is enabled on ExtraHop.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) update detection.

  • A note is added to the ExtraHop detection when a matching SOAR incident is closed.

The workflow is initiated by the automatic data table rule Example: Extrahop Reveal(x) update detection when a SOAR incident is closed.

The following screenshot shows an example of a note added to an ExtraHop detection:

screenshot: fn-extrahop-revealx-add-detection-note-note

Inputs:

Name Type Required Example Tooltip
extrahop_detection_id number No - Extrahop detection ID
extrahop_note text No - ExtraHop note object
extrahop_update_time number No - (Optional) Return detections that were updated on or after the specified date, expressed in milliseconds since the epoch.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": "success"
  },
  "inputs": {
    "extrahop_detection_id": 3,
    "extrahop_note": "\nIBM SOAR 16/05/2022 15:13:37\n[SOAR Case - 4305](https://127.0.0.1:1443/#incidents/4305)\n[SOAR case - \u00274305\u0027](Closed with resolution summary: \u0027test closed.\u0027)",
    "extrahop_update_time": 0
  },
  "metrics": {
    "execution_time_ms": 892,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-05-16 15:29:16",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

##  ExtraHop - wf_extrahop_rx_update_detection pre processing script ##
import re
inputs.extrahop_detection_id = incident.properties.extrahop_detection_id

UPD_DET_DATETIME = workflow.properties.update_detection_note_result.metrics["timestamp"]
SUMMARY = re.sub('<[^<]+?>', '', incident.resolution_summary.content)


def get_current_note():
    # Get old note
    note = u''
    get_detection_note_content = workflow.properties.get_detection_note_result.content
    note_obj = get_detection_note_content["result"]
    if not note_obj:
        raise ValueError("Existing ExtraHop detection note not found.")
    note = note_obj["note"]
    return note


def make_summary_note():
    # Make a  note.
    summary_note = "IBM SOAR {}\n".format(UPD_DET_DATETIME)
    summary_note += "[SOAR case - '{}'](Closed with resolution summary: '{}')" \
    .format(incident.id, SUMMARY)
    return summary_note

# Processing
def main():
    detection_note = get_current_note()
    inputs.extrahop_note = '\n'.join([detection_note if detection_note else "", make_summary_note()])
    inputs.extrahop_update_time = 0
main()

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_update_detection post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_add_detection_note"
WF_NAME = "Example: Extrahop Reveal(x) update detection"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    detection_id = INPUTS["extrahop_detection_id"]
    if CONTENT:
        result = CONTENT.result
        if result == "success":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully added closure resolution note to " \
                        u"ExtraHop detection <b>{1}</b> for SOAR function <b>{2}</b> with parameters <b>{3}</b>."\
                .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        elif result.get("error"):
            note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to add closure resolution note to ExtraHop " \
                        u"detection <b>{1}</b> for SOAR function <b>{2}</b> with parameters <b>{3}</b>."\
                .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            note_text += u"<br>Error code: <b>{0}</b>, Error <b>{1}<b>.".format(result.get("error"), result.get("text"))
        elif result == "failed":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to add closure resolution note to ExtraHop " \
                        u"detection <b>{1}</b> for SOAR function <b>{2}</b> with parameters <b>{3}</b>."\
                .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        else:
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to add closure resolution note to ExtraHop " \
                        u"detection <b>{1}</b> with unexpected response for SOAR function <b>{2}</b> with parameters <b>{3}</b>."\
                .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to add closure resolution note to ExtraHop detection <b>{1}</b> for SOAR function <b>{2}</b> with parameters" \
                     u" <b>{3}</b> ."\
            .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) assign tag

Assign a tag to a list of devices ids forExtrahop Reveal(x). Parameters tag_id. devices_ids.

screenshot: fn-extrahop-revealx-assign-tag

The function provides the following functionality.

  • Assigns a tag to a list of device ids discovered in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) assign tag.

  • A note is added to the SOAR incident with the status of the action.

The workflow is initiated by the manual data table rule Example: Extrahop Reveal(x) assign tag for data table Example: Extrahop Reveal(x) assign tag.

screenshot: fn-extrahop-revealx-assign-tag-action

screenshot: fn-extrahop-revealx-assign-tag-action_2

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-assign-tag-note

Inputs:

Name Type Required Example Tooltip
extrahop_device_ids text No - Comma or newline seperated list of device ids.
extrahop_tag_id number No - The unique identifier for the tag.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": "success"
  },
  "inputs": {
    "extrahop_device_ids": "3",
    "extrahop_tag_id": 5
  },
  "metrics": {
    "execution_time_ms": 810,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:19:42",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

tag_name = rule.properties.extrahop_tag_name
get_tags_content = workflow.properties.get_tags_result.content
inputs.extrahop_device_ids = str(row.devs_id)
if tag_name is None:
    raise ValueError("The tag name is not set")
inputs.extrahop_tag_id = None
for tag in get_tags_content["result"]:
    if tag_name == tag["name"]:
        inputs.extrahop_tag_id = tag["id"]
        break
if not inputs.extrahop_tag_id:
    raise ValueError("Tag {} not found.".format(tag_name))

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_assign_tag post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_assign_tag"
WF_NAME = "Example: Extrahop Reveal(x) assign tag"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    tag_name = rule.properties.extrahop_tag_name
    tag = INPUTS.get("extrahop_tag_name")
    if CONTENT:
        result = CONTENT.result
        if result == "success":
            device_id = INPUTS.get("extrahop_device_ids")
            tag_id = INPUTS.get("extrahop_tag_id")
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully assigned tag <b>'{1}'</b> with id <b>{2}</b> to device id <b>{3}</b> for SOAR " \
                        u"function <b>{4}</b> with parameters <b>{5}</b>.".format(WF_NAME, tag_name, tag_id, device_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

        elif result == "failed":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to assign tag <b>{1}</b> with id <b>{2}</b> to device id <b>{3}</b> for " \
                        u"SOAR function <b>{4}</b> with parameters <b>{5}</b>.".format(WF_NAME, tag_name, tag_id, device_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        else:
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Assign tag <b>{1}</b> with id <b>{2}</b> to device id <b>{3}</b> failed with unexpected " \
                        u"response for SOAR function <b>{4}</b> with parameters <b>{5}</b>.".format(WF_NAME, tag_name, tag_id, device_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to assign tag <b>{1}</b> with id  <b>{2}</b> to device id <b>{3}</b> for SOAR function <b>{4}</b> with parameters <b>{5}</b>."\
            .format(WF_NAME, tag_name, tag_id, device_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) create tag

Create a new tag for Extrahop Reveal(x). Parameter tag_name.

screenshot: fn-extrahop-revealx-create-tag

The function provides the following functionality.

  • Creates a new tag in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) create tag.

  • A note is added to the SOAR incident with the status of the action.
  • The data table Extrahop Tags is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) create tag.

screenshot: fn-extrahop-revealx-create-tag-action

screenshot: fn-extrahop-revealx-create-tag-action_2

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-create-tag-note

Inputs:

Name Type Required Example Tooltip
extrahop_tag_name text No - The string value for an ExtraHop tag name.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": "success"
  },
  "inputs": {
    "extrahop_tag_name": "TEST_TAG_1"
  },
  "metrics": {
    "execution_time_ms": 798,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:22:37",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

inputs.extrahop_tag_name = rule.properties.extrahop_tag_name
if inputs.extrahop_tag_name is None:
    raise ValueError("The tag name is not set")

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_create_tag post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_create_tag"
WF_NAME = "Example: Extrahop Reveal(x) create tag"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]

# Processing
def main():
    note_text = u''
    tag = INPUTS.get("extrahop_tag_name")
    if CONTENT:
        result = CONTENT.result
        if result == "success":
            workflow.addProperty("tag_exists", {})
            tag = INPUTS.get("extrahop_tag_name")
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully created tag <b>'{1}'</b> for SOAR " \
                        u"function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, unicode(tag), FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))
        elif result == "failed":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to create tag <b>'{1}'</b> for " \
                        u"SOAR function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, unicode(tag), FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))
        elif result == "exists":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: A 422 (tag name exists) error was thrown while to create tag <b>'{1}'</b> for " \
                        u"SOAR function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, unicode(tag), FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))
        else:
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Create tag <b>'{1}'</b> failed with unexpected " \
                        u"response for SOAR function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, unicode(tag), FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to create a tag <b>'{1}'</b>for SOAR function <b>{2}</b> with parameters <b>{3}</b> ."\
            .format(WF_NAME, unicode(tag), FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) get activitymaps

Get activitymap information from Extrahop Reveal(x). Optional parameter activitymap_id.

screenshot: fn-extrahop-revealx-get-activitymaps

The function provides the following functionality.

  • Retrieves information on activitymaps in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) get activitymaps.

  • A note is added to the SOAR incident with the status of the action.
  • The data table ExtraHop Activitymaps is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) get activitymaps.

screenshot: fn-extrahop-revealx-get-activitymaps-action

The following screenshot shows an example of the data table updated by the function.

screenshot: fn-extrahop-revealx-get-activitymaps-datatable

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-get-activitymaps-note

Inputs:

Name Type Required Example Tooltip
extrahop_activitymap_id number No - The unique identifier for the activity map.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "description": "Test map 1",
        "id": 1,
        "mod_time": 1644514002331,
        "mode": "2dforce",
        "name": "Test_activity_map_1",
        "owner": "setup",
        "rights": [
          "delete",
          "edit",
          "share",
          "transfer",
          "view"
        ],
        "short_code": "wGCGL",
        "show_alert_status": false,
        "walks": [
          {
            "origins": [
              {
                "object_id": 6,
                "object_type": "device"
              }
            ],
            "steps": [
              {
                "relationships": [
                  {
                    "protocol": "any",
                    "role": "any"
                  }
                ]
              }
            ]
          }
        ],
        "weighting": "bytes"
      }
    ]
  },
  "inputs": {},
  "metrics": {
    "execution_time_ms": 1063,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 16:50:16",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

None

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_get_activitymaps post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_activitymaps"
WF_NAME = "Example: Extrahop Reveal(x) get activitymaps"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
DATA_TABLE = "extrahop_activitymaps"
DATA_TBL_FIELDS = ["ams_description", "ams_id", "mod_time", "mode", "ams_name", "owner", "rights", "short_code",
                   "show_alert_status", "walks", "weighting"]
# Processing
def main():
    note_text = u''
    if CONTENT:
        ams = CONTENT.result
        note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: There were <b>{1}</b> Activitymaps returned for SOAR " \
                    u"function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, len(ams), FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        if ams:
            for am in ams:
                newrow = incident.addRow(DATA_TABLE)
                newrow.query_execution_date = QUERY_EXECUTION_DATE
                for f1 in DATA_TBL_FIELDS:
                    f2 = f1
                    if f1.startswith("ams_"):
                        f2 = f1.split('_', 1)[1]
                    if am[f2] is None:
                        newrow[f1] = am[f2]
                    if isinstance(am[f2], list):
                        if f1 in ["walks"]:
                            obj_cnt = 0
                            tbl = u''
                            for w in am[f2]:
                                for kw, vw in w.items():
                                    if kw == "origins":
                                        tbl += u"<div><b>origins:</b></div>"
                                        for o in vw:
                                            for k, v in o.items():
                                                tbl += u"<div><b>&emsp;{0}:</b>{1}</div>".format(k, v)
                                        tbl += u"<br>"
                                    elif kw == "steps":
                                        tbl += u"<div><b>steps:</b></div>"
                                        for s in vw:
                                            relationships = s.get("relationships")
                                            if relationships:
                                                tbl += u"<div><b>&emsp;relationships:</b></div>"
                                                for r in relationships:
                                                    for k, v in r.items():
                                                        tbl += u"<div><b>&emsp;&emsp;{0}:</b>{1}</div>".format(k, v)
                                                tbl += u"<br>"
                                        tbl += u"<br>"
                                    else:
                                        tbl += u"<div><b>{}:</b></div>".format(kw)
                                        tbl += u"<div><b>&emsp{}</b></div>".format(vw)
                            tbl += u"<br>"
                            obj_cnt += 1
                            newrow[f1] = tbl
                        else:
                            newrow[f1] = "{}".format(", ".join(am[f2]))
                    elif isinstance(am[f2], (bool, dict)):
                        newrow[f1] = str(am[f2])
                    else:
                        newrow[f1] = "{}".format(am[f2])
            note_text += u"<br>The data table <b>{0}</b> has been updated".format("Extrahop Activitymaps")
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get activitymaps for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) get detection note

Get a note from an ExtraHop detection. Parameter detection_id.

screenshot: fn-extrahop-revealx-get-detection-note

The function provides the following functionality.

  • Gets the current note from a detection in the ExtraHop environment.

NOTE: Get detection note will fail if Detection Tracking is enabled on ExtraHop.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) update detection.

  • The current note is retrieved from the ExtraHop detection when a matching SOAR incident is closed.

The workflow is initiated by the automatic data table rule Example: Extrahop Reveal(x) update detection whern a SOAR incident is closed

Inputs:

Name Type Required Example Tooltip
extrahop_detection_id number No - Extrahop detection ID

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": {
      "author": "setup",
      "note": "\nIBM SOAR 16/05/2022 15:13:37\n[SOAR Case - 4305](https://127.0.0.1:1443/#incidents/4305)",
      "update_time": 1652711350410
    }
  },
  "inputs": {
    "extrahop_detection_id": 3
  },
  "metrics": {
    "execution_time_ms": 780,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-05-16 15:29:13",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

inputs.extrahop_detection_id = incident.properties.extrahop_detection_id

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_update_detection post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_detection_note"
WF_NAME = "Example: Extrahop Reveal(x) update detection"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    if CONTENT:
        if CONTENT.get("result"):
            result = CONTENT.result
            if result.get("note"):
                workflow.addProperty("get_note_ok", {})
        elif CONTENT.get("error"):
            note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: Get detection note failed for " \
                        u"SOAR function <b>{1}</b> with parameters <b>{2}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            note_text += u"<br>Error code: <b>{0}</b>, Error <b>{1}<b>.".format(CONTENT.get("error"), CONTENT.get("text"))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get a detection note for SOAR function <b>{1}</b> with parameters <b>{2}</b>."\
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
    if note_text:
        incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) get detections

Get detections information from Extrahop Reveal(x). Optional parameter extrahop_detection_id.

screenshot: fn-extrahop-revealx-get-detections

The function provides the following functionality.

  • Retrieves information on detections in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) update incident.

  • A note is added to the SOAR incident with the status of the action.
  • The data table ExtraHop Detections is updated.

The workflow is initiated by the automatic incident rule Example: Extrahop Reveal(x) update incident. The following screenshots show an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-get-detections-datatable screenshot: fn-extrahop-revealx-get-detections-datatable_2 screenshot: fn-extrahop-revealx-get-detections-datatable_3

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-get-detections-note

Inputs:

Name Type Required Example Tooltip
extrahop_detection_id number No - Extrahop detection ID
extrahop_limit number No - (Optional) Limit the number of devices returned to the specified maximum number.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": {
      "appliance_id": 0,
      "assignee": "a@a.com",
      "categories": [
        "sec",
        "sec.caution"
      ],
      "description": "Over the past week, servers negotiated SSL/TLS sessions with a cipher suite that includes an encryption algorithm that is known to be vulnerable. Cipher suites that contain weak encryption algorithms such as CBC, 3DES, RC4, null, anonymous, and export should be removed from servers and replaced with stronger cipher suites.",
      "end_time": 1647051270000,
      "id": 71,
      "is_user_created": false,
      "mitre_tactics": [],
      "mitre_techniques": [],
      "participants": [
        {
          "external": false,
          "id": 175,
          "object_id": 3,
          "object_type": "device",
          "role": "offender"
        },
        {
          "external": false,
          "id": 179,
          "object_id": 6,
          "object_type": "device",
          "role": "offender"
        }
      ],
      "properties": {},
      "resolution": null,
      "risk_score": 61,
      "start_time": 1646559540000,
      "status": "in_progress",
      "ticket_id": "3055",
      "title": "Weekly Summary: Weak Cipher Suites",
      "type": "weak_cipher",
      "update_time": 1647656040000
    }
  },
  "inputs": {
    "extrahop_detection_id": 71
  },
  "metrics": {
    "execution_time_ms": 1373,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:01:56",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

inputs.extrahop_detection_id = incident.properties.extrahop_detection_id

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_update_incident post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_detections"
WF_NAME = "Example: Extrahop Reveal(x) refresh incident"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
DATA_TABLE = "extrahop_detections"
DATA_TBL_FIELDS = ["appliance_id", "assignee", "categories", "det_description", "end_time", "det_id", "is_user_created",
                   "mitre_tactics", "mitre_techniques", "participants", "properties", "resolution", "risk_score",
                   "start_time", "status", "ticket_id", "ticket_url", "title", "type", "update_time"]
# Read CATEGORY_MAP and TYPE_MAP from workflow property.
CATEGORY_MAP = workflow.properties.category_map
TYPE_MAP = workflow.properties.type_map
LINKBACK_URL = "/extrahop/#/detections/detail/{}"

# Processing
def make_linkback_url(det_id):
    """Create a url to link back to the detection.

    Args:
        det_id (str/int): representing the detection.

    Returns:
        str: completed url for linkback
    """
    return incident.properties.extrahop_console_url + LINKBACK_URL.format(det_id)

def addArtifact(artifact_type, artifact_value, description):
    """Add new artifacts to the incident.

    :param artifact_type: The type of the artifact.
    :param artifact_value: - The value of the artifact.
    :param description: - the description of the artifact.
    """
    incident.addArtifact(artifact_type, artifact_value, description)

# Processing
def main():
    detection_id = INPUTS["extrahop_detection_id"]
    note_text = u''
    if CONTENT:
        det = CONTENT.result
        note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: A Detection was successfully returned for " \
                    u"detection ID <b>{1}</b> for SOAR function <b>{2}</b> with parameters <b>{3}</b>." \
            .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        if det:
            detection_url = make_linkback_url(det["id"])
            detection_url_html = u'<div><b><a target="blank" href="{0}">{1}</a></b></div>' \
                         .format(detection_url, det["id"])
            newrow = incident.addRow(DATA_TABLE)
            newrow.query_execution_date = QUERY_EXECUTION_DATE
            newrow.detection_url = detection_url_html
            for f1 in DATA_TBL_FIELDS:
                f2 = f1
                if f1.startswith("det_"):
                    f2 = f1.split('_', 1)[1]
                if det[f2] is None or isinstance(det[f2], long):
                    newrow[f1] = det[f2]
                elif isinstance(det[f1], list):
                    if f1 == "categories":
                        newrow[f1] = "{}".format(", ".join(CATEGORY_MAP[c] if CATEGORY_MAP.get(c) else c for c in det[f2]))
                    elif f1 in ["participants", "mitre_tactics", "mitre_techniques"]:
                        if f1 == "participants":
                            for p in det[f2]:
                                if p["object_type"] == "ipaddr":
                                    artifact_type = "IP Address"
                                    addArtifact(artifact_type, p["object_value"],
                                                "Participant IP address in ExtraHop detection '{0}', role: '{1}'."
                                                .format(det["id"], p["role"]))
                                    if p["hostname"]:
                                        artifact_type = "DNS Name"
                                        addArtifact(artifact_type, p["hostname"],
                                                    "Participant DNS name in ExtraHop detection '{0}', role: '{1}'."
                                                    .format(det["id"], p["role"]))
                        obj_cnt = 0
                        tbl = u''
                        for i in det[f2]:
                            for k, v in i.items():
                                if k == "legacy_ids":
                                    tbl += u'<div><b>{0}:</b>{1}</div>'.format(k, ','.join(v))
                                elif k == "url":
                                    tbl += u'<div><b>{0}:<a target="blank" href="{1}">{2}</a></div>' \
                                        .format(k, v, i["id"])
                                else:
                                    tbl += u'<div><b>{0}:</b>{1}</div>'.format(k, v)
                            tbl += u"<br>"
                            obj_cnt += 1
                        newrow[f1] = tbl
                    else:
                        newrow[f1] = "{}".format(", ".join(det[f2]))
                elif isinstance(det[f2], (bool, dict)):
                    if f1 in ["properties"]:
                        tbl = u''
                        for i, j in det[f2].items():
                            if i == "suspicious_ipaddr":
                                artifact_type = "IP Address"
                                type = "Suspicious IP Addresses"
                                value = j["value"]
                                for ip in value:
                                    addArtifact(artifact_type, ip, "Suspicious IP address found by ExtraHop.")
                                tbl += u'<div><b>{0}:'.format(type)
                                tbl += u'<div><b>{0}'.format(", ".join("{}".format(i) for i in value))
                            else:
                                tbl += u'<div><b>{0}:</b>{1}</div>'.format(i, j)
                        newrow[f1] = tbl
                    else:
                        newrow[f1] = str(det[f2])
                else:
                    if f1 == "type":
                        newrow[f1] = TYPE_MAP[det[f2]] if TYPE_MAP.get(det[f2]) else det[f2]
                    elif f1 == "ticket_url":
                        newrow[f1] =  u'<div><b><a target="blank" href="{0}">{1}</a></div>'.format(det[f2], det[f2].split('/')[-1])
                    else:
                        newrow[f1] = "{}".format(det[f2])
            note_text += u"<br>The data table <b>{0}</b> has been updated".format("Extrahop Detections")
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get detections for detection ID <b>{1}</b> for SOAR function <b>{2}</b> ." \
                     u" with parameters <b>{3}</b>." \
            .format(WF_NAME, detection_id, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))


main()


Function - Extrahop Reveal(x) get devices

Get devices information from Extrahop Reveal(x). Optional parameters device_id, active_from, active_util, limit and offset.

screenshot: fn-extrahop-revealx-get-devices

The function provides the following functionality.

  • Retrieves information for devices in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) search devices.

  • A note is added to the SOAR incident with the status of the action.
  • The data table ExtraHop Devices is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) search devices.

screenshot: fn-extrahop-revealx-get-devices-action

screenshot: fn-extrahop-revealx-get-devices-action_2

The following screenshots show an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-get-devices-datatable

screenshot: fn-extrahop-revealx-get-devices-datatable_2

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-get-devices-note

Inputs:

Name Type Required Example Tooltip
extrahop_active_from number No - (Optional) The beginning timestamp for the request. Return only devices active after this time. Time is expressed in milliseconds since the epoch. 0 indicates the time of the request.
extrahop_active_until number No - (Optional) The ending timestamp for the request. Return only devices active before this time.
extrahop_device_id number No - Extrahop device ID
extrahop_limit number No - (Optional) Limit the number of devices returned to the specified maximum number.
extrahop_offset number No - (Optional) Skip the specified number of devices. This parameter is often combined with the limit parameter to paginate result sets.
extrahop_search_type text No - Indicates the field to search.
extrahop_value text No - Indicates the vakue to search for.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "analysis": "advanced",
        "analysis_level": 2,
        "auto_role": "http_server",
        "cdp_name": "",
        "cloud_account": null,
        "cloud_instance_id": null,
        "cloud_instance_name": null,
        "cloud_instance_type": null,
        "critical": false,
        "custom_criticality": null,
        "custom_make": null,
        "custom_model": null,
        "custom_name": null,
        "custom_type": "",
        "default_name": "Device 027437b63df40000",
        "description": null,
        "device_class": "node",
        "dhcp_name": "",
        "discover_time": 1644418590000,
        "discovery_id": "027437b63df40000",
        "display_name": "Device 027437b63df40000",
        "dns_name": "",
        "extrahop_id": "027437b63df40000",
        "id": 6,
        "ipaddr4": "192.168.1.2",
        "ipaddr6": null,
        "is_l3": false,
        "last_seen_time": 1647052260000,
        "macaddr": "02:74:37:B6:3D:F4",
        "mod_time": 1647052291076,
        "model": null,
        "model_override": null,
        "netbios_name": "",
        "node_id": null,
        "on_watchlist": true,
        "parent_id": null,
        "role": "http_server",
        "subnet_id": null,
        "user_mod_time": 1646046972271,
        "vendor": null,
        "vlanid": 0,
        "vpc_id": null
      }
    ]
  },
  "inputs": {},
  "metrics": {
    "execution_time_ms": 1558,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:02:00",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

search_filters =  [ 
    rule.properties.extrahop_device_field,
    rule.properties.extrahop_device_operand,
    rule.properties.extrahop_device_operator
]
for p in search_filters:
    if p:
        raise ValueError("A search filter and Device ID are not allowed at the same time.")
        
if rule.properties.extrahop_device_id:
    inputs.extrahop_device_id = rule.properties.extrahop_device_id
    
if rule.properties.extrahop_active_from:
    inputs.extrahop_active_from = rule.properties.extrahop_active_from
if rule.properties.extrahop_active_until:
    inputs.extrahop_active_until = rule.properties.extrahop_active_until
if rule.properties.extrahop_limit:
    inputs.extrahop_limit = rule.properties.extrahop_limit
if rule.properties.extrahop_offset:
    inputs.extrahop_offset = rule.properties.extrahop_offset

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_get_devices post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_devices"
WF_NAME = "Example: Extrahop Reveal(x) refresh incident"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
# Display subset of fields
DATA_TABLE = "extrahop_devices"
DATA_TBL_FIELDS = ["display_name", "devs_description", "default_name", "dns_name", "ipaddr4", "ipaddr6", "macaddr",
                   "role", "vendor", "devs_id", "extrahop_id", "activity", "mod_time", "user_mod_time", "discover_time", 
                   "last_seen_time"]
LINKBACK_URL = "/extrahop/#/metrics/devices/{}.{}"


def make_linkback_url(dev_id):
    """Create a url to link back to the endpoint alert, case, etc.

    Args:
        dev_id (str/int): representing the device etc.

    Returns:
        str: completed url for linkback
    """
    return incident.properties.extrahop_console_url + LINKBACK_URL.format(incident.properties.extrahop_site_uuid, dev_id)

def process_devs(dev):
    # Process a device result.
    newrow = incident.addRow(DATA_TABLE)
    newrow.query_execution_date = QUERY_EXECUTION_DATE
    for f1 in DATA_TBL_FIELDS:
        f2 = f1
        if f1.startswith("devs_"):
            f2 = f1.split('_', 1)[1]
        if dev[f1] is None:
            newrow[f1] = dev[f2]
        elif isinstance(dev[f2], list):
            newrow[f1] = "{}".format(", ".join(dev[f2]))
        elif isinstance(dev[f2], bool):
            newrow[f1] = str(dev[f2])
        elif f1 in ["mod_time", "user_mod_time", "discover_time", "last_seen_time"]:
            newrow[f1] = long(dev[f2])
        else:
            newrow[f1] = "{}".format(dev[f2])
    device_url = make_linkback_url(dev["extrahop_id"])
    device_url_html = u'<div><b><a target="blank" href="{1}">{2}</a></b></div>' \
              .format("url", device_url, dev["extrahop_id"])
    newrow.device_url = device_url_html

def get_dev_ids():
    # Get participant devs    
    dev_ids = []
    get_devices_content = workflow.properties.get_detections_result.content
    devs = get_devices_content["result"]
    participants = devs["participants"]
    for p in participants:
        if p["object_type"] == "device":
            dev_ids.append(p["object_id"])
    return dev_ids


# Processing
def main():
    participant_dev_ids = get_dev_ids()
    note_text = u''
    if CONTENT:
        devs = [d for d in CONTENT.result if d["id"] in participant_dev_ids]
        note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: There were <b>{1}</b> Devices returned for SOAR " \
                    u"function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, len(devs), FN_NAME, ", ".join(
            "{}:{}".format(k, v) for k, v in INPUTS.items()))
        if devs:
            if isinstance(devs, list):
                for dev in devs:
                    process_devs(dev)
            else:
                process_devs(devs)
            note_text += u"<br>The data table <b>{0}</b> has been updated".format(DATA_TABLE)

    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get devices for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

    #Unset the Detection update notification. 
    incident.properties.extrahop_update_notification = None
    
main()


Function - Extrahop Reveal(x) get tags

Get tags information from Extrahop Reveal(x). Optional parameter tag_id.

screenshot: fn-extrahop-revealx-get-tags

The function provides the following functionality.

  • Retrieves a list of tags discovered in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) get tags.

  • A note is added to the SOAR incident with the status of the action.
  • The data table Extrahop Tags is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) get tags.

screenshot: fn-extrahop-revealx-get-tags-action

The following screenshot shows an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-get-tags-datatable

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-get-tags-note

Inputs:

Name Type Required Example Tooltip
extrahop_tag_id number No - The unique identifier for the tag.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "id": 1,
        "mod_time": 1646045416014,
        "name": "TEST_TAG_1"
      },
      {
        "id": 2,
        "mod_time": 1646064909025,
        "name": "TEST_TAG_2"
      }
    ]
  },
  "inputs": {},
  "metrics": {
    "execution_time_ms": 969,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:19:40",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

if rule.properties.extrahop_tag_name is None:
    raise ValueError("The tag name is not set")

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_get_tags post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_tags"
WF_NAME = "Example: Extrahop Reveal(x) assign tag"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    tag_name = rule.properties.extrahop_tag_name
    tag_id = None
    
    if CONTENT:
        tags = CONTENT.result
        if tags:
            for tag in tags:
                if tag_name == tag["name"]:
                    tag_id = tag["id"]
                    workflow.addProperty("tag_exists", {})
                    break
            if not tag_id:
                note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Tag <b>'{1}'</b> not returned for SOAR function <b>{2}</b> "\
                            u"with parameters <b>{3}</b>."\
                    .format(WF_NAME, tag_name, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get tags for SOAR function <b>{1}</b> with parameters <b>{2}</b>."\
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
    if note_text:
        incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) get watchlist

Retrieve all devices that are in the watchlist from Extrahop Reveal(x).

screenshot: fn-extrahop-revealx-get-watchlist

The function provides the following functionality.

  • Retrieves a list of devices on the watchlist in the ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) get watchlist.

  • A note is added to the SOAR incident with the status of the action.
  • The data table Extrahop Watchlist is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) get watchlist.

screenshot: fn-extrahop-revealx-get-watchlist-action

The following screenshot shows an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-get-watchlist-datatable

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-get-watchlist-note

Inputs:

Name Type Required Example Tooltip

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "analysis": "advanced",
        "analysis_level": 2,
        "auto_role": "http_server",
        "cdp_name": "",
        "cloud_account": null,
        "cloud_instance_id": null,
        "cloud_instance_name": null,
        "cloud_instance_type": null,
        "critical": false,
        "custom_criticality": null,
        "custom_make": null,
        "custom_model": null,
        "custom_name": null,
        "custom_type": "",
        "default_name": "Device 027437b63df40000",
        "description": null,
        "device_class": "node",
        "dhcp_name": "",
        "discover_time": 1644418590000,
        "discovery_id": "027437b63df40000",
        "display_name": "Device 027437b63df40000",
        "dns_name": "",
        "extrahop_id": "027437b63df40000",
        "id": 6,
        "ipaddr4": "192.168.1.2",
        "ipaddr6": null,
        "is_l3": false,
        "last_seen_time": 1647052260000,
        "macaddr": "02:74:37:B6:3D:F4",
        "mod_time": 1647052291076,
        "model": null,
        "model_override": null,
        "netbios_name": "",
        "node_id": null,
        "on_watchlist": true,
        "parent_id": null,
        "role": "http_server",
        "subnet_id": null,
        "user_mod_time": 1646046972271,
        "vendor": null,
        "vlanid": 0,
        "vpc_id": null
      }
    ]
  },
  "inputs": {},
  "metrics": {
    "execution_time_ms": 739,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 16:50:11",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

None

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_get_watchlist post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_get_watchlist"
WF_NAME = "Example: Extrahop Reveal(x) get watchlist"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
# Display subset of fields
DATA_TABLE = "extrahop_watchlist"
DATA_TBL_FIELDS = ["display_name", "ipaddr4", "ipaddr6", "macaddr", "extrahop_id"]

# Processing
def main():
    note_text = u''
    if CONTENT:
        devs = CONTENT.result
        note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: There were <b>{1}</b> devices returned in the Watchlist" \
                    u" for SOAR function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, len(devs), FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        if devs:
            for dev in devs:
                newrow = incident.addRow("extrahop_watchlist")
                newrow.query_execution_date = QUERY_EXECUTION_DATE
                for f1 in DATA_TBL_FIELDS:
                  f2 = f1
                  if dev[f1] is None:
                      newrow[f1] = dev[f2]
                  if isinstance(dev[f1], list):
                      newrow[f1] = "{}".format(", ".join(dev[f2]))
                  elif isinstance(dev[f1], bool):
                      newrow[f1] = str(dev[f2])
                  else:
                      newrow[f1] = "{}".format(dev[f2])
            note_text += u"<br>The data table <b>{0}</b> has been updated".format("Extrahop Detections")

    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to get the watchlist for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) search detections

Search for detections information from Extrahop Reveal(x). Optional parameters search_filter, active_from, active_util, limit, offset, update_time and sort.

screenshot: fn-extrahop-revealx-search-detections

The function provides the following functionality.

  • Retrieves a list of detections in the ExtraHop environment based on the provided parameters.
  • A filter in JSON is used to target the information retrieved.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) search detections.

  • A note is added to the SOAR incident with the status of the action.
  • The data table Extrahop Detections is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) search detections.

The following screenshot shows an example of the action inputs for the workflow:

screenshot: fn-extrahop-revealx-search-detections-action

screenshot: fn-extrahop-revealx-search-detections-action_2

The following screenshot shows an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-search-detections-datatable screenshot: fn-extrahop-revealx-search-detections-datatable_2 screenshot: fn-extrahop-revealx-search-detections-datatable_3

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-search-detections-note

Inputs:

Name Type Required Example Tooltip
extrahop_active_from number No - (Optional) The beginning timestamp for the request. Return only devices active after this time. Time is expressed in milliseconds since the epoch. 0 indicates the time of the request.
extrahop_active_until number No - (Optional) The ending timestamp for the request. Return only devices active before this time.
extrahop_limit number No - (Optional) Limit the number of devices returned to the specified maximum number.
extrahop_offset number No - (Optional) Skip the specified number of devices. This parameter is often combined with the limit parameter to paginate result sets.
extrahop_search_filter text No - The filter criteria for Extrahop search results.
extrahop_sort text No - Sorts returned detections by the specified fields. By default, detections are sorted by most recent update time and then ID in ascending order.
extrahop_update_time number No - (Optional) Return detections that were updated on or after the specified date, expressed in milliseconds since the epoch.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "appliance_id": 0,
        "assignee": null,
        "categories": [
          "sec",
          "sec.caution"
        ],
        "description": "Over the past day, servers received connections from devices with suspicious IP addresses. These IP addresses are considered suspicious based on threat intelligence found in your Reveal(x) system. Investigate to determine if the IP addresses are from malicious endpoints.\n\nSuspicious IP addresses linked to this detection:\n* 109.237.103.9\n* 45.83.65.214\n* 45.83.67.186\n* 185.220.101.63\n* 185.220.101.191\n* 130.211.54.158\n* 192.241.212.103",
        "end_time": 1644556530000,
        "id": 3,
        "is_user_created": false,
        "mitre_tactics": [],
        "mitre_techniques": [],
        "participants": [
          {
            "external": false,
            "id": 8,
            "object_id": 2,
            "object_type": "device",
            "role": "victim"
          },
          {
            "external": false,
            "id": 11,
            "object_id": 6,
            "object_type": "device",
            "role": "victim"
          }
        ],
        "properties": {
          "suspicious_ipaddr": {
            "type": "ipaddr",
            "value": [
              "192.168.1.9",
              "192.168.1.214",
              "192.168.1.186",
              "192.168.1.63",
              "192.168.1.191",
              "192.168.1.158",
              "192.168.2.103"
            ]
          }
        },
        "resolution": null,
        "risk_score": 60,
        "start_time": 1644540480000,
        "status": "in_progress",
        "ticket_id": null,
        "title": "Daily Summary: Inbound Suspicious Connections",
        "type": "ti_tcp_incoming",
        "update_time": 1644642690000
      },
      {
        "appliance_id": 0,
        "assignee": "a@a.com",
        "categories": [
          "sec",
          "sec.exploit"
        ],
        "description": "[Device 02a1d541ff800000](#/metrics/devices/c708d037ae5a46b69ec4dcbf7e4555e5.02a1d541ff800000/overview?from=1646741073\u0026interval_type=DT\u0026until=1646741073) received a Remote Desktop Protocol (RDP) connection request that is consistent with a known vulnerability, also known as BlueKeep, in older versions of Microsoft Windows. This vulnerability allows an unauthenticated attacker to remotely run arbitrary code on an RDP server. The attacker can then tamper with data or install malware that could propagate to other Windows devices across the network. Investigate to determine if [Device 02a1d541ff800000](#/metrics/devices/c708d037ae5a46b69ec4dcbf7e4555e5.02a1d541ff800000/overview?from=1646741073\u0026interval_type=DT\u0026until=1646741073) is hosting a version affected by CVE-2019-0708: Windows 7, Windows XP, Windows Vista, Windows Server 2003, and Windows Server 2008.",
        "end_time": 1646741073962,
        "id": 79,
        "is_user_created": false,
        "mitre_tactics": [
          {
            "id": "TA0008",
            "name": "Lateral Movement",
            "url": "https://attack.mitre.org/tactics/TA0008"
          }
        ],
        "mitre_techniques": [
          {
            "id": "T1210",
            "legacy_ids": [
              "T1210"
            ],
            "name": "Exploitation of Remote Services",
            "url": "https://attack.mitre.org/techniques/T1210"
          }
        ],
        "participants": [
          {
            "external": false,
            "id": 194,
            "object_id": 2,
            "object_type": "device",
            "role": "victim"
          },
          {
            "external": true,
            "id": 195,
            "object_type": "ipaddr",
            "object_value": "216.218.206.66",
            "role": "offender"
          }
        ],
        "properties": {
          "client_port": 45214,
          "server_port": 3389
        },
        "resolution": null,
        "risk_score": 98,
        "start_time": 1646741073962,
        "status": "in_progress",
        "ticket_id": "2529",
        "title": "CVE-2019-0708 RDP Exploit Attempt",
        "type": "cve_2019_0708",
        "update_time": 1646741073962
      }
    ]
  },
  "inputs": {
    "extrahop_search_filter": "{\"filter\": {\"status\": [\"in_progress\"]}}"
  },
  "metrics": {
    "execution_time_ms": 948,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:53:38",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

'##  ExtraHop - wf_extrahop_rx_search_detections pre processing script ##
# Read CATEGORY_MAP and TYPE_MAP from workflow propertyself. 
# Reverse the dict keys and values
CATEGORY_MAP = {v: k for k, v in workflow.properties.category_map.items()}
TYPE_MAP = {v: k for k, v in workflow.properties.type_map.items()}
DOT_PARAMS = [
    "me",
    "none"
]


def get_prop(prop, type=None):
    if prop:
        if isinstance(prop, int):
            return prop
        elif isinstance(prop, list):
            return ['{}'.format('.' + i if i in DOT_PARAMS else i) for i in prop]
        else:
            result = '{}'.format('.' + prop if prop in DOT_PARAMS else prop)
        if type == "list":
            return [result]

        return result

    else:
        return None


filter = {}
search_filter = {}
category = None
detection_types = None
if rule.properties.extrahop_detection_category:
    category = CATEGORY_MAP[rule.properties.extrahop_detection_category]
if rule.properties.extrahop_detection_types:
    detection_types = [TYPE_MAP[d] for d in rule.properties.extrahop_detection_types]

filter_props = {
    "risk_score_min": get_prop(rule.properties.extrahop_detection_risk_score_min),
    "types": get_prop(detection_types),
    "category": get_prop(category),
    "assignee": get_prop(rule.properties.extrahop_detection_assignee, "list"),
    "ticket_id": get_prop(rule.properties.extrahop_detection_ticket_id, "list"),
    "status": get_prop(rule.properties.extrahop_detection_status),
    "resolution": get_prop(rule.properties.extrahop_detection_resolution)
}

filter = {k: v for k, v in filter_props.items() if v}

if filter:
    if rule.properties.extrahop_detection_id:
        raise ValueError("The search filter and Detecion ID are not allowed at the same time.")

    search_filter = {
        "filter": filter
    }
    inputs.extrahop_search_filter = str(search_filter).replace("'", '"')

if rule.properties.extrahop_active_from:
    inputs.extrahop_active_from = rule.properties.extrahop_active_from
if rule.properties.extrahop_active_until:
    inputs.extrahop_active_until = rule.properties.extrahop_active_until
if rule.properties.extrahop_limit:
    inputs.extrahop_limit = rule.properties.extrahop_limit
if rule.properties.extrahop_offset:
    inputs.extrahop_offset = rule.properties.extrahop_offset
if rule.properties.extrahop_update_time:
    inputs.extrahop_update_time = rule.properties.extrahop_update_time

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_search_detections post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_search_detections"
WF_NAME = "Example: Extrahop revealx search detections"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
DATA_TABLE = "extrahop_detections"
DATA_TBL_FIELDS = ["appliance_id", "assignee", "categories", "det_description", "end_time", "det_id", "is_user_created",
                   "mitre_tactics", "mitre_techniques", "participants", "properties", "resolution", "risk_score",
                   "start_time", "status", "ticket_id", "ticket_url", "title", "type", "update_time"]

# Read CATEGORY_MAP and TYPE_MAP from workflow property.
CATEGORY_MAP = workflow.properties.category_map
TYPE_MAP = workflow.properties.type_map

LINKBACK_URL = "/extrahop/#/detections/detail/{}"

# Processing
def process_dets(det):
    detection_url = make_linkback_url(det["id"])
    detection_url_html = u'<div><b><a target="blank" href="{0}">{1}</a></b></div>' \
        .format(detection_url, det["id"])
    newrow = incident.addRow(DATA_TABLE)
    newrow.query_execution_date = QUERY_EXECUTION_DATE
    newrow.detection_url = detection_url_html
    for f1 in DATA_TBL_FIELDS:
        f2 = f1
        if f1.startswith("det_"):
            f2 = f1.split('_', 1)[1]
        if det[f2] is None or isinstance(det[f2], long):
            newrow[f1] = det[f2]
        elif isinstance(det[f1], list):
            if f1 == "categories":
                newrow[f1] = "{}".format(", ".join(CATEGORY_MAP[c] if CATEGORY_MAP.get(c) else c for c in det[f2]))
            elif f1 in ["participants", "mitre_tactics", "mitre_techniques"]:
                obj_cnt = 0
                tbl = u''
                for i in det[f2]:
                    for k, v in i.items():
                        if k == "legacy_ids":
                            tbl += u'<div><b>{0}:</b>{1}</div>'.format(k, ','.join(v))
                        elif k == "url":
                            tbl += u'<div><b>{0}:<a target="blank" href="{1}">{2}</a></div>' \
                                .format(k, v, i["id"])
                        else:
                            tbl += u'<div><b>{0}:</b>{1}</div>'.format(k, v)
                    tbl += u"<br>"
                    obj_cnt += 1
                newrow[f1] = tbl
            else:
                newrow[f1] = "{}".format(", ".join(det[f2]))
        elif isinstance(det[f2], (bool, dict)):
            if f1 in ["properties"]:
                suspect_ip = False
                tbl = u''
                for i, j in det[f2].items():
                    if i == "suspicious_ipaddr":
                        artifact_type = "IP Address"
                        type = "Suspicious IP Addresses"
                        value = j["value"]
                        tbl += u'<div><b>{0}:'.format(type)
                        tbl += u'<div><b>{0}'.format(", ".join("{}".format(i) for i in value))
                    else:
                        tbl += u'<div><b>{0}:</b>{1}</div>'.format(i, j)
                newrow[f1] = tbl
            else:
                newrow[f1] = str(det[f2])
        else:
            if f1 == "type":
                newrow[f1] = TYPE_MAP[det[f2]] if TYPE_MAP.get(det[f2]) else det[f2]
            elif f1 == "ticket_url":
                newrow[f1] =  u'<div><b><a target="blank" href="{0}">{1}</a></div>'.format(det[f2], det[f2].split('/')[-1])
            else:
                newrow[f1] = "{}".format(det[f2])

# Processing
def make_linkback_url(det_id):
    """Create a url to link back to the detection.

    Args:
        det_id (str/int): representing the detection.

    Returns:
        str: completed url for linkback
    """
    return incident.properties.extrahop_console_url + LINKBACK_URL.format(det_id)

# Processing
def main():
    note_text = u''

    if CONTENT:
        dets = CONTENT.result
        note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: There were <b>{1}</b> Detections returned for SOAR " \
                    u"function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, len(dets), FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        if dets:
            for det in dets:
                process_dets(det)
            note_text += u"<br>The data table <b>{0}</b> has been updated".format("Extrahop Detections")

    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to search detections for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))
    
# Start execution
main()


Function - Extrahop Reveal(x) search devices

Search for devices information from Extrahop Reveal(x). Optional parameters search_filter, active_from, active_util, limit and offset.

screenshot: fn-extrahop-revealx-search-devices

The function provides the following functionality.

  • Retrieves a list of devices on the in the ExtraHop environment based on the parameters provided.
  • A filter in JSON is used to target the information retrieved.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) search devices.

  • A note is added to the SOAR incident with the status of the action.
  • The data table Extrahop Devices is updated.

The workflow is initiated by the manual incident rule Example: Extrahop Reveal(x) search devices.

The following screenshot shows an example of the action inputs for the workflow:

screenshot: fn-extrahop-revealx-search-devices-action

screenshot: fn-extrahop-revealx-search-devices-action_2

The following screenshot shows an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-search-devices-datatable

screenshot: fn-extrahop-revealx-search-devices-datatable_2

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-search-devices-note

Inputs:

Name Type Required Example Tooltip
extrahop_active_from number No - (Optional) The beginning timestamp for the request. Return only devices active after this time. Time is expressed in milliseconds since the epoch. 0 indicates the time of the request.
extrahop_active_until number No - (Optional) The ending timestamp for the request. Return only devices active before this time.
extrahop_limit number No - (Optional) Limit the number of devices returned to the specified maximum number.
extrahop_offset number No - (Optional) Skip the specified number of devices. This parameter is often combined with the limit parameter to paginate result sets.
extrahop_search_filter text No - The filter criteria for Extrahop search results.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": [
      {
        "analysis": "advanced",
        "analysis_level": 2,
        "auto_role": "other",
        "cdp_name": "",
        "cloud_account": null,
        "cloud_instance_id": null,
        "cloud_instance_name": null,
        "cloud_instance_type": null,
        "critical": false,
        "custom_criticality": null,
        "custom_make": null,
        "custom_model": null,
        "custom_name": null,
        "custom_type": "",
        "default_name": "Device 02f6b87341f00000",
        "description": null,
        "device_class": "node",
        "dhcp_name": "",
        "discover_time": 1644418320000,
        "discovery_id": "02f6b87341f00000",
        "display_name": "Device 02f6b87341f00000",
        "dns_name": "",
        "extrahop_id": "02f6b87341f00000",
        "id": 3,
        "ipaddr4": "192.168.1.159",
        "ipaddr6": null,
        "is_l3": false,
        "last_seen_time": 1647052200000,
        "macaddr": "02:F6:B8:73:41:F0",
        "mod_time": 1649866540057,
        "model": null,
        "model_override": null,
        "netbios_name": "",
        "node_id": null,
        "on_watchlist": true,
        "parent_id": null,
        "role": "other",
        "subnet_id": null,
        "user_mod_time": 1644418537403,
        "vendor": null,
        "vlanid": 0,
        "vpc_id": null
      }
    ]
  },
  "inputs": {
    "extrahop_search_filter": "{\"filter\": {\"operator\": \"=\", \"field\": \"ipaddr\", \"operand\": \"192.168.1.159\"}}"
  },
  "metrics": {
    "execution_time_ms": 965,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:17:19",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

##  ExtraHop - wf_extrahop_rx_search_devices pre processing script ##

def get_prop(prop, type=None):
    if prop:
        return '{}'.format(prop)
    else:
        return None


def main():
    filter = {}
    search_filter = {}
    filter_props = {
        "field": get_prop(rule.properties.extrahop_device_field),
        "operand": get_prop(rule.properties.extrahop_device_operand),
        "operator": get_prop(rule.properties.extrahop_device_operator)
    }
    filter = {k: v for k, v in filter_props.items() if v}

    if filter and rule.properties.extrahop_device_id:
        raise ValueError("The device ID and search filter shouldn't be set at the same time.")

    if filter:
        missing_props = []
        for f in ["field", "operand", "operator"]:
            if not filter.get(f, None):
                missing_props.append(f)
        if missing_props:
            raise ValueError("The filter is missing properties: '{}'.".format(", ".join(missing_props)))

        search_filter = {
            "filter": filter
        }

    if rule.properties.extrahop_device_id:
        search_filter = {
            "filter": {
                "field": "discovery_id",
                "operator": "=",
                "operand": str(rule.properties.extrahop_device_id)
            }
        }
    if search_filter:
        inputs.extrahop_search_filter = str(search_filter).replace("'", '"')
    if rule.properties.extrahop_active_from:
        inputs.extrahop_active_from = rule.properties.extrahop_active_from
    if rule.properties.extrahop_active_until:
        inputs.extrahop_active_until = rule.properties.extrahop_active_until
    if rule.properties.extrahop_limit:
        inputs.extrahop_limit = rule.properties.extrahop_limit
    if rule.properties.extrahop_offset:
        inputs.extrahop_offset = rule.properties.extrahop_offset


main()

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_search_devices post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_search_devices"
WF_NAME = "Example: Extrahop Reveal(x) search devices"
CONTENT = results.content
INPUTS = results.inputs
QUERY_EXECUTION_DATE = results["metrics"]["timestamp"]
# Display subset of fields
DATA_TABLE = "extrahop_devices"
DATA_TBL_FIELDS = ["display_name", "devs_description", "default_name", "dns_name", "ipaddr4", "ipaddr6", "macaddr",
                   "role", "vendor", "devs_id", "extrahop_id", "activity", "on_watchlist", "mod_time", "user_mod_time", "discover_time", 
                   "last_seen_time"]

LINKBACK_URL = "/extrahop/#/metrics/devices/{}.{}"


# Processing
def make_linkback_url(dev_id):
    """Create a url to link back to the endpoint alert, case, etc.

    Args:
        dev_id (str/int): representing the device etc.

    Returns:
        str: completed url for linkback
    """
    return incident.properties.extrahop_console_url + LINKBACK_URL.format(incident.properties.extrahop_site_uuid, dev_id)

def process_devs(dev):
    # Process a device result.
    newrow = incident.addRow(DATA_TABLE)
    newrow.query_execution_date = QUERY_EXECUTION_DATE
    for f1 in DATA_TBL_FIELDS:
        f2 = f1
        if f1.startswith("devs_"):
            f2 = f1.split('_', 1)[1]
        if dev[f1] is None:
            newrow[f1] = dev[f2]
        elif isinstance(dev[f2], list):
            newrow[f1] = "{}".format(", ".join(dev[f2]))
        elif isinstance(dev[f2], bool):
            newrow[f1] = str(dev[f2])
        elif f1 in ["mod_time", "user_mod_time", "discover_time", "last_seen_time"]:
            newrow[f1] = long(dev[f2])
        else:
            newrow[f1] = "{}".format(dev[f2])
    device_url = make_linkback_url(dev["extrahop_id"])
    device_url_html = u'<div><b><a target="blank" href="{1}">{2}</a></b></div>' \
              .format("url", device_url, dev["extrahop_id"])
    newrow.device_url = device_url_html

def main():
    note_text = u''
    if CONTENT:
        if CONTENT.get("error", None):
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Search devices failed with error <b>'{1}'</b> for " \
                        u"SOAR function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, CONTENT["error"], FN_NAME, ", ".join(unicode("{}:{}").format(k, v) for k, v in INPUTS.items()))
        else:
            devs = CONTENT.result
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: There were <b>{1}</b> Devices returned for SOAR " \
                        u"function <b>{2}</b> with parameters <b>{3}</b>.".format(WF_NAME, len(devs), FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            if devs:
                for dev in devs:
                    process_devs(dev)
                note_text += u"<br>The data table <b>{0}</b> has been updated".format(DATA_TABLE)

    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to search devices for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) search packets

Search for and download packets stored on the ExtraHop Reveal(x) system. Valid output types are: pcap, keylog_txt or zip.

screenshot: fn-extrahop-revealx-search-packets

The function provides the following functionality.

  • Does a packet search and download from an ExtraHop environment. The packet data can be downloaded in pcap, zip and keylog_txt output format.

NOTE: Extra configuration is required to use the keylog_txt output. Session key download

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) search packets.

  • A note is added to the SOAR incident with the status of the action.
  • An attachment in the select output format is added to the SOAR incident.

The workflow is initiated by the manual incident artifact rule Example: Extrahop Reveal(x) search packets.

The following screenshot shows an example of the action inputs for the workflow:

screenshot: fn-extrahop-revealx-search-packets-action

screenshot: fn-extrahop-revealx-search-packets-action_2

The following screenshot shows an example of the attachments added by the function:

screenshot: fn-extrahop-revealx-search-packets-attachment

The following screenshot shows an example of notes added to a SOAR incident:

screenshot: fn-extrahop-revealx-search-packets-note

Inputs:

Name Type Required Example Tooltip
extrahop_active_from number No - (Optional) The beginning timestamp for the request. Return only devices active after this time. Time is expressed in milliseconds since the epoch. 0 indicates the time of the request.
extrahop_active_until number No - (Optional) The ending timestamp for the request. Return only devices active before this time.
extrahop_always_return_body boolean No - If True return an empty packet capture file and an HTTP status of 200.
extrahop_bpf text No host 192.168.1.2 dst host 192.168.1.3 Filter packets with Berkeley Packet Filter syntax.
extrahop_ip1 text No - Return packets sent to or received by the specified IP address.
extrahop_ip2 text No - Return packets sent to or received by the specified IP address.
extrahop_limit_bytes text No - The maximum number of bytes to return.
extrahop_limit_search_duration text No - The maximum amount of time to run the packet search.
extrahop_output text No - The output format. Valid values pcap , keylog_txt and zip
extrahop_port1 text No - Return packets sent from or received on the specified port.
extrahop_port2 text No - Return packets sent from or received on the specified port.
incident_id number Yes - The ID for the incident in SOAR

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": {
      "attachment": "\u003cb\u003eextrahop 2022-05-11 16.00.00 to 2022-05-12 21.39.30 PDT.pcap\u003c/b\u003e"
    }
  },
  "inputs": {
    "extrahop_active_from": 1652310000000,
    "extrahop_active_until": null,
    "extrahop_bpf": "host 192.168.1.2",
    "extrahop_ip1": null,
    "extrahop_ip2": null,
    "extrahop_limit_bytes": null,
    "extrahop_limit_search_duration": null,
    "extrahop_output": "pcap",
    "extrahop_port1": null,
    "extrahop_port2": null,
    "incident_id": 4307
  },
  "metrics": {
    "execution_time_ms": 20395,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-05-17 11:24:39",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

inputs.incident_id = incident.id
if artifact.type == "IP Address" or artifact.type == "DNS Name":
    inputs.extrahop_bpf = "host {}".format(artifact.value)
elif artifact.type == "MAC Address":
    inputs.extrahop_bpf = "ether host {}".format(artifact.value)
inputs.extrahop_active_from = rule.properties.extrahop_active_from
inputs.extrahop_active_until = rule.properties.extrahop_active_until
inputs.extrahop_output = rule.properties.extrahop_output
inputs.extrahop_limit_search_duration = rule.properties.extrahop_limit_search_duration
inputs.extrahop_limit_bytes = rule.properties.extrahop_limit_bytes
inputs.extrahop_ip1 = rule.properties.extrahop_ip1
inputs.extrahop_port1 = rule.properties.extrahop_port1
inputs.extrahop_ip2 = rule.properties.extrahop_ip2
inputs.extrahop_port2 = rule.properties.extrahop_port2

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_search_packets post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_search_packets"
WF_NAME = "Example: Extrahop Reveal(x) search packets"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    if CONTENT:
        result = CONTENT.result
        if result.get("attachment"):
            note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully searched for packets for SOAR " \
                        u"function <b>{1}</b> with parameters <b>{2}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            note_text += u"<br>Attachment <b>{}<b> added.".format(result.get("attachment"))
        elif result.get("status"):
            note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: Search for packets returned no results for SOAR " \
                        u"SOAR function <b>{1}</b> with parameters <b>{2}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            note_text += u"<br>Status <b>{}<b>.".format(result.get("status"))
        elif result.get("error"):
            note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: Search for packets failed for " \
                        u"SOAR function <b>{1}</b> with parameters <b>{2}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
            note_text += u"<br>Error <b>{}<b>.".format(result.get("error"))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to search packets for SOAR function <b>{1}</b> with parameters <b>{2}</b>." \
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) update detection

Update a detection in Extrahop Reveal(x). Required parameter incident_id, detection_id, owner_id, plan_status, resolution. Optional parameters participants. screenshot: fn-extrahop-revealx-update-detection

The function provides the following functionality.

  • Updates the status, resolution, ticket ID, assignee and optionally participants of an ExtraHop detection.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) update detection.

  • Closes an ExtraHop detection if the equivalent SOAR incident is closed.
  • A note is added to the SOAR incident with the status of the action.
  • A note is added to the ExtraHop detection.

NOTE: Get or add ExtraHop detection note will fail if Detection Tracking is enabled on ExtraHop but the workflow should still complete.

The workflow is initiated by an automatic incident rule Example: Extrahop Reveal(x) update detection

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-update-detection-note

Inputs:

Name Type Required Example Tooltip
extrahop_detection_id number No - Extrahop detection ID
extrahop_participants text No { "id": 0, "usernames": [], "origins": [] } A list of devices and applications associated with a detection.
incident_id number Yes - The ID for the incident in SOAR
soar_inc_owner_id text No - -
soar_inc_plan_status text No - SOAR incident status
soar_inc_resolution_id text No - SOAR incident resolution

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": "success"
  },
  "inputs": {
    "extrahop_detection_id": 71,
    "incident_id": 3235,
    "soar_inc_owner_id": "a@a.com",
    "soar_inc_plan_status": "C",
    "soar_inc_resolution_id": "Resolved"
  },
  "metrics": {
    "execution_time_ms": 1084,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:21:32",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

inputs.extrahop_detection_id = incident.properties.extrahop_detection_id
inputs.incident_id = incident.id
inputs.soar_inc_owner_id = incident.owner_id
inputs.soar_inc_plan_status = incident.plan_status
inputs.soar_inc_resolution_id = incident.resolution_id

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_update_setection post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_update_detection"
WF_NAME = "Example: Extrahop Reveal(x) update detection"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    if CONTENT:
        result = CONTENT["result"]
        if result == "success":
            workflow.addProperty("update_detection_ok", {})
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully updated the detection status for SOAR " \
                        u"function <b>{1}</b> with parameters <b>{2}</b>.".format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        elif result == "failed":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to update the detection status for " \
                        u"SOAR function <b>{1}</b> with parameters <b>{2}</b>.".format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        else:
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Update detection status failed with unexpected " \
                        u"response for SOAR function <b>{1}</b> with parameters <b>{2}</b>.".format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to update the detection status <b>{1}</b> for SOAR function <b>{2}</b> with parameters <b>{3}</b>."\
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))

    incident.addNote(helper.createRichText(note_text))

main()


Function - Extrahop Reveal(x) update watchlist

Add or remove devices from the watchlist on Extrahop Reveal(x). Required parameter assign or unassign comma-seperated list of devices.

screenshot: fn-extrahop-revealx-update-watchlist

The function provides the following functionality.

  • Adds or removes devices to or from the ExtraHop watchlist of the target ExtraHop environment.

An example workflow that uses this SOAR function is Example: Extrahop Reveal(x) update watchlist.

  • Adds a device or list ExtraHop devices to the watchlist of the target ExtraHop environment.
  • Refreshes the associated row of the data table ExtraHop Devices.
  • A note is added to the SOAR incident with the status of the action.

The workflow is initiated by the manual data table rule Example: Extrahop Reveal(x) assign tag.

The following screenshot shows an example of the action inputs for the workflow:

screenshot: fn-extrahop-revealx-update-watchlist-action

screenshot: fn-extrahop-revealx-update-watchlist-action_2

The following screenshot shows an example of the data table updated by the function:

screenshot: fn-extrahop-revealx-update-watchlist-datatable

The following screenshot shows an example of a note added to a SOAR incident:

screenshot: fn-extrahop-revealx-update-watchlist-note

Inputs:

Name Type Required Example Tooltip
extrahop_assign text No - Comma or newline seperated list of devices to assign to a watchlist.
extrahop_unassign text No - Comma or newline seperated list of devices to unassign from a watchlist.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "content": {
    "result": "success"
  },
  "inputs": {
    "extrahop_assign": "3"
  },
  "metrics": {
    "execution_time_ms": 719,
    "host": "myhost.ibm.com",
    "package": "fn-extrahop",
    "package_version": "1.0.0",
    "timestamp": "2022-04-13 17:17:23",
    "version": "1.0"
  },
  "raw": null,
  "reason": null,
  "success": true,
  "version": 2.0
}

Example Pre-Process Script:

dev_id = row.devs_id
action = rule.properties.extrahop_watchlist_action
if action == "add":
    inputs.extrahop_assign = str(dev_id)
elif action == "remove":
    inputs.extrahop_unassign = str(dev_id)

Example Post-Process Script:

##  ExtraHop - wf_extrahop_rx_update_watchlist post processing script ##
#  Globals
FN_NAME = "funct_extrahop_rx_update_watchlist"
WF_NAME = "Example: Extrahop Reveal(x) update watchlist"
CONTENT = results.content
INPUTS = results.inputs

# Processing
def main():
    note_text = u''
    if CONTENT:
        result = CONTENT["result"]
        if result == "success":
            workflow.addProperty("watchlist_updated", {})
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Successfully updated the watchlist for SOAR " \
                        u"function <b>{1}</b> with parameters <b>{2}</b> for device <b>{3}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()), row.devs_id)
        elif result == "failed":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Failed to update the watchlist for " \
                        u"SOAR function <b>{1}</b> with parameters <b>{2}</b> for device <b>{3}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()))
        elif result == "conflict":
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: A 409 (conflict) error was thrown while attempting  " \
                        u"to update the watchlist for SOAR function <b>{1}</b> with parameters <b>{2}</b> for device <b>{3}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()), row.devs_id)
            note_text += u"<br>Check if the sensor is being managed from the cloud-based service."
        else:
            note_text = u"ExtraHop Integration: Workflow <b>{0}</b>: Update watchlist failed with unexpected " \
                        u"response for SOAR function <b>{1}</b> with parameters <b>{2}</b> for device <b>{3}</b>."\
                .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()), row.devs_id)
    else:
        note_text += u"ExtraHop Integration: Workflow <b>{0}</b>: There was <b>no</b> result returned while attempting " \
                     u"to update the watchlist <b>{1}</b> with parameters <b>{2}</b> for device <b>{3}</b>."\
            .format(WF_NAME, FN_NAME, ", ".join("{}:{}".format(k, v) for k, v in INPUTS.items()), row.devs_id)

    incident.addNote(helper.createRichText(note_text))

main()


Script - ExtraHop script: add artifact from device

Add Devices data table field as a SOAR artifact.

Object: incident

Script Text:

# Create a SOAR artifact based on a dropdown which selects the corresponding data-table field.
ARTIFACT_TYPE = rule.properties.extrahop_artifact_type.replace(" (v4)" ,"").replace(" (v6)" ,"")

PARAMS = {
    "IP Address": row.ipaddr4,
    "DNS Name": row.dns_name,
    "MAC Address": row.macaddr
}
# Both IP address V4 or V6 will be added as type "IP Address".
if "v6" in rule.properties.extrahop_artifact_type:
    PARAMS.update({"IP Address": row.ipaddr6})

def addArtifact(artifact_type, artifact_value, description):
    """This method adds new artifacts to the incident derived from matches of the the regular expression

    :param artifact_type: The type of the artifact.
    :param artifact_value: - The value of the artifact.
    :param description: - the description of the artifact.
    """
    incident.addArtifact(artifact_type, artifact_value, description)

def validate_fields(fields, params):
    """
    Ensure required fields are present. Throw ValueError if not
    :param fields: Required fields.
    :param params: Data-table fields as parameters.
    :return: no return
    """
    for f in fields:
        if f not in params or not params.get(f) or params.get(f) == '':
            raise ValueError(str('Required data-table field is missing or empty for artifact type: ' + f))


def main():
    desc = ''

    validate_fields([ARTIFACT_TYPE], PARAMS)

    desc = "Artifact from Device detected in the ExtraHop environment. Device name '{}', Device ID '{}'.".format(row.default_name, row.devs_id)
    addArtifact(ARTIFACT_TYPE, PARAMS[ARTIFACT_TYPE], desc)


# Script execution starts here
if __name__ == "__main__":
    main()


Script - ExtraHop script: detection property helper

Set ExtraHop detection properties as workflow property dicts.

Object: incident

Script Text:

##  ExtraHop - scr_extrahop_detection_property_helper script ##
# Used to share data with several workflows.

# Map of detection category  display name to name.
CATEGORY_MAP = {
    "sec.action": "Actions on Objective",
    "sec.botnet": "Botnet",
    "sec.caution": "Caution",
    "sec.command": "Command & Control",
    "sec.cryptomining": "Cryptocurrency Mining",
    "sec.dos": "Denial of Service",
    "sec.exfil": "Exfiltration",
    "sec.exploit": "Exploitation",
    "sec.hardening": "Hardening",
    "sec.lateral": "Lateral Movement",
    "sec.ransomware": "Ransomware",
    "sec.recon": "Reconnaissance",
    "sec": "Security"
}
# Map of detection type name to  display name.
TYPE_MAP = {
    "aaa_auth_errors": "AAA Auth Errors",
    "aaa_brute_force": "Spike in AAA Failed Login Attempts",
    "abnormally_large_database_response": "Database Data Staging",
    "abnormal_s3_upload": "Data Exfiltration to S3 Bucket",
    "abnormal_user_creation": "Unusual User Creation",
    "add_printer_driver": "New Printer Driver Installation Request",
    "anonymous_ftp": "Anonymous FTP Auth Enabled",
    "apache_http_server_path_traversal": "Apache HTTP Server Path Traversal Exploit",
    "apache_struts2_exploit_attempt": "Apache Struts 2 Exploit Attempt",
    "attempted_connections_dropped": "Attempted Connections Dropped",
    "aws_imds_proxying": "AWS Instance Metadata Service (IMDS) Proxy",
    "aws_services_enumeration": "AWS Cloud Service Enumeration",
    "bittorrent_activity": "BitTorrent Activity",
    "blacklisted_cert": "Suspicious SSL/TLS Certificates",
    "bloodhound_enumeration_activity": "BloodHound Enumeration Activity",
    "c2_web_beaconing": "Command-and-Control Beaconing",
    "call_does_not_exist_error": "Call Does Not Exist Error",
    "cifs_round_trip_time": "SMB/CIFS Transaction Delays",
    "cisco_cdp_vulnerabilities": "Cisco CDP Exploit Attempt",
    "citrix_issues": "Citrix Issues",
    "cobalt_strike_c2_dns": "Cobalt Strike DNS Beaconing",
    "cobalt_strike_c2_http": "Cobalt Strike C&C HTTP Connection",
    "cobalt_strike_c2_tls": "Cobalt Strike C&C SSL/TLS Connection",
    "crit_server_suspicious_download": "Suspicious File Download on Critical Server",
    "cryptocurrency_mining": "Cryptocurrency Mining",
    "cryptomining_pool_dns_request": "DNS Request for a Cryptocurrency Mining Pool",
    "cryptomining_pool_ssl_connection": "SSL/TLS Connection to a Cryptocurrency Mining Pool",
    "customer_detection_template": "Custom",
    "cve_2017_12635": "CVE-2017-12635 Apache CouchDB Exploit Attempt",
    "cve_2018_1111": "CVE-2018-1111 Red Hat DHCP Exploit Attempt",
    "cve_2018_13379": "CVE-2018-13379 Fortinet FortiOS Exploit",
    "cve_2018_15961": "CVE-2018-15961 Adobe ColdFusion Exploit Attempt",
    "cve_2018_7600": "Drupal Exploit Attempt",
    "cve_2019_0193": "CVE-2019-0193 Apache Solr Exploit Attempt",
    "cve_2019_0604": "CVE-2019-0604 Microsoft SharePoint Exploit Attempt",
    "cve_2019_0708": "CVE-2019-0708 RDP Exploit Attempt",
    "cve_2019_10149": "CVE-2019-10149 Exim Exploit Attempt",
    "cve_2019_11510": "CVE-2019-11510 Pulse Connect Secure Exploit Attempt",
    "cve_2019_11580": "CVE-2019-11580: Atlassian Crowd Vulnerability",
    "cve_2019_15846": "CVE-2019-15846 Exim Exploit Attempt",
    "cve_2019_17558": "CVE-2019-17558 Apache Solr Exploit",
    "cve_2019_19781_exploit": "CVE-2019-19781 Citrix ADC and Gateway Exploit",
    "cve_2019_19781_scan": "CVE-2019-19781 Citrix ADC and Gateway Scan",
    "cve_2019_2725": "Oracle WebLogic Exploit",
    "cve_2019_8394": "CVE-2019-8394 Zoho ManageEngine Exploit Attempt",
    "cve_2019_9670": "CVE-2019-9670 Synacor Zimbra Collaboration Suite Exploit Attempt",
    "cve_2020_0601": "CVE-2020-0601 Windows CryptoAPI ECC Validation Vulnerability",
    "cve_2020_0796": "CVE-2020-0796 Windows 10 SMBv3 Exploit Attempt",
    "cve_2020_10189": "CVE-2020-10189 Zoho ManageEngine Exploit",
    "cve_2020_11651": "CVE-2020-11651 Salt Exploit Attempt",
    "cve_2020_12695": "CVE-2020-12695 UPnP Exploit Attempt",
    "cve_2020_1301": "CVE-2020-1301 SMBv1 Exploit",
    "cve_2020_1350": "CVE-2020-1350 SIGRed Exploit Attempt",
    "cve_2020_1472": "CVE-2020-1472 Zerologon Scan",
    "cve_2020_1472_exploit": "CVE-2020-1472 Zerologon Exploit Attempt",
    "cve_2020_15505": "CVE-2020-15505 MobileIron Core and Connector Exploit Attempt",
    "cve_2020_16898": "CVE-2020-16898 Windows TCP/IP Stack Exploit Attempt",
    "cve_2020_16899": "CVE-2020-16899 Windows TCP/IP Stack Exploit Attempt",
    "cve_2020_17051": "CVE-2020-17051 Windows NFS Exploit Attempt",
    "cve_2020_1938": "CVE-2020-1938 Ghostcat Exploit",
    "cve_2020_25577": "CVE-2020-25577 FreeBSD Exploit Attempt",
    "cve_2020_25583": "CVE-2020-25583 FreeBSD Exploit Attempt",
    "cve_2020_3952": "CVE-2020-3952 VMware vCenter Exploit",
    "cve_2020_5902": "CVE-2020-5902 F5 BIG-IP Exploit",
    "cve_2020_6207": "CVE-2020-6207 SAP Solution Manager Exploit Attempt",
    "cve_2020_6287": "CVE-2020-6287 SAP RECON Vulnerability",
    "cve_2020_7247": "CVE-2020-7247 OpenSMTPD Exploit Attempt",
    "cve_2021_1497": "CVE-2021-1497 Cisco HyperFlex HX Exploit Attempt",
    "cve_2021_1498": "CVE-2021-1498 Cisco HyperFlex HX Exploit Attempt",
    "cve_2021_21972_exploit": "CVE-2021-21972 VMware vCenter Exploit",
    "cve_2021_21972_scan": "CVE-2021-21972 VMware vCenter Scan",
    "cve_2021_21974": "CVE-2021-21974 VMware ESXi OpenSLP Exploit Attempt",
    "cve_2021_21985": "CVE-2021-21985 VMware vCenter Exploit",
    "cve_2021_22005": "CVE-2021-22005 VMware vCenter Exploit",
    "cve_2021_22006": "CVE-2021-22006 VMware vCenter Exploit",
    "cve_2021_22205": "CVE-2021-22205 GitLab CE and EE Exploit Attempt",
    "cve_2021_22893": "CVE-2021-22893 Pulse Connect Secure Exploit Attempt",
    "cve_2021_22986": "CVE-2021-22986 F5 BIG-IP and BIG-IQ Exploit",
    "cve_2021_22991": "CVE-2021-22991 F5 BIG-IP Exploit",
    "cve_2021_26084": "CVE-2021-26084 Atlassian Confluence Exploit Attempt",
    "cve_2021_26432": "CVE-2021-26432 Windows NFS ONCRPC Exploit Attempt",
    "cve_2021_26877": "CVE-2021-26877 Windows DNS Server Exploit Attempt",
    "cve_2021_26897": "CVE-2021-26897 Windows DNS Server Exploit Attempt",
    "cve_2021_28324": "CVE-2021-28324 Windows 10 SMBv3 Exploit Attempt",
    "cve_2021_31166": "CVE-2021-31166 Windows HTTP Stack Exploit Attempt",
    "cve_2021_31181": "CVE-2021-31181 Microsoft SharePoint Exploit Attempt",
    "cve_2021_34467": "CVE-2021-34467 Microsoft SharePoint Exploit Attempt",
    "cve_2021_34473": "CVE-2021-34473 Microsoft Exchange Server Exploit",
    "cve_2021_34527": "CVE-2021-34527 Windows Print Spooler Exploit Attempt",
    "cve_2021_35394": "CVE-2021-35394 Realtek SDK Exploit Attempt",
    "cve_2021_35395": "CVE-2021-35395 Realtek SDK Exploit Attempt",
    "cve_2021_38647": "CVE-2021-38647 OMIGOD Exploit",
    "cve_2021_42321": "CVE-2021-42321 Microsoft Exchange Exploit Attempt",
    "cve_2021_43798": "CVE-2021-43798 Grafana Exploit Attempt",
    "cve_2021_44228_jndi_injection_attempt": "Log4Shell JNDI Injection Attempt",
    "cve_2021_44228_outbound_activity": "Outbound Log4Shell Activity",
    "cve_2022_0543": "CVE-2022-0543 Redis Exploit",
    "cve_2022_1388": "CVE-2022-1388 F5 BIG-IP Exploit",
    "cve_2022_21907": "CVE-2022-21907 Windows HTTP Stack Exploit Attempt",
    "cve_2022_22947": "CVE-2022-22947 Spring Cloud Gateway Exploit Attempt",
    "cve_2022_22963": "CVE-2022-22963 Spring Cloud Function Exploit Attempt",
    "database_brute_force": "Database Brute Force",
    "database_enumeration": "Database Enumeration",
    "database_issues": "Database Issues",
    "database_takeover": "Database Takeover Attack",
    "database_transaction_failures": "Database Transaction Failures",
    "data_exfil_by_vpn": "VPN Client Data Exfiltration",
    "data_exfiltration": "Data Exfiltration",
    "data_transfer_issues": "Data Transfer Issues",
    "db_processing_spike": "Poor Database Performance",
    "dcom_lateral_movement": "DCOM Remote Command Launch",
    "dcshadow": "DCShadow Attack",
    "dcsync": "DCSync Attack",
    "delayed_citrix_data_transfer": "Delayed Citrix Data Transfer",
    "delayed_database_data_transfer": "Delayed Database Data Transfer",
    "delayed_data_transfer": "Delayed Data Transfer",
    "delayed_email_data_transfer": "Delayed Email Data Transfer",
    "delayed_ftp_data_transfer": "Delayed FTP Data Transfer",
    "delayed_http_data_transfer": "Delayed HTTP Data Transfer",
    "delayed_ip_address_configuration": "Delayed IP Address Configuration",
    "delayed_kerberos_auth": "Delayed Kerberos Auth",
    "delayed_kerberos_data_transfer": "Delayed Kerberos Data Transfer",
    "delayed_ldap_auth": "Delayed LDAP Auth",
    "delayed_ldap_data_transfer": "Delayed LDAP Data Transfer",
    "delayed_memcache_data_transfer": "Delayed Memcache Data Transfer",
    "delayed_redis_data_transfer": "Delayed Redis Data Transfer",
    "delayed_web_services": "Delayed Web Services",
    "delayed_wifi_auth": "Delayed WiFi Auth",
    "dhcp_decline_error": "DHCP Decline Error",
    "dhcp_errors": "DHCP Errors",
    "dhcp_issues": "DHCP Issues",
    "dhcp_restart_error": "DHCP Restart Error",
    "dns_brute_force": "DNS Brute Force",
    "dns_errors": "DNS Errors",
    "dns_internal_reverse_lookup_scan": "DNS Internal Reverse Lookup Scan",
    "dns_issues": "DNS Issues",
    "dns_lookup_failures": "DNS Lookup Failures",
    "dns_rebind": "DNS Rebinding",
    "dns_request_timeouts": "DNS Request Timeouts",
    "dns_timeouts": "DNS Timeouts",
    "dns_tunnel": "DNS Tunnel",
    "dns_zone_transfer": "DNS Zone Transfer",
    "domain_fronting": "Domain Fronting",
    "domain_generation_algorithm": "Domain Generation Algorithm",
    "domain_generation_algorithm_resolved": "DGA Domain Resolution",
    "domain_generation_algorithm_unresolved": "DGA Domain Queries",
    "domain_trust_enumeration": "Domain Trust Enumeration",
    "domain_trusts_enumeration": "Domain Trusts Enumeration",
    "doublepulsar_rdp_implant": "DoublePulsar RDP Implant",
    "doublepulsar_rdp_scan": "DoublePulsar RDP Scan",
    "doublepulsar_smb_implant": "DoublePulsar SMB/CIFS Implant Activity",
    "doublepulsar_smb_scan": "DoublePulsar SMB/CIFS Scan",
    "email_errors": "Email Errors",
    "email_issues": "Email Issues",
    "email_mailbox_unavailable_error": "Email Mailbox Unavailable Error",
    "email_service_unavailable_error": "Email Service Unavailable Error",
    "empire_c2_http": "Empire C&C HTTP Connection",
    "empire_c2_tls": "Empire C&C SSL/TLS Connection",
    "eternalblue_exploit": "EternalBlue Exploit",
    "excessive_ip_fragmentation": "Overlapping IP Fragmentation",
    "experimental": "Experimental Detection",
    "experimentalMetric": "Experimental Detection for Protocol Activity",
    "experimentalMetricAnomaly": "Experimental Detection for a Single Metric",
    "experimentalSource": "Experimental Detection for a Single Source",
    "expired_cert": "Expired SSL Server Certificates",
    "external_db_req": "Request to External Database Server",
    "external_exec_file_download": "Unusual Executable File Download",
    "external_ldap_req": "Request to External LDAP Server",
    "external_nfs_req": "Request to External NFS Server",
    "external_ssh_new_device": "New SSH Device",
    "file_access_failure": "File Access Failure",
    "ftp_access_denied_error": "FTP Access Denied Error",
    "ftp_bad_syntax_error": "FTP Bad Syntax Error",
    "ftp_brute_force": "FTP Brute Force",
    "ftp_errors": "FTP Errors",
    "ftp_file_transfer_issues": "FTP File Transfer Issues",
    "ftp_not_logged_in_error": "FTP Not Logged in Error",
    "hacking_tools": "Hacking Tool Domain Access",
    "high_citrix_latency": "High Citrix Latency",
    "http_400_status_codes": "HTTP 400 Status Codes",
    "http_bad_requests": "HTTP Bad Requests",
    "http_desync_attack": "HTTP Desync Attack",
    "http_errors": "HTTP Errors",
    "http_forbidden": "HTTP Forbidden",
    "http_gateway_timeout_error": "HTTP Gateway Timeout Error",
    "http_internal_error": "HTTP Internal Error",
    "http_method_scan": "HTTP Method Scan",
    "http_not_found": "HTTP Not Found",
    "http_path_traversal": "HTTP Path Traversal",
    "http_plaintext_password_client": "Credentials Sent over HTTP",
    "http_plaintext_password_server": "Credentials Received over HTTP",
    "http_service_unavailable_error": "HTTP Service Unavailable Error",
    "icmp_tunnel": "ICMP Tunnel",
    "inbound_cobalt_strike_connection": "Inbound Connection from a Cobalt Strike IP Address",
    "inbound_tor_connection": "Inbound Tor Node Connections",
    "interactive_traffic_remote_desktop": "Unusual Interactive Traffic from a Remote Desktop",
    "interactive_traffic_shell": "Unusual Interactive Traffic from an External Endpoint",
    "interactive_traffic_ssh": "Remote Control SSH Traffic",
    "interrupted_citrix_data_transfer": "Interrupted Citrix Data Transfer",
    "kali_ssh_server_key": "Default Kali Linux SSH Keys",
    "kaseya_ml": "REvil C&C Activity (Kaseya Supply Chain)",
    "kaseya_ml_ip": "REvil Suspicious Connection (Kaseya Supply Chain)",
    "kaseya_vsa": "Kaseya VSA Activity",
    "kerberos_attack_tool_activity": "Kerberos Attack Tool Activity",
    "kerberos_auth_errors": "Kerberos Auth Errors",
    "kerberos_auth_issues": "Kerberos Auth Issues",
    "kerberos_brute_force": "Kerberos Brute Force",
    "kerberos_duplicate_sessions_errors": "Kerberos Duplicate Sessions Errors",
    "kerberos_expired_password_errors": "Kerberos Expired Password Errors",
    "kerberos_golden_ticket_attack": "Kerberos Golden Ticket Attack",
    "kerberos_invalid_ticket_errors": "Kerberos Invalid Ticket Errors",
    "kerberos_policy_errors": "Kerberos Policy Errors",
    "kerberos_revoked_credentials_errors": "Kerberos Revoked Credentials Errors",
    "kerberos_service_unknown_errors": "Kerberos Service Unknown Errors",
    "kerberos_silver_ticket_attack": "Kerberos Silver Ticket Attack",
    "kerberos_sync_errors": "Kerberos Sync Errors",
    "kerberos_ticket_errors": "Kerberos Ticket Errors",
    "kerberos_unknown_service_errors": "Kerberos Unknown Service Errors",
    "kerberos_user_enumeration": "Kerberos User Enumeration",
    "kerberos_wrong_password_errors": "Kerberos Wrong Password Errors",
    "ldap_all_workstation_enum": "Domain Workstation Enumeration",
    "ldap_as_rep_activity": "AS-REP Roasting Activity",
    "ldap_auth_error": "LDAP Auth Error",
    "ldap_auth_errors": "LDAP Auth Errors",
    "ldap_auth_issues": "LDAP Auth Issues",
    "ldap_client_any_attribute_enum": "LDAP Wildcard Query",
    "ldap_computer_enum": "LDAP Computer Enumeration",
    "ldap_gpo_enumeration": "LDAP GPO Enumeration",
    "ldap_invalid_credentials_error": "LDAP Invalid Credentials Error",
    "ldap_object_enum": "All Object Enumeration",
    "ldap_operational_error": "LDAP Operational Error",
    "ldap_protocol_error": "LDAP Protocol Error",
    "ldap_spn_scan": "LDAP SPN Scan",
    "llmnr_poisoning": "LLMNR Poisoning",
    "local_admin_enumeration": "Windows Account Enumeration",
    "memcache_errors": "Memcache Errors",
    "memcache_issues": "Memcache Issues",
    "meterpreter_shell": "Meterpreter C&C Session",
    "ms_exchange_ssrf_rce": "Microsoft Exchange Server SSRF and RCE Exploit",
    "msf_cert": "Metasploit C&C SSL/TLS Connection",
    "msrpc_admin_access_check": "Unusual Remote Admin Connection Requests",
    "msrpc_alias_member_enum": "Alias Member Enumeration",
    "msrpc_domain_controller_enumeration": "Domain Controller Enumeration",
    "msrpc_group_member_enum": "Group Member Enumeration",
    "msrpc_loggedon_user_enum": "Logged-On User Enumeration",
    "msrpc_netsession_enum": "User Session Enumeration",
    "msrpc_network_share_enum": "Network Share Enumeration",
    "msrpc_rdp_session_enum": "RDP Session Enumeration",
    "msrpc_registry_enumeration_via_winreg": "Windows Registry Enumeration",
    "msrpc_scheduled_task_via_atsvc": "Scheduled Task Activity (ATSVC)",
    "msrpc_scheduled_task_via_ITaskSchedulerService": "Scheduled Task Activity (ITaskSchedulerService)",
    "multiple_email_errors": "Multiple Email Errors",
    "multiple_ftp_errors": "Multiple FTP Errors",
    "multiple_kerberos_auth_errors": "Multiple Kerberos Authentication Errors",
    "multiple_ldap_auth_errors": "Multiple LDAP Auth Errors",
    "multiple_smb_cifs_errors": "Multiple SMB/CIFS Errors",
    "nbt_ns_poisoning": "NBT-NS Poisoning",
    "network_privilege_escalation": "Network Privilege Escalation",
    "new_adws_activity": "New Active Directory Web Service (ADWS) Activity",
    "new_dhcp_activity": "New DHCP Activity",
    "new_doh_activity": "New DNS over HTTPS (DoH) Activity",
    "new_external_connection": "New External Connection",
    "new_external_db_connection": "New External Database Connection",
    "new_external_iiop_connection": "New External IIOP Connection",
    "new_external_ldap_connection": "New External LDAP Connection",
    "new_external_nfs_connection": "New External NFS Connection",
    "new_external_rdp_connection": "New External RDP Connection",
    "new_external_rmi_connection": "New External Java RMI Connection",
    "new_external_ssh_connection": "New External SSH Connection",
    "new_external_telnet_connection": "New External Telnet Connection",
    "new_external_vnc_connection": "New External VNC Connection",
    "new_iot_connection": "New External IoT Connection",
    "new_local_dns_server": "New Local DNS Server Activity",
    "new_smb_cifs_file_transfer": "New SMB/CIFS Executable File Transfer",
    "new_telnet_activity": "New Telnet Activity",
    "nfs_file_access_failure": "NFS File Access Failure",
    "ntlm_relay": "NTLM Relay Attack",
    "ntlmv1_authentication": "NTLMv1 Authentication",
    "numerous_emails": "Numerous Emails",
    "onepercent_ml": "Confirmed OnePercent Group Ransomware IOC",
    "outbound_cobalt_strike_connection": "Outbound Connection to a Cobalt Strike IP Address",
    "outbound_socks_connection": "New Outbound SOCKS Connection",
    "outbound_tor_connection": "Outbound Tor Node Connections",
    "overwhelmed_citrix_data_transfer": "Overwhelmed Citrix Data Transfer",
    "overwhelmed_database_data_transfer": "Overwhelmed Database Data Transfer",
    "overwhelmed_data_transfer": "Overwhelmed Data Transfer",
    "overwhelmed_email_data_transfer": "Overwhelmed Email Data Transfer",
    "overwhelmed_ftp_data_transfer": "Overwhelmed FTP Data Transfer",
    "overwhelmed_http_data_transfer": "Overwhelmed HTTP Data Transfer",
    "overwhelmed_kerberos_data_transfer": "Overwhelmed Kerberos Data Transfer",
    "overwhelmed_ldap_data_transfer": "Overwhelmed LDAP Data Transfer",
    "overwhelmed_memcache_data_transfer": "Overwhelmed Memcache Data Transfer",
    "overwhelmed_redis_data_transfer": "Overwhelmed Redis Data Transfer",
    "ping_scan": "Ping Scan",
    "poor_aaa_performance": "Poor AAA Performance",
    "poor_dhcp_performance": "Poor DHCP Performance",
    "poor_http_performance": "Poor HTTP Performance",
    "potential_covert_channel": "HTTP Tunnel",
    "psexec_activity": "Remote Service Launch",
    "ransomware_activity": "Ransomware Activity",
    "rare_database_table_access": "Rare Database Table Access",
    "rare_ssh_port": "Rare SSH Port",
    "rdp_brute_force": "RDP Brute Force",
    "rdp_unusual_location": "Inbound Remote Desktop Traffic from an Unusual Location",
    "redis_errors": "Redis Errors",
    "redis_issues": "Redis Issues",
    "remote_reg_setvalue": "Remote Registry Modification",
    "reverse_ssh_connection": "Reverse SSH Connection",
    "rfb_brute_force": "VNC Brute Force",
    "ripple20_dns_rce": "CVE-2020-11901 Ripple20 Exploit Attempt",
    "ripple20_icmp_scan": "Ripple20 ICMP Scan",
    "ripple20_icmp_treck": "Treck TCP/IP Network Stack Detected",
    "ripple20_ip_in_ip": "Ripple20 IP in IP Exploit Attempt",
    "ripple20_ip_in_ip_ipaddr": "Ripple20 IP in IP Exploit Attempt",
    "rpc_log_deletion_srv": "Remote Log Deletion",
    "rpc_remote_shutdown": "Remote System Shutdown",
    "samr_domain_admin_enum": "Domain Admin Enumeration",
    "samr_domain_computer_enum": "Domain Workstation Enumeration",
    "samr_domain_group_enum": "Domain Group Enumeration",
    "samr_domain_user_enum": "Domain User Enumeration",
    "samr_domain_workstation_enum": "Domain Workstation Enumeration",
    "samr_local_admin_enum": "Local Admin Enumeration",
    "samr_local_user_enum": "Local User Enumeration",
    "scheduled_task_enumeration": "Scheduled Task Enumeration",
    "sensitive_data_transfer": "Unusual Sensitive Data Transfer",
    "shellshock_dhcp": "Shellshock DHCP Exploit Attempt",
    "shellshock_http": "Shellshock HTTP Exploit Attempt",
    "sip_brute_force": "SIP Brute Force",
    "smb_autostart_path": "File Transfer to Windows Autostart Path",
    "smb_cifs_access_denied_errors": "SMB/CIFS Access Denied Errors",
    "smb_cifs_brute_force": "SMB/CIFS Brute Force",
    "smb_cifs_errors": "SMB/CIFS Errors",
    "smb_cifs_file_access_failure": "SMB/CIFS File Access Failure",
    "smb_cifs_privileged_pipe": "SMB/CIFS Privileged Pipe",
    "smb_cifs_share_enumeration": "SMB/CIFS Share Enumeration",
    "smb_cifs_valid_login_errors": "SMB/CIFS Account Errors",
    "smb_named_pipe_beaconing": "SMB/CIFS Named Pipe Beaconing",
    "smtp_helo_ehlo_buffer_overflow": "Unusual Email Domain Length",
    "smtp_processing_spike": "Poor SMTP Server Performance",
    "smtp_syntax_error": "SMTP Syntax Error",
    "spike_in_email_traffic_volume": "Spike in Email Traffic Volume",
    "spike_in_ldap_requests": "Spike in LDAP Requests",
    "spike_in_rdp_sessions": "Spike in RDP Sessions",
    "spike_in_rfb_sessions": "Spike in VNC Sessions",
    "spike_in_round_trip_time": "Transaction Delays",
    "spike_in_ssh_sessions": "Spike in SSH Sessions",
    "spike_in_telnet_connections": "Spike in Telnet Connections",
    "spoofed_self_signed_ssl_certificate": "Spoofed SSL/TLS Certificate",
    "spring4shell": "CVE-2022-22965 Spring4Shell Exploit Attempt",
    "sqli_attack": "SQL Injection (SQLi) Attack",
    "ssh_brute_force": "SSH Brute Force",
    "ssh_unusual_location": "Inbound SSH Traffic from an Unusual Location",
    "ssh_unusual_location_c2": "Outbound SSH Traffic to an Unusual Location",
    "ssl_scan": "SSL Scan",
    "stalled_data_transfer": "Stalled Data Transfer",
    "sudden_decrease_in_application_bandwidth": "Sudden Decrease in Application Bandwidth",
    "sudden_decrease_in_device_bandwidth": "Sudden Decrease in Device Bandwidth",
    "sudden_decrease_in_network_bandwidth": "Sudden Decrease in Network Bandwidth",
    "sunburst": "SUNBURST C&C Activity",
    "supernova_web_shell_command": "SUPERNOVA Web Shell",
    "suspicious_cifs": "Suspicious SMB/CIFS Resource Accessed",
    "suspicious_file_download_external": "Suspicious External File Download",
    "suspicious_file_download_internal": "Suspicious Internal File Download",
    "suspicious_ftp_data_reads": "FTP Data Staging",
    "suspicious_ftp_download": "Suspicious FTP Download",
    "suspicious_hta_download": "Unusual HTML Application (HTA) File Download",
    "suspicious_http_file": "Suspicious HTTP File Received",
    "suspicious_http_port": "Non-standard HTTP Port",
    "suspicious_ja3_fingerprint": "Suspicious JA3 Fingerprint",
    "suspicious_new_device": "Suspicious New Device Detected",
    "suspicious_nfs_data_reads": "NFS Data Staging",
    "suspicious_nfs_file_reads": "Suspicious NFS File Reads",
    "suspicious_nfs_file_share_access": "Suspicious NFS File Share Access",
    "suspicious_rdp_client": "RDP Attack Tool Activity",
    "suspicious_smb_cifs_data_reads": "SMB/CIFS Data Staging",
    "suspicious_smb_cifs_file_reads": "Suspicious SMB/CIFS File Reads",
    "suspicious_smb_cifs_file_share_access": "Suspicious SMB/CIFS File Share Access",
    "suspicious_smb_cifs_file_transfer": "Unusual SMB/CIFS Executable File Transfer",
    "suspicious_smb_named_pipe": "Suspicious SMB/CIFS Named Pipe",
    "suspicious_tld": "Suspicious Top-level Domain",
    "suspicious_user_agent": "Suspicious User Agent",
    "tcp_null_fin_or_xmas_scan": "TCP NULL, FIN, or XMAS Scan",
    "tcp_syn_scan": "TCP SYN Scan",
    "tcp_urg_flag_client": "TCP Stack Exploit Attempt (Client)",
    "tcp_urg_flag_server": "TCP Stack Exploit Attempt (Server)",
    "telnet_password": "Telnet Password",
    "ti_dns_host": "DNS Client Request to a Suspicious Host",
    "ti_http_host": "HTTP Client Request to a Suspicious Host",
    "ti_http_uri": "HTTP Client Request to a Suspicious URI",
    "ti_ssl_sni": "SSL/TLS Connection to a Suspicious Host",
    "ti_tcp_incoming": "Inbound Suspicious Connections",
    "ti_tcp_outgoing": "Outbound Suspicious Connection",
    "tomcat_jsp_upload": "Apache Tomcat JSP Exploit Attempt",
    "udp_port_scan": "UDP Port Scan",
    "unapproved_saas": "Unapproved Cloud Service Access",
    "unauthorized_caller_error": "Unauthorized Caller Error",
    "unconventional_data_transfer": "Unconventional Data Transfer",
    "unconventional_new_external_host": "Unconventional External Connection",
    "unconventional_new_internal_host": "Unconventional Internal Connection",
    "unconventional_new_protocol": "Unconventional Protocol Communication",
    "unconventional_rdp_behavior": "Unconventional RDP Behavior",
    "unconventional_rdp_data_transfer": "Unconventional RDP Data Transfer",
    "unconventional_rfb_behavior": "Unconventional VNC Behavior",
    "unconventional_rfb_data_transfer": "Unconventional VNC Data Transfer",
    "unconventional_smb_cifs_data_transfer": "Unconventional SMB/CIFS Data Transfer",
    "unconventional_ssh_behavior": "Unconventional SSH Behavior",
    "unconventional_ssh_data_transfer": "Unconventional SSH Data Transfer",
    "unconventional_telnet_data_transfer": "Unconventional Telnet Data Transfer",
    "unencrypted_zoom": "Unencrypted Zoom Data",
    "unexpected_dropped_connections": "Unexpected Dropped Connections",
    "unexpected_service_access": "Unexpected Service Access",
    "unknown_public_dns_server": "Unknown Public DNS Server",
    "unknown_s3_bucket_upload": "Data Exfiltration to Unknown S3 Bucket",
    "unsafe_ldap_auth": "Unsafe LDAP Authentication",
    "unusual_iot_protocol": "Unusual IoT Protocol Activity",
    "unusual_kerberos_fingerprint": "Unusual Kerberos Fingerprint",
    "unusual_protocol_for_enterprise_software": "Unusual Protocol for Enterprise Software",
    "unusual_s3_download": "Unusual Download from S3 Bucket",
    "unusual_user_login_time": "Unusual Login Time",
    "vnc_unusual_location": "Inbound VNC Traffic from an Unusual Location",
    "voip_call_failure": "VoIP Call Failure",
    "voip_unavailability_error": "VoIP Unavailability Error",
    "vpn_gateway_unusual_location": "VPN Gateway Access from an Unusual Location",
    "weak_cipher": "Weak Cipher Suites",
    "weak_kerberos_encryption_attempt": "Weak Kerberos Encryption",
    "web_directory_scan": "Web Directory Scan",
    "web_issues": "Web Issues",
    "weblogic_admin_console_handle_rce": "Oracle WebLogic Administration Console Exploit Attempt",
    "weblogic_xml_deserialization": "Oracle WebLogic Deserialization Exploit Attempt",
    "web_service_issues": "Web Service Issues",
    "wifi_auth_issues": "WiFi Auth Issues",
    "wmi_activity": "New WMI Method Launch",
    "wmi_create_process": "New WMI Process Creation",
    "wmi_enumeration_query": "New WMI Enumeration Query",
    "wordpress_brute_force": "WordPress Brute Force",
    "wsman_activity": "PowerShell Remoting Activity",
    "xss_attack": "Cross-Site Scripting (XSS) Attack"
}

workflow.addProperty("category_map", CATEGORY_MAP)
workflow.addProperty("type_map", TYPE_MAP)


if rule.properties.extrahop_detection_id:
    workflow.addProperty("det_id_set", {})


Script - ExtraHop script: device property helper

Set ExtraHop device properties as workflow property dicts.

Object: incident

Script Text:

##  ExtraHop - scr_extrahop_device_property_helper script ##
# Used to share data with other workflows.
if rule.properties.extrahop_device_id:
    workflow.addProperty("dev_id_set", {})


Data Table - ExtraHop Activitymaps

screenshot: dt-extrahop-activitymaps

API Name:

extrahop_activitymaps

Columns:

Column Name API Access Name Type Tooltip
Description ams_description text -
ID ams_id text -
Mod time mod_time text -
Mode mode text -
Name ams_name text -
Owner owner text -
Query execution date query_execution_date text -
Rights rights text -
Short code short_code text -
Show alert status show_alert_status text -
Walks walks textarea -
Weighting weighting text -

Data Table - Extrahop Detections

screenshot: dt-extrahop-detections screenshot: dt-extrahop-detections_2 screenshot: dt-extrahop-detections_3

API Name:

extrahop_detections

Columns:

Column Name API Access Name Type Tooltip
Appliance ID appliance_id text -
Assignee assignee text -
Categories categories text -
Description det_description text -
Detection URL detection_url textarea -
End time end_time datetimepicker -
ID det_id text -
Is user created is_user_created text -
Mitre tactics mitre_tactics textarea -
Mitre techniques mitre_techniques textarea -
Participants participants textarea -
Properties properties textarea -
Query execution date query_execution_date text -
Resolution resolution text -
Risk score risk_score text -
Start time start_time datetimepicker -
Status status text -
Ticket ID ticket_id text -
Ticket URL ticket_url textarea -
Title title text -
Type type text -
Update time update_time datetimepicker -

Data Table - ExtraHop Devices

screenshot: dt-extrahop-devices screenshot: dt-extrahop-devices_2

API Name:

extrahop_devices

Columns:

Column Name API Access Name Type Tooltip
Activity activity text -
Default name default_name text -
Description devs_description text -
Device URL device_url textarea Linkback to device on ExtraHop.
Discovery time discover_time datetimepicker -
Display name display_name text -
DNS name dns_name text -
ExtraHop ID extrahop_id text ExtraHop Discovery ID
ID devs_id number REST API ID
IPaddr4 ipaddr4 text -
IPaddr6 ipaddr6 text -
Last seen time last_seen_time datetimepicker -
MACaddr macaddr text -
Modification time mod_time datetimepicker -
On watchlist on_watchlist text -
Query execution date query_execution_date text -
Role role text -
User modification time user_mod_time datetimepicker -
Vendor vendor text -

Data Table - Extrahop Tags

screenshot: dt-extrahop-tags

API Name:

extrahop_tags

Columns:

Column Name API Access Name Type Tooltip
ID tag_id text Tag ID
Mod time mod_time datetimepicker Tag modification time
Query execution date query_execution_date text -
Tag tag text Tag name

Data Table - ExtraHop Watchlist

screenshot: dt-extrahop-watchlist

API Name:

extrahop_watchlist

Columns:

Column Name API Access Name Type Tooltip
Display name display_name text -
ExtraHop ID extrahop_id text -
IPaddr4 ipaddr4 text -
IPaddr6 ipaddr6 text -
MACaddr macaddr text -
Query execution date query_execution_date text -

Custom Fields

Label API Access Name Type Prefix Placeholder Tooltip
Extrahop Assignee extrahop_assignee text properties - -
Extrahop console URL extrahop_console_url text properties - ExtraHop base console url.
Extrahop Detection ID extrahop_detection_id number properties - Extrahop detecion ID.
Extrahop Detection Link extrahop_detection_link textarea properties - Link back to ExtraHop detection
Extrahop Detection Updated extrahop_detection_updated datetimepicker properties - Field to indicate detection has been updated
Extrahop End Time extrahop_end_time datetimepicker properties - -
Extrahop Risk Score extrahop_risk_score number properties - -
Extrahop site name extrahop_site_name text properties - The name of the ExtraHop appliance.
Extrahop site UUID extrahop_site_uuid text properties - The uuidof the ExtraHop appliance.
Extrahop Status extrahop_status text properties - -
Extrahop Ticket ID extrahop_ticket_id text properties - -
ExtraHop Update Notification extrahop_update_notification textarea properties - -
ExtraHop Update Time extrahop_update_time datetimepicker properties - -

Rules

Rule Name Object Workflow Triggered
Example: Extrahop Reveal(x) add artifact extrahop_devices wf_extrahop_rx_add_artifact
Example: Extrahop Reveal(x) assign tag extrahop_devices wf_extrahop_rx_assign_tag
Example: Extrahop Reveal(x) create tag incident wf_extrahop_rx_create_tag
Example: Extrahop Reveal(x) get activitymaps incident wf_extrahop_rx_get_activitymaps
Example: Extrahop Reveal(x) get tags incident wf_extrahop_rx_get_tags
Example: Extrahop Reveal(x) get watchlist incident wf_extrahop_rx_get_watchlist
Example: Extrahop Reveal(x) refresh incident incident wf_extrahop_rx_refresh_incident
Example: Extrahop Reveal(x) search detections incident wf_extrahop_rx_search_detections
Example: Extrahop Reveal(x) search devices incident wf_extrahop_rx_search_devices
Example: Extrahop Reveal(x) search packets artifact wf_extrahop_rx_search_packets
Example: Extrahop Reveal(x) update detection incident wf_extrahop_rx_update_detection
Example: Extrahop Reveal(x) update incident incident wf_extrahop_rx_update_incident
Example: Extrahop Reveal(x) update watchlist extrahop_devices wf_extrahop_rx_update_watchlist

Troubleshooting & Support

Refer to the documentation listed in the Requirements section for troubleshooting information.

For Support

This is an IBM supported app. Please search ibm.com/mysupport for assistance.