Skip to content

cert-lv/spicy-iec104

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

280 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zeek IEC 104

Overview

zeek-iec104 is a Zeek plugin written using Spicy for parsing and logging fields used by the IEC 104 protocol.

Differences from upstream

  • More ASDU type parsing implemented
  • APDU contents logged to log files (only if log.zeek script is loaded)
    • For unknown (unimplemented) ASDU types hex dump of content is logged
  • Zeek events generated only for high-level units (i.e., no separate events for internal units like CP56Time2a or bit-fields):
    • Control part of an APCI (S, U and I format headers)
    • Identification part of an ASDU
    • Object specific information of an ASDU
  • Easy to correlate APDU sub-part event generation, with the parts mentioned above in sequence:
    • APCI control field
    • ASDU common part (Cause of Transmission, address fields)
    • Object-specific ASDU part (object information)
  • All events carry communication direction information
  • print.zeek script to dump APCIs to console (good for analyzing captured traffic with no need to correlate different log files)
  • Proper parsing (and logging) of R32 (float) and VTI (7-bit signed integer) values
  • Logging in TSV (Zeek default) or JSON formats

Installation

To build and install the parser into Zeek the following can be used:

cmake . && make install

After successful installation the following command:

zeek -NN | grep IEC104

should have output similar to this:

[Analyzer] spicy_iec104 (ANALYZER_SPICY_IEC104, enabled)

Implementation

The plugin is implemented using following files:

analyzer/zeek_iec104.spicy
Spicy protocol analyzer.
analyzer/iec104.evt
Event descriptions for Zeek integration.
scripts/iec104.zeek
Zeek side definitions of structures exported from Spicy and analyzer registration for IEC-104 default port 2404/tcp.
scripts/common.zeek
Shared helper code
scripts/log_telemetry.zeek
Emits telemetry/measured-value style information objects into iec104_telemetry.log.
scripts/log_cmd.zeek
Command transaction logging with correlation of Act / Actcon / ActTerm into:
  • iec104_write.log (writes/commands)
  • iec104_query.log (interrogation/counter interrogation)
  • iec104_ctrl.log (clock sync/test/reset)
  • iec104_param.log (parameterization)
scripts/log_read.zeek
Correlates C_RD_NA_1 read request/response pairs into iec104_read.log.
scripts/log_file.zeek
Summarizes file transfer segment bursts (F_SG_NA_1) and flushes on end markers or timeout into iec104_file.log.
scripts/print.zeek
Support script that prints communication in sequential manner in a way that can be easily cross-checked with other tools (e.g., Wireshark). This is how the initial output of analyzing testing/Traces/first/iec104.pcap using this script looks like:
1372918997.053303 10.20.102.1:46413 -> 10.20.100.108:2404, U TESTFR act
1372918997.053845 10.20.102.1:46413 <- 10.20.100.108:2404, U TESTFR con
1372918997.306461 10.20.102.1:46413 -> 10.20.100.108:2404, U STARTDT act
1372918997.307014 10.20.102.1:46413 <- 10.20.100.108:2404, U STARTDT con
1372918997.321659 10.20.102.1:46413 -> 10.20.100.108:2404, I ssn:0, rsn:0
  ASDU Act OA=0 CA=10, C_IC_NA_1 obj_addr=0 QOI=20
1372918997.323589 10.20.102.1:46413 <- 10.20.100.108:2404, I ssn:0, rsn:0
  ASDU Init OA=0 CA=10, M_EI_NA_1 obj_addr=0 COI=0 LPC=F
1372918997.331734 10.20.102.1:46413 -> 10.20.100.108:2404, I ssn:1, rsn:1
  ASDU Act OA=0 CA=10, C_IC_NA_1 obj_addr=0 QOI=20
1372918997.333710 10.20.102.1:46413 <- 10.20.100.108:2404, I ssn:1, rsn:1
  ASDU Actcon OA=0 CA=10, C_IC_NA_1 obj_addr=0 QOI=20
1372918997.333710 10.20.102.1:46413 <- 10.20.100.108:2404, I ssn:2, rsn:1
  ASDU Inrogen OA=0 CA=10, M_SP_NA_1 obj_addr=1 SIQ=[spi=F, bl=F, sb=F, nt=F, iv=F]
  ASDU Inrogen OA=0 CA=10, M_SP_NA_1 obj_addr=2 SIQ=[spi=F, bl=F, sb=F, nt=F, iv=F]
  ASDU Inrogen OA=0 CA=10, M_SP_NA_1 obj_addr=3 SIQ=[spi=F, bl=F, sb=F, nt=F, iv=F]
  ASDU Inrogen OA=0 CA=10, M_SP_NA_1 obj_addr=4 SIQ=[spi=F, bl=F, sb=F, nt=F, iv=F]
    
scripts/seq.zeek
APCI Send and Receive sequence number tracking.

Supported information object types

The Spicy protocol analyzer and the corresponding Zeek code has support for the following ASDU information object types:

ReferenceTypeIDImplemented
M_SP_NA_11yes
M_SP_TA_12yes
M_DP_NA_13yes
M_DP_TA_14yes
M_ST_NA_15yes
M_ST_TA_16yes
M_BO_NA_17yes
M_BO_TA_18yes
M_ME_NA_19yes
M_ME_TA_110yes
M_ME_NB_111yes
M_ME_TB_112yes
M_ME_NC_113yes
M_ME_TC_114yes
M_IT_NA_115yes
M_IT_TA_116yes
M_EP_TA_117yes
M_EP_TB_118yes
M_EP_TC_119yes
M_PS_NA_120yes
M_ME_ND_121yes
M_SP_TB_130yes
M_DP_TB_131yes
M_ST_TB_132yes
M_BO_TB_133yes
M_ME_TD_134yes
M_ME_TE_135yes
M_ME_TF_136yes
M_IT_TB_137yes
M_EP_TD_138yes
M_EP_TE_139yes
M_EP_TF_140yes
C_SC_NA_145yes
C_DC_NA_146yes
C_RC_NA_147yes
C_SE_NA_148yes
C_SE_NB_149yes
C_SE_NC_150yes
C_BO_NA_151yes
C_SC_TA_158yes
C_DC_TA_159yes
C_RC_TA_160yes
C_SE_TA_161yes
C_SE_TB_162yes
C_SE_TC_163yes
C_BO_TA_164yes
M_EI_NA_170yes
C_IC_NA_1100yes
C_CI_NA_1101yes
C_RD_NA_1102yes
C_CS_NA_1103yes
C_TS_NA_1104
C_RP_NA_1105yes
C_CD_NA_1106
C_TS_TA_1107yes
P_ME_NA_1110yes
P_ME_NB_1111yes
P_ME_NC_1112yes
P_AC_NA_1113yes
F_FR_NA_1120yes
F_SR_NA_1121yes
F_SC_NA_1122yes
F_LS_NA_1123yes
F_AF_NA_1124yes
F_SG_NA_1125yes
F_DR_TA_1126
F_SC_NB_1127

Logging capabilities

This repository ships a set of Zeek scripts that turn the Spicy-generated IEC-104 events into a number of dedicated log files.

The log files are written in Zeek’s default TSV format unless you enable JSON logging (e.g., via Zeek’s LogAscii::use_json).

Common field semantics (applies to most logs)

Many logs share the following concepts:

  • ts: event/transaction start time as seen by Zeek.
  • uid: Zeek connection UID (useful for joining with conn.log).
  • id: Zeek 4-tuple record (orig_h, orig_p, resp_h, resp_p).
  • is_orig: Zeek’s direction flag for the event (originator -> responder).
  • asdu_type: IEC-104 ASDU Type ID (printed as the enum name, e.g. C_SC_NA_1).
  • cot: Cause of Transmission (enum, e.g. Act, Actcon, Spont, Inrogen, …).
  • ca: “Common Address of ASDU”.
  • ioa: “Information Object Address” (object address).

Unless noted otherwise, optional fields are omitted (empty in TSV, absent in JSON) when the value is not available for the particular ASDU type or phase.

Transaction correlation and status fields

The command-oriented logs (iec104_write, iec104_query, iec104_ctrl, iec104_param) correlate the IEC-104 activation sequence:

  • Act (activation)
  • Actcon (activation confirmation)
  • ActTerm (activation termination)

Correlation is performed per connection and per command “shape” (ASDU type, addressing, value, qualifiers, etc.) using FIFO assumptions (i.e., the first Actcon is matched to the first pending Act of the same command “shape”).

These logs expose:

  • actcon_ts, actterm_ts: timestamps of the observed phases (if any).
  • duration: typically actterm_ts - ts (only present if both exist).
  • missing: comma-separated list of missing phases (e.g., Actcon,ActTerm).
  • error / error_reason: derived error signal and reasons; reasons are comma-separated, examples:
    • negative_confirmation@Actcon (PN flag set)
    • test_frame@Act (TEST flag set)
    • cot=UnkType@Actcon (hard error COT values)
  • status: synthesized outcome string:
    • ok: all expected phases observed, no error
    • ok_broadcast: broadcast CA (65535) where confirmations are not expected
    • incomplete: missing phases but no timeout triggered yet
    • error: error conditions observed
    • timeout(request), timeout(Actcon,ActTerm), …: timed-out with missing phases

The read log (iec104_read.log) correlates request/response pairs for C_RD_NA_1.

Log formats

The following sections document each log file (path and column meanings).

iec104_telemetry.log (telemetry / measured values)

This log emits one entry per telemetry object (e.g., single-point or measured values). It focuses on “what value was reported” plus quality and optional timestamps.

Columns:

FieldTypeOptionalMeaning
tstimenoTime when Zeek processed the information object.
uidstringnoZeek connection UID.
idconn_idnoZeek connection 4-tuple.
asdu_typeIEC104TypeIDnoASDU type of the current ASDU context.
cotIEC104CoTnoCause of transmission of the current ASDU context.
cacountnoCommon address (CA).
ioacountnoInformation object address.
valuestringyesHuman-readable value (type-dependent; e.g. "T", "0xdeadbeef", "12.34").
spiboolyesSingle-point information state (for M_SP_*).
blboolyes“Blocked” quality flag (when available).
sbboolyes“Substituted” quality flag (when available).
ntboolyes“Not topical” quality flag (when available).
ivboolyes“Invalid” quality flag (when available).
ovboolyes“Overflow” quality flag (for QDS-based types).
cp24stringyesCP24Time2a formatted string (if present in the IO).
cp56stringyesCP56Time2a formatted string (if present in the IO).

Notes:

  • For ASDU types that do not carry quality flags, the respective fields may be unset.
  • CP24/CP56 are rendered as strings (see common.zeek), e.g.
    • CP24: min=... sec=... msec=... iv=T/F
    • CP56: y=... mon=... day=... h=... min=... sec=... msec=... iv=T/F

iec104_write.log

Tracks write-like command transactions (e.g., single command, double command, set-point, bitstring command), correlating Act / Actcon / ActTerm.

Columns:

FieldTypeOptionalMeaning
tstimenoTransaction start (usually time of Act).
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
is_origboolnoDirection of the phase that started/anchored the transaction.
actionstringnoNormalized action name (e.g. single_write, double_write, setpoint_write, bitstring_write, step_write).
asdu_typeIEC104TypeIDnoASDU type.
cotIEC104CoTnoCOT of the anchored phase (typically Act).
cacountnoCommon address.
ioacountyesInformation object address (when applicable).
valuestringyesNormalized value representation (type-dependent).
seboolyesSelect/Execute flag (where available).
qualifiercountyesCommand qualifier (e.g., QU/QL depending on command type).
actcon_tstimeyesTimestamp when Actcon was seen.
actterm_tstimeyesTimestamp when ActTerm was seen.
durationintervalyesactterm_ts - ts when both are present.
missingstringyesMissing phases (comma-separated).
errorboolyesDerived error indicator.
error_reasonstringyesComma-separated error reasons.
statusstringyesOutcome (ok, incomplete, error, timeout(...), ok_broadcast).

iec104_query.log

Tracks interrogation-like transactions.

Columns:

FieldTypeOptionalMeaning
tstimenoTransaction start (usually time of Act).
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
is_origboolnoDirection of the anchored phase.
actionstringnointerrogation or counter_interrogation.
asdu_typeIEC104TypeIDnoASDU type.
cotIEC104CoTnoCOT of anchored phase.
cacountnoCommon address.
ioacountyesInformation object address (when present).
qoicountyesQualifier of interrogation (for C_IC_NA_1).
qcc_rqtcountyesCounter interrogation request (RQT) (for C_CI_NA_1).
qcc_frzcountyesCounter freeze (FRZ) (for C_CI_NA_1).
actcon_tstimeyesTimestamp when Actcon was seen.
actterm_tstimeyesTimestamp when ActTerm was seen.
durationintervalyesactterm_ts - ts when both are present.
missingstringyesMissing phases.
errorboolyesDerived error indicator.
error_reasonstringyesComma-separated error reasons.
statusstringyesOutcome.

iec104_ctrl.log

Tracks control-type operations such as clock synchronization, test, and reset process.

Columns:

FieldTypeOptionalMeaning
tstimenoTransaction start (usually time of Act).
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
is_origboolnoDirection of anchored phase.
actionstringnoclock_sync, test, reset_process.
asdu_typeIEC104TypeIDnoASDU type.
cotIEC104CoTnoCOT of anchored phase.
cacountnoCommon address.
ioacountyesInformation object address.
time_syncstringyesFormatted CP56Time2a (for clock sync/test where present).
tsccountyesTest sequence counter (for C_TS_TA_1).
qrpcountyesQualifier of reset process (for C_RP_NA_1).
actcon_tstimeyesTimestamp when Actcon was seen.
actterm_tstimeyesTimestamp when ActTerm was seen.
durationintervalyesactterm_ts - ts when both are present.
missingstringyesMissing phases.
errorboolyesDerived error indicator.
error_reasonstringyesComma-separated error reasons.
statusstringyesOutcome.

iec104_param.log

Tracks parameterization transactions (P_ME_* and P_AC_NA_1) except when they are part of interrogation results (those are treated as telemetry and appear in iec104_telemetry.log).

Columns:

FieldTypeOptionalMeaning
tstimenoTransaction start (usually time of Act).
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
is_origboolnoDirection of anchored phase.
actionstringnoparam_measured or param_activation.
asdu_typeIEC104TypeIDnoASDU type.
cotIEC104CoTnoCOT of anchored phase.
cacountnoCommon address.
ioacountyesInformation object address.
valuestringyesValue / parameter representation.
qpm_kpacountyesKPA from QPM (parameter class).
qpm_popboolyesPOP from QPM.
qpm_lpcboolyesLPC from QPM.
qpacountyesQualifier of parameter activation (for P_AC_NA_1).
actcon_tstimeyesTimestamp when Actcon was seen.
actterm_tstimeyesTimestamp when ActTerm was seen.
durationintervalyesactterm_ts - ts when both are present.
missingstringyesMissing phases.
errorboolyesDerived error indicator.
error_reasonstringyesComma-separated error reasons.
statusstringyesOutcome.

iec104_read.log

This log correlates read requests (C_RD_NA_1 from the originator) with the corresponding response (C_RD_NA_1 from the responder) using a FIFO model.

Columns:

FieldTypeOptionalMeaning
tstimenoRequest timestamp (when seen as originator).
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
is_origboolnoDirection of the anchored phase; for a complete transaction this is typically T (request).
actionstringnoAlways value_read.
asdu_typeIEC104TypeIDnoASDU type (C_RD_NA_1).
cotIEC104CoTnoCOT from the anchored phase.
cacountnoCommon address.
ioacountyesInformation object address being read.
raw_datacountyesRaw data returned by the read response (if present in the response).
actcon_tstimeyesTimestamp when the response was seen (used analogously to “confirmation”).
durationintervalyesactcon_ts - ts when both request and response are present.
missingstringyesMissing parts: request, response.
errorboolyesDerived error indicator (PN/TEST/hard-error COT).
error_reasonstringyesComma-separated error reasons.
statusstringyesok, incomplete, error, timeout(...).

iec104_file.log

This log summarizes file segment transfers (F_SG_NA_1) and emits a single row per (connection UID, direction, IOA, file name) “transfer burst”. The summary is flushed when an end marker is observed (F_LS_NA_1 or F_AF_NA_1) or when the transfer stalls for file_seg_timeout.

Columns:

FieldTypeOptionalMeaning
tstimenoTimestamp of the first observed segment in the burst.
ts_endtimeyesTimestamp of the last observed segment (or last activity before timeout).
durationintervalyests_end - ts when available.
uidstringnoConnection UID.
idconn_idnoConnection 4-tuple.
directionstringnocontrol_to_station if is_orig=T, else station_to_control.
is_origboolnoDirection flag used for the segment stream.
cacountnoCommon address seen for the segments (tries to prefer non-broadcast over 65535).
ioacountnoObject address (file object).
fnamecountnoFile name / identifier (as carried in the protocol).
segmentscountnoNumber of F_SG_NA_1 segments seen.
bytescountnoTotal bytes of segment payloads (sum of |seg|).
statusstringnook (end marker seen) or timeout (flushed due to inactivity) or in_progress (internal state, typically not emitted).

Resources

PCAPs

About

A Zeek Parser for the IEC 104 protcol built using Spicy.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Zeek 83.8%
  • Common Lisp 10.5%
  • CMake 3.4%
  • Shell 1.9%
  • Dockerfile 0.3%
  • Standard ML 0.1%