Details
| ID | SCADAfence CNM |
|---|---|
| Provider | Rapid7 |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.12.7090913 |
| Supported Modules | Agentix XSIAM |
README
Overview
Use the SCADAfence integration to manage alerts and assets.
This integration was integrated and tested with SCADAfence CNM v.
Use cases
- Fetch alerts from SCADAfence
Configure the SCADAfence CNM Integration on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for SCADAfence CNM.
- 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
- 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.
- Query alert data: scadafence-getAlerts
- Get asset data: scadafence-getAsset
- Set the status of an alert: scadafence-setAlertStatus
- Get asset connection data: scadafence-getAssetConnections
- Get asset network activity data: scadafence-getAssetTraffic
- Create an alert: scadafence-createAlert
- 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 settingsinsecure— Trust any certificate (not secure)isFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch IntervalAlertSeverity— Required severity levels for alerts separated by comma, from [Information,Warning,Threat,Severe,Critical]. For ex.: Warning, Threat (required)
Commands (7)
-
scadafence-createAlertcreate alert in SCADAfence CNM.
-
scadafence-getAlertsquery alerts data from SCADAfence CNM.
-
scadafence-getAllConnectionsFetches all connections from the CNM.
-
scadafence-getAssetfetch asset data from SCADAfence CNM.
-
scadafence-getAssetConnectionsfetches asset connections data by one or more (combined) parameters.
-
scadafence-getAssetTrafficfetch asset network activity data by one or more (combined) parameters.
-
scadafence-setAlertStatussetting 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())