mirror of
https://github.com/zeek/zeek.git
synced 2025-10-13 12:08:20 +00:00
Merge remote-tracking branch 'remotes/origin/topic/seth/modbus-merge'
* remotes/origin/topic/seth/modbus-merge: Small modbus documentation update and tiny refactoring. Final touches to modbus analyzer for now. Major revisions to Modbus analyzer support (not quite done yet). put some make-up on Modbus analyser Modbus analyser, added support: FC=20,21 Modbus analyzer,added support: FC=1,2,15,24 Modbus analyzer, current support: FC=3,4,5,6,7,16,22,23 Closes #915.
This commit is contained in:
commit
86ce564107
21 changed files with 81439 additions and 2 deletions
56
scripts/policy/protocols/modbus/known-masters-slaves.bro
Normal file
56
scripts/policy/protocols/modbus/known-masters-slaves.bro
Normal file
|
@ -0,0 +1,56 @@
|
|||
##! Script for tracking known Modbus masters and slaves.
|
||||
##!
|
||||
##! .. todo: This script needs a lot of work. What might be more interesting is to track
|
||||
##! master/slave relationships based on commands sent and successful (non-exception)
|
||||
##! responses.
|
||||
|
||||
module Known;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { MODBUS_LOG };
|
||||
|
||||
type ModbusDeviceType: enum {
|
||||
MODBUS_MASTER,
|
||||
MODBUS_SLAVE,
|
||||
};
|
||||
|
||||
type ModbusInfo: record {
|
||||
## The time the device was discovered.
|
||||
ts: time &log;
|
||||
## The IP address of the host.
|
||||
host: addr &log;
|
||||
## The type of device being tracked.
|
||||
device_type: ModbusDeviceType &log;
|
||||
};
|
||||
|
||||
## The Modbus nodes being tracked.
|
||||
global modbus_nodes: set[addr, ModbusDeviceType] &create_expire=1day &redef;
|
||||
|
||||
## Event that can be handled to access the loggable record as it is sent
|
||||
## on to the logging framework.
|
||||
global log_known_modbus: event(rec: ModbusInfo);
|
||||
}
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Known::MODBUS_LOG, [$columns=ModbusInfo, $ev=log_known_modbus]);
|
||||
}
|
||||
|
||||
event modbus_message(c: connection, headers: ModbusHeaders, is_orig: bool)
|
||||
{
|
||||
local master = c$id$orig_h;
|
||||
local slave = c$id$resp_h;
|
||||
|
||||
if ( [master, MODBUS_MASTER] !in modbus_nodes )
|
||||
{
|
||||
add modbus_nodes[master, MODBUS_MASTER];
|
||||
Log::write(MODBUS_LOG, [$ts=network_time(), $host=master, $device_type=MODBUS_MASTER]);
|
||||
}
|
||||
|
||||
if ( [slave, MODBUS_SLAVE] !in modbus_nodes )
|
||||
{
|
||||
add modbus_nodes[slave, MODBUS_SLAVE];
|
||||
Log::write(MODBUS_LOG, [$ts=network_time(), $host=slave, $device_type=MODBUS_SLAVE]);
|
||||
}
|
||||
|
||||
}
|
101
scripts/policy/protocols/modbus/track-memmap.bro
Normal file
101
scripts/policy/protocols/modbus/track-memmap.bro
Normal file
|
@ -0,0 +1,101 @@
|
|||
##! This script tracks the memory map of holding (read/write) registers and logs
|
||||
##! changes as they are discovered.
|
||||
##!
|
||||
##! .. todo: Not all register reads and write functions are being supported yet.
|
||||
module Modbus;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { Modbus::REGISTER_CHANGE_LOG };
|
||||
|
||||
## The hosts that should have memory mapping enabled.
|
||||
const track_memmap: Host = ALL_HOSTS &redef;
|
||||
|
||||
type MemmapInfo: record {
|
||||
## Timestamp for the detected register change
|
||||
ts: time &log;
|
||||
## Unique ID for the connection
|
||||
uid: string &log;
|
||||
## Connection ID.
|
||||
id: conn_id &log;
|
||||
## The device memory offset.
|
||||
register: count &log;
|
||||
## The old value stored in the register.
|
||||
old_val: count &log;
|
||||
## The new value stored in the register.
|
||||
new_val: count &log;
|
||||
## The time delta between when the 'old_val' and 'new_val' were seen.
|
||||
delta: interval &log;
|
||||
};
|
||||
|
||||
type RegisterValue: record {
|
||||
last_set: time;
|
||||
value: count;
|
||||
};
|
||||
|
||||
## Indexed on the device register value and yielding the register value.
|
||||
type Registers: table[count] of RegisterValue;
|
||||
|
||||
## The memory map of slaves is tracked with this variable.
|
||||
global device_registers: table[addr] of Registers;
|
||||
|
||||
## This event is generated every time a register is seen to be different than
|
||||
## it was previously seen to be.
|
||||
global changed_register: event(c: connection, register: count, old_val: count, new_val: count, delta: interval);
|
||||
}
|
||||
|
||||
redef record Modbus::Info += {
|
||||
track_address: count &default=0;
|
||||
};
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Modbus::REGISTER_CHANGE_LOG, [$columns=MemmapInfo]);
|
||||
}
|
||||
|
||||
event modbus_read_holding_registers_request(c: connection, headers: ModbusHeaders, start_address: count, quantity: count)
|
||||
{
|
||||
c$modbus$track_address = start_address+1;
|
||||
}
|
||||
|
||||
event modbus_read_holding_registers_response(c: connection, headers: ModbusHeaders, registers: ModbusRegisters)
|
||||
{
|
||||
local slave = c$id$resp_h;
|
||||
|
||||
if ( ! addr_matches_host(slave, track_memmap ) )
|
||||
return;
|
||||
|
||||
if ( slave !in device_registers )
|
||||
device_registers[slave] = table();
|
||||
|
||||
local slave_regs = device_registers[slave];
|
||||
for ( i in registers )
|
||||
{
|
||||
if ( c$modbus$track_address in slave_regs )
|
||||
{
|
||||
if ( slave_regs[c$modbus$track_address]$value != registers[i] )
|
||||
{
|
||||
local delta = network_time() - slave_regs[c$modbus$track_address]$last_set;
|
||||
event Modbus::changed_register(c, c$modbus$track_address,
|
||||
slave_regs[c$modbus$track_address]$value, registers[i],
|
||||
delta);
|
||||
|
||||
slave_regs[c$modbus$track_address]$last_set = network_time();
|
||||
slave_regs[c$modbus$track_address]$value = registers[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local tmp_reg: RegisterValue = [$last_set=network_time(), $value=registers[i]];
|
||||
slave_regs[c$modbus$track_address] = tmp_reg;
|
||||
}
|
||||
|
||||
++c$modbus$track_address;
|
||||
}
|
||||
}
|
||||
|
||||
event Modbus::changed_register(c: connection, register: count, old_val: count, new_val: count, delta: interval)
|
||||
{
|
||||
local rec: MemmapInfo = [$ts=network_time(), $uid=c$uid, $id=c$id,
|
||||
$register=register, $old_val=old_val, $new_val=new_val, $delta=delta];
|
||||
Log::write(REGISTER_CHANGE_LOG, rec);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue