mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
200 lines
5.8 KiB
Text
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));
|
|
}
|