Hi,
As there is no native mms parser inside zeek, I am trying to send packets which have dport 102 over tcp over the broker to another python-based mms parser. I know this is not concrete and full-fledged solution as port-based detection may not be correct always or may generate false detection. Anyway, I have used “zkg create --feature=spicy-protocol-analyzer” to create the below parser. (I am using zeek 6.0.0, also tested in zeek 6.2.0-dev.147)
The idea is to send payload above tcp to the python module over the broker, so I have used below mms.evt, mms.spicy and zeek_mms.spicy to generate mms.hlto.
#mms.evt
import mms;
import Zeek_mms;
# TODO: Adjust below how/when the analyzer will be activated. The example
# defines a well-known port to trigger it. For more information, see:
#
# https://docs.zeek.org/projects/spicy/en/latest/zeek.html#interface-definitions-evt-files
#
protocol analyzer mms over TCP:
parse originator with mms::mmsUnit,
parse responder with mms::mmsUnit,
port 102/tcp; # adapt port number in main.zeek accordingly
# TODO: Connect Spicy-side events with Zeek-side events. The example just
# defines a simple example event that forwards the raw data (which in practice
# you don't want to do!).
on mms::mmsUnit -> event mms::message($conn, $is_orig, self.payload);
#mms.spicy
# TODO: Define your analyzer here.
module mms;
public type mmsUnit = unit {
payload: bytes &eod;
};
#zeek_mms.spicy
# Set up protocol confirmation/rejection for analyzers, as well as any further
# Zeek-specific analysis.
module Zeek_mms;
import mms;
import zeek;
# TODO: Protocol analyzers should confirm once they are reasonably sure that
# they are indeed parsing the right protocol. Pick a unit that's a little bit
# into the parsing process here.
#
on mms::mmsUnit::%done {
zeek::confirm_protocol();
}
# Any error bubbling up to the top unit will trigger a protocol rejection.
on mms::mmsUnit::%error {
zeek::reject_protocol("error while parsing mms");
}
#main.zeek
@load base/protocols/conn/removal-hooks
module mms;
global mms_topic = "/topic/mms";
global mms_parsed: event(c: connection);
export {
## Log stream identifier.
redef enum Log::ID += { LOG };
## Record type containing the column fields of the mms log.
type Info: record {
## Timestamp for when the activity happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
# TODO: Adapt subsequent fields as needed.
# Message direction (request or response)
network_direction: string &log &optional;
## Request-side payload.
request: string &optional &log;
## Response-side payload.
reply: string &optional &log;
};
## A default logging policy hook for the stream.
global log_policy: Log::PolicyHook;
## Default hook into mms logging.
global log_mms: event(rec: Info);
## mms finalization hook.
global finalize_mms: Conn::RemovalHook;
}
const request_str_g: string = "request"; # Used with Network 'requests'
const response_str_g: string = "response"; # Used with Network 'responses'
redef record connection += {
mms: Info &optional;
};
const ports = {
# TODO: Replace with actual port(s).
102/tcp # adapt port number in mms.evt accordingly
};
redef likely_server_ports += { ports };
event zeek_init() &priority=5
{
suspend_processing();
Broker::peer(addr_to_uri(127.0.0.1), 50004/tcp);
Log::create_stream(mms::LOG, [$columns=Info, $ev=log_mms, $path="mms", $policy=log_policy]);
}
event Broker::peer_added(ep: Broker::EndpointInfo, msg: string)
{
print "PEER ADDED", ep;
continue_processing();
}
# Initialize logging state.
hook set_session(c: connection)
{
if ( c?$mms )
return;
c$mms = Info($ts=network_time(), $uid=c$uid, $id=c$id);
Conn::register_removal_hook(c, finalize_mms);
}
function emit_log(c: connection)
{
if ( ! c?$mms )
return;
Log::write(mms::LOG, c$mms);
delete c$mms;
}
# Example event defined in mms.evt.
event mms::message(c: connection, is_orig: bool, payload: string)
{
print fmt("Testing mms: [%s] %s %s", (is_orig ? "request" : "reply"), c$id, payload);
hook set_session(c);
local info = c$mms;
if ( is_orig )
{
info$request = payload;
info$network_direction = request_str_g;
}
else
{
info$reply = payload;
info$network_direction = response_str_g;
}
Broker::publish(mms_topic, mms_parsed, c);
}
hook finalize_mms(c: connection)
{
# TODO: For UDP protocols, you may want to do this after every request
# and/or reply.
emit_log(c);
#Broker::publish(mms_topic, mms_parsed, c);
}
The below packet dump I am getting while running the script … (highlighting the packet dump)
[root@root]# /usr/local/zeek/bin/zeek -Cr mms-takeControl.pcap main.zeek
processing suspended
PEER ADDED, [id=6775f597-ede4-5fb6-9d23-32acf3517b5a, network=[address=127.0.0.1, bound_port=50004/tcp]]
processing continued
Testing mms: [request] [orig_h=127.0.0.1, orig_p=36597/tcp, resp_h=127.0.0.1, resp_p=102/tcp] \x03\x00\x00\x13\x0e\xe0\x00\x00\x00\x06\x00\xc1\x02\x00\x02\xc2\x02\x02\x00\x03\x00\x00/\x02\xf0\x80\xa8&\x80\x02\x00\x1f\x81\x01\x03\x82\x01\x03\x83\x02\x08\x08\xa4\x16\x80\x01\x01\x81\x03\x05\xe8\x00\x82\x0c\x03\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\x00\x00 \x02\xf0\x80\xa0\x17\x02\x01\x01\xb3\x12\xa0\x0a\x80\x08reserved\x83\x01\x01\x86\x01\x01\x03\x00\x00\x1a\x02\xf0\x80\xa0\x11\x02\x01\x01\xb4\x0c\xa0\x0a\x80\x08reserved\x03\x00\x00\x09\x02\xf0\x80\x8b\x00
^C1227729893.716384 received termination signal
Testing mms: [reply] [orig_h=127.0.0.1, orig_p=36597/tcp, resp_h=127.0.0.1, resp_p=102/tcp] \x03\x00\x00\x05\x00\xd0\x80\x03\x00\x00\x07\x00\x0f\x80\xa9\x00\x03\x00\x00\x0c\x00\x0f\x80\xa1\x05\x02\x01\x00\xb3\x00\x03\x00\x00\x05\x00\x0f\x80\x03\x00\x00\x05\x00\x0f\x80
Where as if you see the below image or pcap file you will find less bytes in the payload.
I have 3 questions here,
-
Why am I seeing extra bytes in the broker dump? Is there any issue in the parser or script?
-
When I do ctrl+c, then only I can see the reply packet in the stdout. As you can see in the above dump, reply is being printed after terminating the zeek process. Why? Sometime there are many mms packets but it’s getting stuck after the first.
-
Zeek is not printing COTP packets here although it’s matching the criteria of dport 102 over tcp. Why?
Thanks
Biswa