| Source | main Status |
main Timestamp |
|---|---|---|
| CISAGOV | ||
| Development |
Industrial Control Systems Network Protocol Parsers (ICSNPP) - Emerson ROC Plus
ICSNPP-ROC-PLUS is a Spicy based Zeek plugin for parsing and logging fields within the ROC Plus protocol.
ROC Plus is a protocol created by Emerson for communication between Emerson devices in industrial automation systems. It is widely used in industrial applications such as oil and gas operations.
This parser targets the ROC Plus commands specified in the publicly available 2022 version of the spec.
This script is available as a package for Zeek Package Manager. Zeek includes Spicy support by default as of v6.0.0.
$ zkg refresh
$ zkg install icsnpp-roc-plusIf this package is installed from ZKG, it will be added to the available plugins. This can be tested by running zeek -NN. If installed correctly, users will see ANALYZER_ROC_PLUS_TCP and ANALYZER_ROC_PLUS_UDP under the list of Zeek::Spicy analyzers.
If users have ZKG configured to load packages (see @load packages in the ZKG Quickstart Guide), this plugin and these scripts will automatically be loaded and ready to go.
git clone https://github.com/cisagov/icsnpp-roc-plus.git
cd icsnpp-roc-plus
mkdir build && cd build && cmake .. && make && cd ..From here you can install the locally built files through zkg install ./icsnpp-roc-plus and run it like you would normally.
Or you can manually run the parser without installing it: zeek ./build/roc_plus.hlto ./scripts/__load__.zeek -Cr <pcap>
ROC Plus detection is port-based; this package does not provide payload signatures. The standard TCP and UDP ports are both 4000. To add port 12345 through a Zeek site policy, add it to the set for each transport that should be parsed:
redef ROC_PLUS::roc_plus_ports_tcp += { 12345/tcp };
redef ROC_PLUS::roc_plus_ports_udp += { 12345/udp };ROC_PLUS::roc_plus_ports_tcp is registered with the TCP analyzer, and
ROC_PLUS::roc_plus_ports_udp is registered with the UDP analyzer. The package
also adds both sets to Zeek's likely_server_ports direction heuristic during
initialization. Adding a port only to likely_server_ports does not enable ROC
Plus parsing; the port must also be registered with the appropriate analyzer by
including it in the corresponding ROC Plus set.
As an alternative, set ZEEK_ROC_PLUS_PORTS to a comma-separated list of
transport-qualified ports before starting Zeek. Each entry is routed to the
corresponding TCP or UDP analyzer and direction heuristic:
ZEEK_ROC_PLUS_PORTS=12345/tcp,12345/udp zeek -Cr traffic.pcapThe environment variable and site policy are read when Zeek initializes, so a running standalone process or cluster must be restarted or redeployed after a change. Changing the configured ports does not require rebuilding the plugin.
Port registration assigns all traffic using the configured server port directly to the ROC Plus analyzer. Configure only ports dedicated to ROC Plus: unrelated or malformed traffic on those ports will still be presented to the analyzer and may add processing overhead or parser diagnostics before it is rejected.
The ROC Plus analyzer generates several log files based on the type of ROC Plus traffic observed.
This log file contains the core fields for all ROC Plus protocol traffic.
| Field | Type | Description |
|---|---|---|
| ts | time | Timestamp |
| uid | string | Unique identifier for the connection |
| id | conn_id | Connection identifier |
| protocol | transport_proto | Transport protocol |
| roc_plus_link_id | string | Unique identifier for the ROC Plus connection |
| packet_type | string | Type of packet (e.g., "REQUEST", "RESPONSE", "UNKNOWN") |
| destination_unit | count | Destination unit address |
| destination_group | count | Destination group address |
| source_unit | count | Source unit address |
| source_group | count | Source group address |
| opcode | string | Operation code for the ROC Plus command |
| data_length | count | Length of the following data portion in bytes (not including this byte, the CRC bytes, or the error bytes) |
| lsb_crc | count | Least significant byte of the CRC checksum |
| msb_crc | count | Most significant byte of the CRC checksum |
| error_code | vector of string | Error codes returned in the response (if any) |
| error_offset | vector of count | Offsets where errors occurred (if any) |
This log captures system configuration information for ROC Plus devices and logs it to roc_plus_sys_cfg.log.
- See the
ROC_PLUS::roc_plus_sys_cfg_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 6 (SENDS ROC800 CONFIGURATION).
This log captures the historical minimum and maximum values for points and logs it to roc_plus_historical_min_max_vals.log.
- See the
ROC_PLUS::roc_plus_historical_min_max_vals_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 105 (SENDS HISTORY POINT DEFINITION, MIN/MAX DATA, AND CURRENT VALUES).
This log captures real-time clock data and logs it to roc_plus_realtime_clock.log.
- See the
ROC_PLUS::roc_plus_realtime_clock_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcodes 7 (READ REAL-TIME CLOCK) and 8 (SET REAL-TIME CLOCK).
This log captures configurable opcode point data and logs it to roc_plus_configurable_opcode.log.
- See the
ROC_PLUS::roc_plus_configurable_opcode_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcodes 10 (READ CONFIGURABLE OPCODE POINT DATA) and 11 (WRITE CONFIGURABLE OPCODE POINT DATA).
This log captures login information and logs it to roc_plus_login.log.
- See the
ROC_PLUS::roc_plus_login_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 17 (LOGIN REQUEST).
This log captures store and forward messaging data and logs it to roc_plus_store_and_forward.log.
- See the
ROC_PLUS::roc_plus_store_and_forward_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 24 (STORE AND FORWARD MESSAGES).
This log captures various data request operations and logs it to roc_plus_data_request.log.
- See the
ROC_PLUS::roc_plus_data_request_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcodes:
- 50 (I/O DATA REQUEST)
- 108 (HISTORICAL DATABASE READ)
- 118 (READ ALARM LOG)
- 119 (READ EVENT LOG)
- 137 (READ HISTORY SETUP)
- 138 (READ HISTORY POINT INFO)
- 224 (SRBX Signal)
- 225 (SRBX Acknowledgement)
This log captures user-defined information and logs it to roc_plus_user_defined_info.log.
- See the
ROC_PLUS::roc_plus_user_defined_info_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 100 (READ USER DEFINED POINT TYPES).
This log captures history information data and logs it to roc_plus_history_point_data.log.
- See the
ROC_PLUS::roc_plus_history_point_data_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcodes 135 (SINGLE HISTORY POINT DATA) and 136 (MULTIPLE HISTORY POINT DATA).
This log captures history point data and logs it to roc_plus_history_information.log.
- See the
ROC_PLUS::roc_plus_history_information_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 139 (READ HISTORY INFORMATION).
This log captures time period history points data and logs it to roc_plus_time_period_history_points.log.
- See the
ROC_PLUS::roc_plus_time_period_history_points_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 139 (READ HISTORY INFORMATION).
This log captures single point parameter data and logs it to roc_plus_single_point_parameters.log.
- See the
ROC_PLUS::roc_plus_single_point_parameters_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcodes 166 (WRITE SINGLE POINT PARAMETERS) and 167 (READ SINGLE POINT PARAMETERS).
This log captures file transfer operations and logs it to roc_plus_file_transfer.log.
- See the
ROC_PLUS::roc_plus_file_transfer_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 203 (GENERAL FILE TRANSFER).
This log captures peer-to-peer network message data and logs it to roc_plus_peer_to_peer_network_messages.log.
- See the
ROC_PLUS::roc_plus_peer_to_peer_network_messages_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 205 (PEER TO PEER NETWORK MESSAGES).
- NOTE: as of right now these opcodes are not parsed so this log is not currently utilized.
This log captures transaction history data and logs it to roc_plus_transaction_history.log.
- See the
ROC_PLUS::roc_plus_transaction_history_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is associated with ROC Plus Opcode 206 (TRANSACTION HISTORY).
This log captures raw data from unrecognized or unparseable ROC Plus opcodes and logs it to roc_plus_unknown_data.log.
- See the
ROC_PLUS::roc_plus_unknown_data_log: recordin filescripts/roc_plus_types.zeekfor a list of the fields logged. - This log is used for any opcode that the parser doesn't specifically handle.
Copyright 2025 Battelle Energy Alliance, LLC. Released under the terms of the 3-Clause BSD License (see LICENSE).