0

Good Morning,

I have a Zeek machine generating logs on a Modbus traffic.

Currently, my script generates logs looking like this :

ts      tid     id.orig_h       id.orig_p       id.resp_h       id.resp_p       unit_id func    network_direction
1342774501.072580       32      10.2.2.2      51411   10.2.2.3      502     255    READ_HOLDING_REGISTERS  request 
1342774501.087014       32      10.2.2.2      51411   10.2.2.3      502     255     READ_HOLDING_REGISTERS  response

'tid' is the transaction id to identify a request/response couple. I want to know if a robot hasn't responded to the Controller by logging only requests that did not have a response within 1 second.

My code is :

module Modbus_Extended;

export {
    redef enum Log::ID += { LOG_DETAILED,
                            LOG_MASK_WRITE_REGISTER,
                            LOG_READ_WRITE_MULTIPLE_REGISTERS};

    type Modbus_Detailed: record {
        ts                      : time              &log;             # Timestamp of event
        tid                     : count            &log;             # Zeek unique ID for connection
        id                      : conn_id           &log;             # Zeek connection struct (addresses and ports)
        unit_id                 : count             &log;             # Modbus unit-id
        func                    : string            &log &optional;   # Modbus Function
        network_direction       : string            &log &optional;   # Message direction (request or response)
        address                 : count             &log &optional;   # Starting address for value(s) field
        quantity                : count             &log &optional;   # Number of addresses/values read or written to
        values                  : string            &log &optional;   # Coils, discrete_inputs, or registers read/written to
    };
    global log_modbus_detailed: event(rec: Modbus_Detailed);


global transaction_ids: set[string, string] = {};

event modbus_message(c: connection,
                     headers: ModbusHeaders,
                     is_orig: bool) &priority=-5 {

    local modbus_detailed_rec: Modbus_Detailed;

    if(headers$tid !in transaction_ids[count]){
        add transaction_ids[headers$tid, c$modbus$ts]
    }else{
        delete transaction_ids[headers$tid, c$modbus$ts]
    }
    for(i in transaction_ids[timestamp]){
        if(c$modbus$ts > transactions_ids[headers$tid, i] +1)
        {
            Log::write(LOG_DETAILED, modbus_detailed_rec);
        }
    }
}
}

My guess is that I have to store transaction ids and check if I get only one occurence within this timelapse and then log it into a file, but I can figure out how to do it. Currently I can only generate logs with all the modbus traffic.

Thank you for your help

Leviath
  • 3
  • 3
  • You are basing this on the CISA `icsnpp-modbus` package, right? Are you planning to run your change on top of it, or replacing it? I'd suggest different approaches in those cases, which I'd be happy to flesh out in a full answer. – Christian Dec 01 '22 at 22:16

0 Answers0