summaryrefslogtreecommitdiff
path: root/broccoli/script
diff options
context:
space:
mode:
authorAndreas Lindhé <andreas@lindhe.io>2017-10-11 08:47:50 +0200
committerAndreas Lindhé <andreas@lindhe.io>2017-10-11 08:47:50 +0200
commitda9544a4dba273d1cada460f3064d9e1ff21b44e (patch)
treea4280500e713216b49fdd46786f30eee3d60adb8 /broccoli/script
parent89ea70298caff759b719ab0855ad2cd48dfee0ca (diff)
downloadmidbro-da9544a4dba273d1cada460f3064d9e1ff21b44e.tar.gz
midbro-da9544a4dba273d1cada460f3064d9e1ff21b44e.tar.bz2
Move files from bro-script directory
Diffstat (limited to 'broccoli/script')
-rw-r--r--broccoli/script/README9
-rw-r--r--broccoli/script/pasad-parsed.bro96
-rw-r--r--broccoli/script/pasad-simple.bro56
3 files changed, 161 insertions, 0 deletions
diff --git a/broccoli/script/README b/broccoli/script/README
new file mode 100644
index 0000000..15f121e
--- /dev/null
+++ b/broccoli/script/README
@@ -0,0 +1,9 @@
+This directory contains a baseline implementation of the package parser
+implemented as a Bro script. A .bro file contains a script that can be
+executed on a Modbus pcap dump. A .log file contains an example for an
+output file generated by this script. By convention, the sample log file
+should contain the first 100 lines of a real log file obtained from running
+the script on packets_00014_20161128135616.cap.
+
+Currently, the scripts only handle the read_holding_registers event. Other
+events can handled by simply copying and adapting the existing handlers.
diff --git a/broccoli/script/pasad-parsed.bro b/broccoli/script/pasad-parsed.bro
new file mode 100644
index 0000000..88b1be1
--- /dev/null
+++ b/broccoli/script/pasad-parsed.bro
@@ -0,0 +1,96 @@
+## Implementation that outputs the register identification and the register
+## value. The correct register count is not checked and might lead to indexing
+## errors.
+
+module Pasad;
+
+## DATA STRUCTURES
+
+export {
+ redef enum Log::ID += { LOG };
+
+ type Transaction: record {
+ start_address: count;
+ quantity: count;
+ };
+
+ type TransactionTable: table[count] of Transaction;
+
+ type Info: record {
+ transactions: TransactionTable &default=TransactionTable();
+ };
+
+ type Entry: record {
+ ip: addr &log;
+ uid: count &log;
+ regtype: string &log;
+ address: count &log;
+ register: count &log;
+ };
+}
+
+redef record connection += {
+ pasad: Info &default=Info();
+};
+
+## CUSTOM EVENTS
+
+event pasad_entry(entry: Entry)
+ {
+ Log::write(Pasad::LOG, entry);
+ }
+
+event pasad_unmatched(tid: count)
+ {
+ print fmt("Unmatched response: tid=%d", tid);
+ }
+
+## CUSTOM FUNCTIONS
+
+function pasad_generate_events(transaction: Transaction, c: connection, headers: ModbusHeaders, registers: ModbusRegisters, regtype: string)
+ {
+ # TODO: check registers size
+ local i = 0;
+ while ( i < transaction$quantity )
+ {
+ local entry = Entry(
+ $ip=c$id$orig_h,
+ $uid=headers$uid,
+ $regtype=regtype,
+ $address=transaction$start_address + i,
+ $register=registers[i]
+ );
+ event pasad_entry(entry);
+ ++i;
+ }
+ }
+
+## EVENT HANDLERS
+
+event bro_init() &priority=5
+ {
+ Log::create_stream(Pasad::LOG, [$columns=Entry, $path="pasad-parsed"]);
+ }
+
+event modbus_read_holding_registers_request(c: connection, headers: ModbusHeaders, start_address: count, quantity: count)
+ {
+ local tid = headers$tid;
+ local transaction = Transaction(
+ $start_address=start_address,
+ $quantity=quantity
+ );
+ c$pasad$transactions[tid] = transaction;
+ }
+
+event modbus_read_holding_registers_response(c: connection, headers: ModbusHeaders, registers: ModbusRegisters)
+ {
+ local tid = headers$tid;
+ if ( tid !in c$pasad$transactions )
+ {
+ event pasad_unmatched(tid);
+ return;
+ }
+ local transaction = c$pasad$transactions[tid];
+ delete c$pasad$transactions[tid];
+ pasad_generate_events(transaction, c, headers, registers, "h");
+ }
diff --git a/broccoli/script/pasad-simple.bro b/broccoli/script/pasad-simple.bro
new file mode 100644
index 0000000..db3b4be
--- /dev/null
+++ b/broccoli/script/pasad-simple.bro
@@ -0,0 +1,56 @@
+## Simple implementation that outputs the raw request and response data
+## to a log file.
+## Currently, this only handles the read_holding_registers event. Other
+## events can be handled similarily. This implementation assumes that
+## requests and responses are exchanged within the same connection. I am not
+## sure whether this really holds.
+
+module Pasad;
+
+export {
+ redef enum Log::ID += { LOG };
+
+ type Info: record {
+ ts_request: time &log;
+ ts_response: time &log &optional;
+ rtype: string &log;
+ tid_request: count &log;
+ tid_response: count &log &optional;
+ ip_orig: addr &log;
+ ip_resp: addr &log;
+ start_address: count &log;
+ quantity: count &log;
+ registers: ModbusRegisters &log &optional;
+ };
+}
+
+redef record connection += {
+ pasad: Info &optional;
+};
+
+event bro_init() &priority=5
+ {
+ Log::create_stream(Pasad::LOG, [$columns=Info, $path="pasad-simple"]);
+ }
+
+event modbus_read_holding_registers_request(c: connection, headers: ModbusHeaders, start_address: count, quantity: count)
+ {
+ local rec: Info = [
+ $ts_request=network_time(),
+ $rtype="holding",
+ $tid_request=headers$tid,
+ $start_address=start_address,
+ $quantity=quantity,
+ $ip_orig=c$id$orig_h,
+ $ip_resp=c$id$resp_h
+ ];
+ c$pasad = rec;
+ }
+
+event modbus_read_holding_registers_response(c: connection, headers: ModbusHeaders, registers: ModbusRegisters)
+ {
+ c$pasad$tid_response = headers$tid;
+ c$pasad$ts_response = network_time();
+ c$pasad$registers = registers;
+ Log::write(Pasad::LOG, c$pasad);
+ }