SCADAfence CNM

fetching data from CNM.

Network Security · SCADAfence CNM

Details

IDSCADAfence CNM
ProviderRapid7
CategoryNetwork Security
From Version5.0.0
Docker Imagedemisto/python3:3.12.12.7090913
Supported ModulesAgentix XSIAM

README

Overview


Use the SCADAfence integration to manage alerts and assets.

This integration was integrated and tested with SCADAfence CNM v.

 

Use cases


  1. Fetch alerts from SCADAfence

 

Configure the SCADAfence CNM Integration on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for SCADAfence CNM.
  3. Click _Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • API auth secret
    • API auth key
    • API url
    • Trust any certificate (not secure)
    • Fetch incidents
    • Incident type
    • Required severity levels for alerts separated by comma, from [Information,Warning,Threat,Severe,Critical]. For ex.: Warning, Threat
  4. Click Test to validate the URLs, token, and connection.

 

Fetched Incidents Data


[
    {
        "createdOn": "2018-08-05T12:06:22.278Z",
        "details": "1.1.1.1 sent suspicious write command to PLC 2.2.2.2.",
        "id": "5b600cecfeb8001f1cc5d2ea",
        "ip": "2.2.2.2",
        "severity": "Critical",
        "status": "InProgress",
        "type": "Suspicious write command to PLC"
    }
]

 

Commands


You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

  1. Query alert data: scadafence-getAlerts
  2. Get asset data: scadafence-getAsset
  3. Set the status of an alert: scadafence-setAlertStatus
  4. Get asset connection data: scadafence-getAssetConnections
  5. Get asset network activity data: scadafence-getAssetTraffic
  6. Create an alert: scadafence-createAlert
  7. Get all connections: scadafence-getAllConnections

1. Query alert data


Queries alerts data from SCADAfence CNM.

Base Command
scadafence-getAlerts
Input
Argument Name Description Required
severity Required severity level of alert Optional
ipAddress IP address to get alerts for Optional
 
Context Output
[
    {
        "createdOn": "2018-08-05T12:06:22.278Z",
        "details": "140.80.0.101 sent suspicious write command to PLC 2.2.2.2.",
        "id": "5b600cecfeb8001f1cc5d2ea",
        "ip": "2.2.2.2",
        "severity": "Critical",
        "status": "Resolved",
        "type": "Suspicious write command to PLC"
    }
]
Path Type Description
SCADAfence.Alert.id string Alert ID
SCADAfence.Alert.ip string Asset IP
SCADAfence.Alert.severity string Alert severity level
SCADAfence.Alert.type string Short description of the alert
SCADAfence.Alert.details string Extended description of the alert
 
Command Example
!scadafence-getAlerts severity=Critical
Human Readable Output

Alerts are:

status severity ip createdOn details type id
Resolved Critical 2.2.2.2 2018-08-05T12:06:22.278Z 140.80.0.101 sent suspicious write command to PLC 2.2.2.2. Suspicious write command to PLC 5b600cecfeb8001f1cc5d2ea

 

2. Get asset data


Fetches asset data from SCADAfence CNM.

Base Command
scadafence-getAsset
Input
Argument Name Description Required
ipAddress Asset IP address Optional
hostName Hostname Optional
assetType Asset type (from list of options) Optional
 
Context Output
Path Type Description
SCADAfence.Asset.ip string IP address of the suspicious asset
 
Command Example

!scadafence-getAsset ip=10.10.10.10

Context Example
[
    {
        "assetTypes": "hmi, server",
        "eventsCount": 0,
        "externalIpsCount": 0,
        "firstSeen": "2016-05-23T12:25:03.838Z",
        "hostname": "wmhtp25",
        "internalIpsCount": 13,
        "ip": "3.3.3.3",
        "lastSeen": "2016-05-23T12:25:03.838Z",
        "mac": "E8:39:35:BD:24:76",
        "nicType": "Ethernet",
        "operatingSystem": "Windows Server 2008 R2",
        "totalBytes": 0,
        "vendor": "Hewlett-Packard Company"
    }
]
Path Type Description
SCADAfence.Asset.ip string IP address of the suspicious asset
 
Command Example
scadafence-getAsset ip=10.10.10.10
Human Readable Output

Asset details:

assetTypes eventsCount vendor ip externalIpsCount hostname nicType mac lastSeen totalBytes internalIpsCount operatingSystem firstSeen
hmi, server 0 Hewlett-Packard Company 3.3.3.3 0 wmhtp25 Ethernet E8:39:35:BD:24:76 2016-05-23T12:25:03.838Z 0 13 Windows Server 2008 R2 2016-05-23T12:25:03.838Z

 

3. Set the status of an alert


Sets the status of a specified alert.

Base Command
scadafence-setAlertStatus
Input
Argument Name Description Required
alertId Alert ID Required
alertStatus Alert status Required
 
Context Output

Setting status for alert 5bcf0e1a106e0c000f5448b6 to 'Resolved':

success
true
 
Command Example
!scadafence-setAlertStatus alertId=5b600cecfeb8001f1cc5d2ea alertStatus=InProgress
Human Readable Output

Setting status for alert 5bcf0e1a106e0c000f5448b6 to 'Resolved':

success
true
 

4. Get asset connection data


Fetches asset connections data according to one or more parameters.

Base Command
scadafence-getAssetConnections
Input
Argument Name Description Required
ipAddress IP address of the asset Optional
hostName Hostname that corresponds to the asset of interest Optional
macAddress MAC address of the asset Optional
 
Context Output
[
    {
        "dir": "DEST",
        "hostname": "",
        "ip": "1.1.1.1",
        "mac": "08:00:06:01:00:02",
        "port": null,
        "proto": "TCP",
        "traffic": 9691680
    },
    {
        "dir": "DEST",
        "hostname": "t20102173",
        "ip": "2.2.2.2",
        "mac": "00:80:80:8E:8F:F0",
        "port": null,
        "proto": "TCP",
        "traffic": 101410609
    },
    {
        "dir": "SRC",
        "hostname": "",
        "ip": "3.3.3.3",
        "mac": "",
        "port": null,
        "proto": "UDP",
        "traffic": 24768
    },
    {
        "dir": "SRC",
        "hostname": "",
        "ip": "4.4.4.4",
        "mac": "",
        "port": 5355,
        "proto": "UDP",
        "traffic": 816
    }
]
Path Type Description
SCADAfence.Asset.Conn.ip string Another endpoint's IP address
SCADAfence.Asset.Conn.port number Another endpoint's port
SCADAfence.Asset.Conn.protocol string Protocol used for the connection
SCADAfence.Asset.Conn.traffic number Total bytes sent (both directions)
SCADAfence.Asset.Conn.hostname string Another endpoint's hostname
SCADAfence.Asset.Conn.mac string Another endpoint's MAC address
 
Command Example
!scadafence-getAssetConnections ipAddress=3.3.3.3
Context Example
[
    {
        "dir": "DEST",
        "hostname": "",
        "ip": "1.1.1.1",
        "mac": "08:00:06:01:00:02",
        "port": null,
        "proto": "TCP",
        "traffic": 9691680
    },
    {
        "dir": "DEST",
        "hostname": "t20102173",
        "ip": "2.2.2.2",
        "mac": "00:80:80:8E:8F:F0",
        "port": null,
        "proto": "TCP",
        "traffic": 101410609
    },
    {
        "dir": "SRC",
        "hostname": "",
        "ip": "3.3.3.3",
        "mac": "",
        "port": null,
        "proto": "UDP",
        "traffic": 24768
    },
    {
        "dir": "SRC",
        "hostname": "",
        "ip": "4.4.4.4",
        "mac": "",
        "port": 5355,
        "proto": "UDP",
        "traffic": 816
    }
]
Human Readable Output

Asset connections:

proto ip hostname mac traffic port dir
TCP 1.1.1.1   08:00:06:01:00:02 9691680   DEST
TCP 2.2.2.2 t20102173 00:80:80:8E:8F:F0 101410609   DEST
UDP 3.3.3.3     24768   SRC
UDP 4.4.4.4     816 5355 SRC

 

5. Get asset network activity data


Fetches asset network activity data according to one or more parameters.

Base Command
scadafence-getAssetTraffic
Input
Argument Name Description Required
ipAddress IP address of the asset Optional
macAddress MAC address of the asset Optional
hostName Hostname of the asset Optional
 
 
Context Output
{
    "TCP": {
        "Bytes received": 447191388,
        "Bytes sent": 100766536
    },
    "UDP": {
        "Bytes received": 0,
        "Bytes sent": 27560
    }
}
Path Type Description
SCADAfence.AssetTraffic.TCP_tx_bytes number Bytes sent by the asset via TCP
SCADAfence.AssetTraffic.TCP_rx_bytes number Bytes received by the asset via TCP
SCADAfence.AssetTraffic.UDP_tx_bytes number Bytes sent by the asset via UDP
SCADAfence.AssetTraffic.UDP_rx_bytes number Bytes received by the asset via UDP
 
Command Example
!scadafence-getAssetTraffic ipAddress=3.3.3.3
Context Example
{
    "TCP": {
        "Bytes received": 447191388,
        "Bytes sent": 100766536
    },
    "UDP": {
        "Bytes received": 0,
        "Bytes sent": 27560
    }
}
Human Readable Output

Asset network activity:

UDP_tx_bytes TCP_rx_bytes TCP_tx_bytes UDP_rx_bytes
27560 447191388 100766536 0

 

6. Create an alert


Creates an alert in SCADAfence CNM.

Base Command

scadafence-createAlert

Input
Argument Name Description Required
ipAddress IP address of the asset that the alert is related to Required
severity Alert severity level Required
description Human readable alert description Required
remediationText Instructions for issue remediation Optional
alertIsActive Set active=True to make the alert appear in the SCADAfence UI Required
 
Context Output
Path Type Description
SCADAfence.Alert.alertCreated boolean Flag defining alert creation status
SCADAfence.Alert.id string Unique ID set to a new alert
 
Command Example
!scadafence-createAlert alertIsActive=True description=test_alert ipAddress=10.0.0.6 severity=Information remediationText="test alert"
Context Example

Create alert:

alertCreated id
true 5bcf1925a81ed3000f831578
 
Human Readable Output

Create alert:

alertCreated id
true 5bcf1925a81ed3000f831578

 

7. Get all connections


Fetches all connections from SCADAfence CNM.

Base Command
scadafence-getAllConnections
Input

There is no input for this command.

Context Output
Path Type Description
SCADAfence.Connection.src_ip string IP address of endpoint A
SCADAfence.Connection.dest_ip string IP address of endpoint B
SCADAfence.Connection.src_port number Port of endpoint A
SCADAfence.Connection.dest_port number Port of endpoint B
SCADAfence.Connection.src_mac string Endpoint A MAC address
SCADAfence.Connection.dest_mac string Endpoint B MAC address
SCADAfence.Connection.src_cname string Endpoint A hostname
SCADAfence.Connection.dest_cname string Endpoint B hostname
SCADAfence.Connection.proto string L4 protocol
SCADAfence.Connection.traffic number Total number of bytes sent (both directions)
 
Command Example
!scadafence-getAllConnections
Context Example
[
  {
    "dest_hostname": "",
    "dest_ip": "1.1.1.1",
    "dest_mac": "F4:54:33:A9:13:23",
    "dest_port": 44818,
    "proto": "TCP",
    "src_hostname": "",
    "src_ip": "4.4.4.4",
    "src_mac": "00:0C:29:65:1C:29",
    "src_port": 50153,
    "traffic": 234840
  },
  {
    "dest_hostname": "",
    "dest_ip": "2.2.2.2",
    "dest_mac": "F4:54:33:A9:0E:60",
    "dest_port": 44818,
    "proto": "TCP",
    "src_hostname": "",
    "src_ip": "3.3.3.3",
    "src_mac": "00:0C:29:65:1C:29",
    "src_port": 50154,
    "traffic": 151722
  },
  {
    "dest_hostname": "",
    "dest_ip": "4.4.4.4",
    "dest_mac": "F4:54:33:A8:33:93",
    "dest_port": 44818,
    "proto": "TCP",
    "src_hostname": "",
    "src_ip": "5.5.5.5",
    "src_mac": "00:0C:29:65:1C:29",
    "src_port": 50108,
    "traffic": 23936
  }
]

 

Human Readable Output
src_port proto dest_hostname src_hostname src_ip traffic dest_mac dest_port src_mac dest_ip
50153 TCP     1.1.1.1 234840 F4:54:33:A9:13:23 44818 00:0C:29:65:1C:29 4.4.4.4
50154 TCP     1.1.1.1 151722 F4:54:33:A9:0E:60 44818 00:0C:29:65:1C:29 1.1.1.1
50108 TCP     1.1.1.1 23936 F4:54:33:A8:33:93 44818 00:0C:29:65:1C:29 4.4.4.4

Configuration parameters

  • APISecret — API auth secret (required)
  • APIKey — API auth key (required)
  • APIUrl — API url (required)
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • AlertSeverity — Required severity levels for alerts separated by comma, from [Information,Warning,Threat,Severe,Critical]. For ex.: Warning, Threat (required)

Commands (7)

  • scadafence-createAlert

    create alert in SCADAfence CNM.

  • scadafence-getAlerts

    query alerts data from SCADAfence CNM.

  • scadafence-getAllConnections

    Fetches all connections from the CNM.

  • scadafence-getAsset

    fetch asset data from SCADAfence CNM.

  • scadafence-getAssetConnections

    fetches asset connections data by one or more (combined) parameters.

  • scadafence-getAssetTraffic

    fetch asset network activity data by one or more (combined) parameters.

  • scadafence-setAlertStatus

    setting alert status.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

""" IMPORTS """
import json
import sys
from datetime import datetime

import requests
import urllib3

# Disable insecure warnings
urllib3.disable_warnings()

""" GLOBAL VARS """
API_URL = f'{demisto.params()["APIUrl"].rstrip("/")}/externalApi'
API_KEY = demisto.params()["APIKey"]
API_SECRET = demisto.params()["APISecret"]
ALERT_SEVERITY = demisto.params()["AlertSeverity"]

USE_SSL = not demisto.params().get("insecure", False)

if not demisto.params().get("proxy", False):
    # Remove proxy environment variables if they exist
    for proxy_var in ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"]:
        os.environ.pop(proxy_var, None)

DEFAULT_HEADERS = {
    "x-api-key": API_KEY,
    "x-api-secret": API_SECRET,
    "Accept": "application/json",
    "Content-Type": "application/x-www-form-urlencoded",
}


SCADAFENCE_ALERT_SEVERITY_LEVEL = {"Information": 0, "Warning": 1, "Threat": 2, "Severe": 3, "Critical": 4}

""" HELPER FUNCTIONS """

INCIDENT_TYPES = {"IP conflict detected": "SCADAfence IP conlict"}


def get_alert_severity():
    """
    validate severity values provided as parameter
    :return: set: valid severity values
    """
    s = ALERT_SEVERITY.replace(" ", "")
    s_arr = s.split(",")
    if sum([x in ["Information", "Warning", "Threat", "Severe", "Critical"] for x in s_arr]) == len(s_arr):
        return set(s_arr)
    raise Exception("Invalid alert severity values")


def http_request(method, url_suffix, params_dict, headers):
    """

    :param method: string: https method
    :param url_suffix: string: API route
    :param params_dict: dict: request parameters
    :param headers: dict: optional http headers
    :return: dict: response data
    """
    req_params = {}
    if params_dict is not None:
        req_params.update(params_dict)

    url = f"{API_URL}{url_suffix}"

    demisto.debug(f"running {method} request with url={url}\theaders={headers}\nparams={json.dumps(req_params)}")
    res_msg = ""
    try:
        if method in ["PATCH", "POST"]:
            data = req_params
            params = None
        else:
            params = req_params
            data = None
        res = requests.request(method, url, verify=USE_SSL, data=data, params=params, headers=headers)
        if res.text:
            res_msg = res.text
        res.raise_for_status()

        if not res.text:
            return None
        return json.loads(res.text)

    except Exception as e:
        raise Exception(f"{e}\n{res_msg}")


def call_api(method, api_suffix, params):
    """
    Call the requested API path and return its result
    :param api_path: A string beginning with '/' followed by the desired service
    :rtype: dict
    :raises Exception: If the response code is not 200
    :return the response as a dict if possible, otherwise None
    """
    return http_request(method, api_suffix, params, DEFAULT_HEADERS)


def get_alerts(severity, ip, from_date):
    """
    API caller
    :param severity: string: required severity level
    :param from_date: string: lower time limit
    :return: call_api.http_request.data
    """
    api_suffix = "/alerts"
    return call_api("GET", api_suffix, {"severity": severity, "ip": ip, "from": from_date})


def fetch_incidents():
    """
    method for polling alerts from SCADAfence alerts API
    :return: list: demisto.incidents
    """
    last_run = demisto.getLastRun()

    last_updated = (datetime(1999, 1, 1, 0, 0, 0, 0), "1999-01-01T00:00:00.0Z")
    if last_run and "createdOn" in last_run:
        ts_str = last_run.get("createdOn")
        last_updated = (datetime.strptime(ts_str, "%Y-%m-%dT%H:%M:%S.%fZ"), ts_str)

    severities = get_alert_severity()

    events = []
    incidents = []
    tmp_time = last_updated

    for severity in severities:
        events = get_alerts(severity, None, last_updated[1])

        for event in events:
            event_ts = datetime.strptime(event["createdOn"], "%Y-%m-%dT%H:%M:%S.%fZ")
            if event_ts > tmp_time[0]:
                tmp_time = (event_ts, event["createdOn"])

            incident = {
                "name": event["type"],
                "occurred": event["createdOn"],
                "severity": SCADAFENCE_ALERT_SEVERITY_LEVEL[event["severity"]],
                "rawJSON": json.dumps(event),
            }
            incidents.append(incident)
    if tmp_time[0] > last_updated[0]:
        demisto.setLastRun({"createdOn": tmp_time[1]})

    demisto.incidents(incidents)


def map_optional_params(keys, api_keys):
    """
    mapping Demisto parameters to SCADAfence API parameters
    :param keys: list: expected demisto parameters
    :param api_keys: valid scadafence parameters
    :return: dict: mapped current function call parameters
    """
    params = {}
    param_keys = list(demisto.args().keys())
    for i, key in enumerate(keys):
        if key in param_keys:
            params[api_keys[i]] = demisto.args()[key]
    return params


def get_assets(asset_data):
    """
    getter for assets data by one or more parameters:
    IP, hostame, type (plc, hmi, IO, Telnel server etc)
    :param asset_data: dict
    :return: call_api.http_request.res.text
    """
    if asset_data:
        api_suffix = "/assets"
        return call_api("GET", api_suffix, asset_data)
    return_error("Invalid call for assets data (missing parameters)")
    return None


def get_asset_map(asset_details):
    """
    fetches asset connection data by one or more (combined) parameters
    :param asset_details: disct :{'ip': ip, 'host': hostname, 'mac': mac}
    :return: call_api.http_request.res.text
    """
    if asset_details:
        api_suffix = "/asset/map"
        return call_api("GET", api_suffix, asset_details)
    return_error("Invalid call for asset map (missing parameters)")
    return None


def get_assets_map():
    """
    fetches asset connection data by one or more (combined) parameters
    :param asset_details: disct :{'ip': ip, 'host': hostname, 'mac': mac}
    :return: call_api.http_request.res.text
    """
    api_suffix = "/asset/map"
    return call_api("GET", api_suffix, None)


def get_asset_traffic(asset_details):
    """
    fetches asset connection data by one or more (combined) parameters
    :param asset_details: disct :{'ip': ip, 'host': hostname, 'mac': mac}
    :return: call_api.http_request.res.text
    """
    if asset_details:
        api_suffix = "/asset/traffic"
        return call_api("GET", api_suffix, asset_details)
    return_error("Invalid call for asset traffic (missing parameters)")
    return None


def dest_endpoint(ep):
    return {
        "ip": ep["dest_ip"],
        "mac": ep["dest_mac"],
        "hostname": ep["dest_hostname"],
        "port": ep["dest_port"],
        "proto": ep["proto"],
        "traffic": ep["traffic"],
    }


def src_endpoint(ep):
    return {
        "ip": ep["src_ip"],
        "mac": ep["src_mac"],
        "hostname": ep["src_hostname"],
        "port": ep["src_port"],
        "proto": ep["proto"],
        "traffic": ep["traffic"],
    }


def get_endpoint_data(data):
    ret = []
    for ep in data:
        if "ipAddress" in list(demisto.args().keys()):
            if demisto.args()["ipAddress"] == ep["src_ip"]:
                ret.append(dest_endpoint(ep))
            else:
                ret.append(src_endpoint(ep))

        elif "macAddress" in list(demisto.args().keys()):
            if demisto.args()["macAddress"] == ep["src_mac"]:
                ret.append(dest_endpoint(ep))
            else:
                ret.append(src_endpoint(ep))

        else:
            if demisto.args()["hostName"] == ep["src_hostname"]:
                ret.append(dest_endpoint(ep))
            else:
                ret.append(src_endpoint(ep))
    return ret


if demisto.command() == "test-module":
    # This is the call made when pressing the integration test button.
    get_alerts("Critical", None, None)
    demisto.results("ok")
    sys.exit(0)

elif demisto.command() == "scadafence-createAlert":
    ip = demisto.args()["ipAddress"]
    severity = demisto.args()["severity"]
    description = demisto.args()["description"]
    active = demisto.args()["alertIsActive"]
    remediation = demisto.args()["remediationText"]

    api_suffix = "/alert"
    alert_data = {"ip": ip, "severity": severity, "details": description, "active": active, "remediation": remediation}
    data = call_api("POST", api_suffix, alert_data)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": data,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown("Create alert:", data),
            "EntryContext": {"SCADAfence.Alert": data},
        }
    )

elif demisto.command() == "scadafence-getAlerts":
    ip = None
    severity = None
    if "ipAddress" in demisto.args():
        ip = demisto.args()["ipAddress"]
    if "severity" in demisto.args():
        severity = demisto.args()["severity"]
    data = get_alerts(severity, ip, None)
    output = []
    for alert in data:
        output.append(
            {
                "status": alert["status"],
                "severity": alert["severity"],
                "ip": alert["ip"],
                "details": alert["details"],
                "id": alert["id"],
                "remediation": alert["remediation"],
            }
        )
    md = tableToMarkdown("SCADAfence alerts", output)
    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": data,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.Alert(val.id==obj.id)": output},
        }
    )

elif demisto.command() == "scadafence-setAlertStatus":
    api_suffix = f"/alerts/{demisto.args()['alertId']}"
    alert_status = demisto.args()["alertStatus"]
    call_api("PATCH", api_suffix, {"status": alert_status})
    md = tableToMarkdown(f"Setting status for alert {demisto.args()['alertId']} to '{alert_status}':", {"success": True})
    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": {"status": alert_status},
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.Alert.status": alert_status},
        }
    )


elif demisto.command() == "scadafence-getAsset":
    params = map_optional_params(["ipAddress", "hostName", "assetType"], ["ip", "host", "type"])
    data = get_assets(params)
    md = tableToMarkdown("Asset details: ", data)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": data,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.Asset(val.ip==obj.ip)": data},
        }
    )

elif demisto.command() == "scadafence-getAssetConnections":
    params = map_optional_params(["ipAddress", "macAddress", "hostName"], ["ip", "mac", "host"])
    data = get_asset_map(params)
    result = get_endpoint_data(data)
    md = tableToMarkdown("Asset connections: ", result)
    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": result,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.Asset.Conn(val.ip==obj.ip)": result},
        }
    )

elif demisto.command() == "scadafence-getAllConnections":
    data = get_assets_map()
    md = tableToMarkdown("Asset connections: ", data)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": data,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.Connection": data},
        }
    )

elif demisto.command() == "scadafence-getAssetTraffic":
    params = map_optional_params(["ipAddress", "macAddress", "hostName"], ["ip", "mac", "host"])
    data = get_asset_traffic(params)
    data_x = {
        "TCP_tx_bytes": data["TCP"]["Bytes sent"],
        "TCP_rx_bytes": data["TCP"]["Bytes received"],
        "UDP_tx_bytes": data["UDP"]["Bytes sent"],
        "UDP_rx_bytes": data["UDP"]["Bytes received"],
    }
    md = tableToMarkdown("Asset network activity: ", data_x)
    demisto.results(
        {
            "Type": entryTypes["note"],
            "Contents": data,
            "ContentsFormat": formats["json"],
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": md,
            "EntryContext": {"SCADAfence.AssetTraffic": data_x},
        }
    )

elif demisto.command() == "fetch-incidents":
    demisto.incidents(fetch_incidents())