zeek/scripts/base/protocols/rdp/main.bro
2015-02-14 13:16:48 -08:00

200 lines
5.8 KiB
Text

@load ./consts
module RDP;
export {
redef enum Log::ID += { LOG };
type Info: record {
## Timestamp for when the event 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;
## Cookie value used by the client machine.
## This is typically a username.
cookie: string &log &optional;
## Keyboard layout (language) of the client machine.
keyboard_layout: string &log &optional;
## RDP client version used by the client machine.
client_build: string &log &optional;
## Hostname of the client machine.
client_hostname: string &log &optional;
## Product ID of the client machine.
client_product_id: string &log &optional;
## Name of the server.
server_name: vector of string &log &optional;
## Authentication result for the connection. This value is extracted from the payload for native authentication.
## TODO: Perform heuristic authentication determination for NLA.
authentication_result: string &log &optional;
## Encryption level of the connection.
encryption_level: string &log &optional;
## Encryption method of the connection.
encryption_method: string &log &optional;
## Track status of logging RDP connections.
done: bool &default=F;
};
## Variable to track if NTLM authentication is used.
global ntlm = F;
## Size in bytes of data sent by the server at which the RDP connection is presumed to be successful (NTLM authentication only).
const authentication_data_size = 1000 &redef;
## Event that can be handled to access the rdp record as it is sent on
## to the loggin framework.
global log_rdp: event(rec: Info);
}
const ports = { 3389/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(RDP::LOG, [$columns=Info, $ev=log_rdp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, ports);
}
redef record connection += {
rdp: Info &optional;
};
function rdp_done(c: connection, done: bool)
{
if ( done )
{
c$rdp$done = T;
# Not currently implemented
# if ( ntlm && use_conn_size_analyzer )
# {
# if ( c$resp$size > authentication_data_size )
# c$rdp$authentication_result = "Success (H)";
# else c$rdp$authentication_result = "Undetermined";
# }
if ( c$rdp?$authentication_result && ( ! c$rdp?$encryption_method || ! c$rdp?$encryption_level ) )
Reporter::error(fmt("Error parsing RDP security data in connection %s",c$uid));
Log::write(RDP::LOG, c$rdp);
skip_further_processing(c$id);
set_record_packets(c$id, F);
}
}
event rdp_tracker(c: connection)
{
if ( c$rdp$done )
return;
local id = c$id;
if ( ! connection_exists(id) )
{
rdp_done(c,T);
return;
}
lookup_connection(id);
if ( connection_exists(id) )
{
# If the RDP connection has been alive for more than 5secs, log it
# This duration should be sufficient to collect the data that needs to be logged
local diff = network_time() - c$rdp$ts;
if ( diff > 5secs )
{
rdp_done(c,T);
return;
}
}
# schedule the event to run again if necessary
schedule +5secs { rdp_tracker(c) };
}
function set_session(c: connection)
{
if ( ! c?$rdp )
{
c$rdp = [$ts=network_time(),$id=c$id,$uid=c$uid];
add c$service["rdp"];
}
}
event connection_state_remove(c: connection) &priority=-5
{
# Log the RDP connection if the connection is removed but the session has not been marked as done
if ( c?$rdp && ! c$rdp$done )
rdp_done(c,T);
}
event rdp_native_client_request(c: connection, cookie: string) &priority=5
{
if ( "Cookie" in clean(cookie) )
{
set_session(c);
local cookie_val = sub(cookie,/Cookie.*\=/,"");
c$rdp$cookie = sub(cookie_val,/\x0d\x0a.*$/,"");
schedule +5secs { rdp_tracker(c) };
}
}
event rdp_native_client_info(c: connection, keyboard_layout: count, build: count, hostname: string, product_id: string) &priority=5
{
set_session(c);
c$rdp$keyboard_layout = languages[keyboard_layout];
c$rdp$client_build = builds[build];
c$rdp$client_hostname = gsub(cat(hostname),/\\0/,"");
c$rdp$client_product_id = gsub(cat(product_id),/\\0/,"");
schedule +5secs { rdp_tracker(c) };
}
event rdp_native_authentication(c: connection, result: count) &priority=5
{
set_session(c);
c$rdp$authentication_result = results[result];
schedule +5secs { rdp_tracker(c) };
}
event rdp_native_server_security(c: connection, encryption_method: count, encryption_level: count, random: string, certificate: string) &priority=5
{
set_session(c);
c$rdp$encryption_method = encryption_methods[encryption_method];
c$rdp$encryption_level = encryption_levels[encryption_level];
schedule +5secs { rdp_tracker(c) };
}
event rdp_ntlm_client_request(c: connection, server: string) &priority=5
{
set_session(c);
ntlm = T;
if ( ! c$rdp?$server_name )
c$rdp$server_name = vector();
c$rdp$server_name[|c$rdp$server_name|] = server;
schedule +5secs { rdp_tracker(c) };
}
event rdp_ntlm_server_response(c: connection, server: string) &priority=5
{
set_session(c);
ntlm = T;
if ( ! c$rdp?$server_name )
c$rdp$server_name = vector();
c$rdp$server_name[|c$rdp$server_name|] = server;
schedule +5secs { rdp_tracker(c) };
}
event rdp_debug(c: connection, remainder: string)
{
Reporter::error(fmt("Debug RDP data generated in connection %s: %s",c$uid,remainder));
}