From da9544a4dba273d1cada460f3064d9e1ff21b44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lindh=C3=A9?= Date: Wed, 11 Oct 2017 08:47:50 +0200 Subject: Move files from bro-script directory --- broccoli/script/README | 9 ++++ broccoli/script/pasad-parsed.bro | 96 ++++++++++++++++++++++++++++++++++++++++ broccoli/script/pasad-simple.bro | 56 +++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 broccoli/script/README create mode 100644 broccoli/script/pasad-parsed.bro create mode 100644 broccoli/script/pasad-simple.bro (limited to 'broccoli') 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); + } -- cgit v1.2.1