RDP: Add parsing and logging of channels requested by the client. Can determine capabilities requested by the client, as well as attacks such as CVE-2019-0708

This commit is contained in:
Vlad Grigorescu 2019-05-28 09:25:50 -05:00
parent d886f40728
commit 8eb14fcb83
6 changed files with 126 additions and 1 deletions

View file

@ -4261,6 +4261,39 @@ export {
ec_flags: RDP::EarlyCapabilityFlags &optional;
dig_product_id: string &optional;
};
## Name and flags for a single channel requested by the client.
type RDP::ClientChannelDef: record {
## A unique name for the channel
name: string;
## Absence of this flag indicates that this channel is
## a placeholder and that the server MUST NOT set it
## up.
initialized: bool;
## Unused, must be ignored by the server.
encrypt_rdp: bool;
## Unused, must be ignored by the server.
encrypt_sc: bool;
## Unused, must be ignored by the server.
encrypt_cs: bool;
## Channel data must be sent with high MCS priority.
pri_high: bool;
## Channel data must be sent with medium MCS priority.
pri_med: bool;
## Channel data must be sent with low MCS priority.
pri_low: bool;
## Virtual channel data must be compressed if RDP data is being compressed.
compress_rdp: bool;
## Virtual channel data must be compressed.
compress: bool;
## Ignored by the server.
show_protocol: bool;
## Channel must be persistent across remote control transactions.
persistent: bool;
};
## The list of channels requested by the client.
type RDP::ClientChannelList: vector of ClientChannelDef;
}
@load base/bif/plugins/Bro_SNMP.types.bif

View file

@ -23,6 +23,8 @@ export {
result: string &log &optional;
## Security protocol chosen by the server.
security_protocol: string &log &optional;
## The channels requested by the client
client_channels: vector of string &log &optional;
## Keyboard layout (language) of the client machine.
keyboard_layout: string &log &optional;
@ -189,6 +191,21 @@ event rdp_client_core_data(c: connection, data: RDP::ClientCoreData) &priority=5
c$rdp$requested_color_depth = RDP::high_color_depths[data$high_color_depth];
}
event rdp_client_network_data(c: connection, channels: ClientChannelList)
{
set_session(c);
if ( ! c$rdp?$client_channels )
{
c$rdp$client_channels = vector();
}
for (i in channels) {
# Remove the NULs at the end
c$rdp$client_channels[i] = gsub(channels[i]$name, /\x00+$/, "");
}
}
event rdp_gcc_server_create_response(c: connection, result: count) &priority=5
{
set_session(c);

View file

@ -26,6 +26,13 @@ event rdp_negotiation_failure%(c: connection, failure_code: count%);
## data: The data contained in the client core data structure.
event rdp_client_core_data%(c: connection, data: RDP::ClientCoreData%);
## Generated for Client Network Data (TS_UD_CS_NET) packets
##
## c: The connection record for the underlying transport-layer session/flow.
##
## channels: The channels that were requested
event rdp_client_network_data%(c: connection, channels: RDP::ClientChannelList%);
## Generated for MCS server responses.
##
## c: The connection record for the underlying transport-layer session/flow.

View file

@ -101,6 +101,44 @@ refine flow RDP_Flow += {
return true;
%}
function proc_rdp_client_network_data(cnetwork: Client_Network_Data): bool
%{
if ( ! rdp_client_network_data )
return false;
if ( ${cnetwork.channel_def_array}->size() )
{
VectorVal* channels = new VectorVal(BifType::Vector::RDP::ClientChannelList);
for( uint i = 0; i < ${cnetwork.channel_def_array}->size(); ++i )
{
RecordVal* channel_def = new RecordVal(BifType::Record::RDP::ClientChannelDef);
channel_def->Assign(0, bytestring_to_val(${cnetwork.channel_def_array[i].name}));
channel_def->Assign(1, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_INITIALIZED}));
channel_def->Assign(2, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_RDP}));
channel_def->Assign(3, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_SC}));
channel_def->Assign(4, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_CS}));
channel_def->Assign(5, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_HIGH}));
channel_def->Assign(6, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_MED}));
channel_def->Assign(7, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_LOW}));
channel_def->Assign(8, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS_RDP}));
channel_def->Assign(9, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS}));
channel_def->Assign(10, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_SHOW_PROTOCOL}));
channel_def->Assign(11, val_mgr->GetBool(${cnetwork.channel_def_array[i].REMOTE_CONTROL_PERSISTENT}));
channels->Assign(channels->Size(), channel_def);
}
BifEvent::generate_rdp_client_network_data(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
channels);
}
return true;
%}
function proc_rdp_server_security(ssd: Server_Security_Data): bool
%{
connection()->bro_analyzer()->ProtocolConfirmation();
@ -165,6 +203,10 @@ refine typeattr Client_Core_Data += &let {
proc: bool = $context.flow.proc_rdp_client_core_data(this);
};
refine typeattr Client_Network_Data += &let {
proc: bool = $context.flow.proc_rdp_client_network_data(this);
};
refine typeattr GCC_Server_Create_Response += &let {
proc: bool = $context.flow.proc_rdp_gcc_server_create_response(this);
};
@ -180,3 +222,4 @@ refine typeattr Server_Certificate += &let {
refine typeattr X509_Cert_Data += &let {
proc: bool = $context.flow.proc_x509_cert_data(this);
};

View file

@ -53,7 +53,7 @@ type Data_Block = record {
block: case header.type of {
0xc001 -> client_core: Client_Core_Data;
#0xc002 -> client_security: Client_Security_Data;
#0xc003 -> client_network: Client_Network_Data;
0xc003 -> client_network: Client_Network_Data;
#0xc004 -> client_cluster: Client_Cluster_Data;
#0xc005 -> client_monitor: Client_Monitor_Data;
#0xc006 -> client_msgchannel: Client_MsgChannel_Data;
@ -220,6 +220,28 @@ type Client_Core_Data = record {
SUPPORT_HEARTBEAT_PDU: bool = early_capability_flags & 0x0400;
} &byteorder=littleendian;
type Client_Network_Data = record {
channel_count: uint32;
channel_def_array: Client_Channel_Def[channel_count];
} &byteorder=littleendian;
type Client_Channel_Def = record {
name: bytestring &length=8;
options: uint32;
} &let {
REMOTE_CONTROL_PERSISTENT: bool = options & 0x00100000;
CHANNEL_OPTION_SHOW_PROTOCOL: bool = options & 0x00200000;
CHANNEL_OPTION_COMPRESS: bool = options & 0x00400000;
CHANNEL_OPTION_COMPRESS_RDP: bool = options & 0x00800000;
CHANNEL_OPTION_PRI_LOW: bool = options & 0x02000000;
CHANNEL_OPTION_PRI_MED: bool = options & 0x04000000;
CHANNEL_OPTION_PRI_HIGH: bool = options & 0x08000000;
CHANNEL_OPTION_ENCRYPT_CS: bool = options & 0x10000000;
CHANNEL_OPTION_ENCRYPT_SC: bool = options & 0x20000000;
CHANNEL_OPTION_ENCRYPT_RDP: bool = options & 0x40000000;
CHANNEL_OPTION_INITIALIZED: bool = options & 0x80000000;
} &byteorder=littleendian;
######################################################################
# Server MCS
######################################################################

View file

@ -3,3 +3,6 @@ module RDP;
type EarlyCapabilityFlags: record;
type ClientCoreData: record;
type ClientChannelList: vector;
type ClientChannelDef: record;