mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 20:48:21 +00:00
Huge updates to the RDP analyzer from Josh Liburdi.
- More data pulled into scriptland. - Logs expanded with client screen resolution and desired color depth. - Values in UTF-16 on the wire are converted to UTF-8 before being sent to scriptland. - If the RDP turns into SSL records, we now pass data that appears to be SSL to the PIA analyzer. - If RDP uses native encryption with X.509 certs we pass those certs to the files framework and the base scripts pass them forward to the X.509 analyzer. - Lots of cleanup and adjustment to fit the documented protocol a bit better. - Cleaned up the DPD signatures. - Moved to flowunit instead of datagram. - Added tests.
This commit is contained in:
parent
a63d7307c8
commit
bbedb73a45
26 changed files with 1535 additions and 346 deletions
|
@ -1,45 +1,74 @@
|
|||
type RDP_PDU(is_orig: bool) = record {
|
||||
type: uint8;
|
||||
switch: case type of {
|
||||
0x16 -> ssl_encryption: bytestring &restofdata &transient; # send to SSL analyzer in the future
|
||||
default -> native_encryption: Native_Encryption; # TPKT version
|
||||
};
|
||||
} &byteorder=bigendian;
|
||||
|
||||
######################################################################
|
||||
# Native Encryption
|
||||
######################################################################
|
||||
type TPKT(is_orig: bool) = record {
|
||||
version: uint8;
|
||||
reserved: uint8;
|
||||
tpkt_len: uint16;
|
||||
|
||||
type Native_Encryption = record {
|
||||
tpkt_reserved: uint8;
|
||||
tpkt_length: uint16;
|
||||
cotp: COTP;
|
||||
};
|
||||
# These data structures are merged together into TPKT
|
||||
# because there are packets that report incorrect
|
||||
# lengths in the tpkt length field. No clue why.
|
||||
|
||||
cotp: COTP;
|
||||
} &byteorder=bigendian &length=tpkt_len;
|
||||
|
||||
type COTP = record {
|
||||
length: uint8;
|
||||
pdu: uint8;
|
||||
switch: case pdu of {
|
||||
0xe0 -> cRequest: Client_Request;
|
||||
0xf0 -> hdr: COTP_Header;
|
||||
default -> data: bytestring &restofdata &transient;
|
||||
};
|
||||
cotp_len: uint8;
|
||||
pdu: uint8;
|
||||
# Probably should do something with this eventually.
|
||||
#cotp_crap: padding[cotp_len-2];
|
||||
switch: case pdu of {
|
||||
#0xd0 -> cConfirm: Connect_Confirm;
|
||||
0xe0 -> c_request: Client_Request;
|
||||
0xf0 -> data: DT_Data;
|
||||
|
||||
# In case we don't support the PDU we just
|
||||
# consume the rest of it and throw it away.
|
||||
default -> not_done: bytestring &restofdata &transient;
|
||||
};
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type COTP_Header = record {
|
||||
tpdu_number: uint8;
|
||||
application_defined_type: uint8; # this begins a BER encoded multiple octet variant, but can be safely skipped
|
||||
application_type: uint8; # this is value for the BER encoded octet variant above
|
||||
switch: case application_type of { # this seems to cause a binpac exception error
|
||||
0x65 -> cHeader: Client_Header; # 0x65 is a client
|
||||
0x66 -> sHeader: Server_Header; # 0x66 is a server
|
||||
default -> data: bytestring &restofdata;
|
||||
};
|
||||
type DT_Data = record {
|
||||
tpdu_number: uint8;
|
||||
# multiple octet variant of the ASN.1 type field, should handle this better.
|
||||
application_defined_type: uint8;
|
||||
application_type: uint8;
|
||||
|
||||
data: case application_type of {
|
||||
0x65 -> client: Client_Header; # 0x65 is a client
|
||||
0x66 -> server: Server_Header; # 0x66 is a server
|
||||
default -> none: empty;
|
||||
};
|
||||
} &byteorder=littleendian;
|
||||
|
||||
######################################################################
|
||||
# Data Blocks
|
||||
######################################################################
|
||||
|
||||
type Data_Header = record {
|
||||
type: uint16;
|
||||
length: uint16;
|
||||
type: uint16;
|
||||
length: uint16;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Data_Block = record {
|
||||
header: Data_Header;
|
||||
block: case header.type of {
|
||||
0xc001 -> client_core: Client_Core_Data;
|
||||
#0xc002 -> client_security: Client_Security_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;
|
||||
#0xc008 -> client_monitor_ex: Client_MonitorExtended_Data;
|
||||
#0xc00A -> client_multitrans: Client_MultiTransport_Data;
|
||||
|
||||
0x0c01 -> server_core: Server_Core_Data;
|
||||
0x0c02 -> server_security: Server_Security_Data;
|
||||
0x0c03 -> server_network: Server_Network_Data;
|
||||
#0x0c04 -> server_msgchannel: Server_MsgChannel_Data;
|
||||
#0x0c08 -> server_multitrans: Server_MultiTransport_Data;
|
||||
|
||||
default -> unhandled: bytestring &restofdata &transient;
|
||||
} &length=header.length-4;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
######################################################################
|
||||
|
@ -47,11 +76,11 @@ type Data_Header = record {
|
|||
######################################################################
|
||||
|
||||
type Client_Request = record {
|
||||
destination_reference: uint16;
|
||||
source_reference: uint16;
|
||||
flow_control: uint8;
|
||||
cookie_mstshash: RE/Cookie: mstshash\=/; # &check would be better here, but it is not implemented
|
||||
cookie_value: RE/[^\x0d]*/; # the value is anything up to \x0d
|
||||
destination_reference: uint16;
|
||||
source_reference: uint16;
|
||||
flow_control: uint8;
|
||||
cookie_mstshash: RE/Cookie: mstshash\=/;
|
||||
cookie_value: RE/[^\x0d]*/;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
|
@ -59,158 +88,173 @@ type Client_Request = record {
|
|||
######################################################################
|
||||
|
||||
type Client_Header = record {
|
||||
type_length: uint8[3]; # BER encoded long variant, can be safely skipped for now
|
||||
calling_domain_selector: ASN1OctetString;
|
||||
called_domain_selector: ASN1OctetString;
|
||||
upward_flag: ASN1Boolean;
|
||||
target_parameters: ASN1SequenceMeta;
|
||||
targ_parameters_pad: padding[target_parameters.encoding.length];
|
||||
minimum_parameters: ASN1SequenceMeta;
|
||||
min_parameters_pad: padding[minimum_parameters.encoding.length];
|
||||
maximum_parameters: ASN1SequenceMeta;
|
||||
max_parameters_pad: padding[maximum_parameters.encoding.length];
|
||||
user_data_length: uint32; # BER encoded OctetString and long variant, can be safely skipped for now
|
||||
gcc_connection_data: GCC_Client_Connection_Data;
|
||||
gcc_client_create_request: GCC_Client_Create_Request;
|
||||
core_header: Data_Header;
|
||||
core_data: Client_Core_Data;
|
||||
remainder: bytestring &restofdata &transient; # everything after core_data can be discarded
|
||||
type_length: ASN1Integer;
|
||||
calling_domain_selector: ASN1OctetString;
|
||||
called_domain_selector: ASN1OctetString;
|
||||
upward_flag: ASN1Boolean;
|
||||
target_parameters: ASN1SequenceMeta;
|
||||
targ_parameters_pad: padding[target_parameters.encoding.length];
|
||||
minimum_parameters: ASN1SequenceMeta;
|
||||
min_parameters_pad: padding[minimum_parameters.encoding.length];
|
||||
maximum_parameters: ASN1SequenceMeta;
|
||||
max_parameters_pad: padding[maximum_parameters.encoding.length];
|
||||
# BER encoded OctetString and long variant, can be safely skipped for now
|
||||
user_data_length: uint32;
|
||||
gcc_connection_data: GCC_Client_Connection_Data;
|
||||
gcc_client_create_request: GCC_Client_Create_Request;
|
||||
data_blocks: Data_Block[] &until($input.length() == 0);
|
||||
};
|
||||
|
||||
type GCC_Client_Connection_Data = record {
|
||||
key_object_length: uint16;
|
||||
key_object: uint8[key_object_length];
|
||||
connect_data_connect_pdu: uint16;
|
||||
key_object_length: uint16;
|
||||
key_object: uint8[key_object_length];
|
||||
connect_data_connect_pdu: uint16;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type GCC_Client_Create_Request = record {
|
||||
extension_bit: uint8;
|
||||
privileges: uint8;
|
||||
numeric_length: uint8;
|
||||
numeric: uint8;
|
||||
termination_method: uint8;
|
||||
number_user_data_sets: uint8;
|
||||
user_data_value_present: uint8;
|
||||
h221_nonstandard_length: uint8;
|
||||
h221_nonstandard_key: RE/Duca/; # &check would be better here, but it is not implemented
|
||||
user_data_value_length: uint16;
|
||||
};
|
||||
extension_bit: uint8;
|
||||
privileges: uint8;
|
||||
numeric_length: uint8;
|
||||
numeric: uint8;
|
||||
termination_method: uint8;
|
||||
number_user_data_sets: uint8;
|
||||
user_data_value_present: uint8;
|
||||
h221_nonstandard_length: uint8;
|
||||
h221_nonstandard_key: RE/Duca/;
|
||||
user_data_value_length: uint16;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type Client_Core_Data = record {
|
||||
version_major: uint16;
|
||||
version_minor: uint16;
|
||||
desktop_width: uint16;
|
||||
desktop_height: uint16;
|
||||
color_depth: uint16;
|
||||
sas_sequence: uint16;
|
||||
keyboard_layout: uint32;
|
||||
client_build: uint32;
|
||||
client_name: bytestring &length=32;
|
||||
keyboard_type: uint32;
|
||||
keyboard_sub: uint32;
|
||||
keyboard_function_key: uint32;
|
||||
ime_file_name: bytestring &length=64;
|
||||
post_beta_color_depth: uint16;
|
||||
product_id: uint16;
|
||||
serial_number: uint32;
|
||||
high_color_depth: uint16;
|
||||
supported_color_depth: uint16;
|
||||
early_capability_flags: uint16;
|
||||
dig_product_id: bytestring &length=64;
|
||||
};
|
||||
version_major: uint16;
|
||||
version_minor: uint16;
|
||||
desktop_width: uint16;
|
||||
desktop_height: uint16;
|
||||
color_depth: uint16;
|
||||
sas_sequence: uint16;
|
||||
keyboard_layout: uint32;
|
||||
client_build: uint32;
|
||||
client_name: bytestring &length=32;
|
||||
keyboard_type: uint32;
|
||||
keyboard_sub: uint32;
|
||||
keyboard_function_key: uint32;
|
||||
ime_file_name: bytestring &length=64;
|
||||
# Everything below here is optional and should be handled better.
|
||||
# If some of these fields aren't included it could lead to parse failure.
|
||||
post_beta2_color_depth: uint16;
|
||||
client_product_id: uint16;
|
||||
serial_number: uint32;
|
||||
high_color_depth: uint16;
|
||||
supported_color_depths: uint16;
|
||||
early_capability_flags: uint16;
|
||||
dig_product_id: bytestring &length=64;
|
||||
# There are more optional fields here but they are
|
||||
# annoying to optionally parse in binpac.
|
||||
# Documented here: https://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||
} &let {
|
||||
SUPPORT_ERRINFO_PDU: bool = early_capability_flags & 0x01;
|
||||
WANT_32BPP_SESSION: bool = early_capability_flags & 0x02;
|
||||
SUPPORT_STATUSINFO_PDU: bool = early_capability_flags & 0x04;
|
||||
STRONG_ASYMMETRIC_KEYS: bool = early_capability_flags & 0x08;
|
||||
SUPPORT_MONITOR_LAYOUT_PDU: bool = early_capability_flags & 0x40;
|
||||
SUPPORT_NETCHAR_AUTODETECT: bool = early_capability_flags & 0x80;
|
||||
SUPPORT_DYNVC_GFX_PROTOCOL: bool = early_capability_flags & 0x0100;
|
||||
SUPPORT_DYNAMIC_TIME_ZONE: bool = early_capability_flags & 0x0200;
|
||||
SUPPORT_HEARTBEAT_PDU: bool = early_capability_flags & 0x0400;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
######################################################################
|
||||
# Server MCS
|
||||
######################################################################
|
||||
|
||||
type Server_Header = record {
|
||||
type_length: uint8[3]; # BER encoded long variant, can be safely skipped for now
|
||||
connect_response_result: ASN1Enumerated;
|
||||
connect_response_called_id: ASN1Integer;
|
||||
connect_response_domain_parameters: ASN1SequenceMeta;
|
||||
domain_parameters_pad: padding[connect_response_domain_parameters.encoding.length]; # skip this data
|
||||
user_data_length: uint32; # BER encoded OctetString and long variant, can be safely skipped for now
|
||||
gcc_connection_data: GCC_Server_Connection_Data;
|
||||
gcc_create_response: GCC_Server_Create_Response;
|
||||
core_header: Data_Header;
|
||||
core_data: padding[core_header.length - 4]; # skip this data
|
||||
network_header: Data_Header;
|
||||
net_data: padding[network_header.length - 4]; # skip this data
|
||||
security_header: Data_Header;
|
||||
security_data: Server_Security_Data;
|
||||
};
|
||||
# We don't need this value, but it's ASN.1 integer in definite length
|
||||
# so I think we can skip over it.
|
||||
type_length: uint8[3];
|
||||
connect_response_result: ASN1Enumerated;
|
||||
connect_response_called_id: ASN1Integer;
|
||||
connect_response_domain_parameters: ASN1SequenceMeta;
|
||||
# Skipping over domain parameters for now.
|
||||
domain_parameters: padding[connect_response_domain_parameters.encoding.length];
|
||||
# I think this is another definite length encoded value.
|
||||
user_data_length: uint32;
|
||||
gcc_connection_data: GCC_Server_Connection_Data;
|
||||
gcc_create_response: GCC_Server_Create_Response;
|
||||
data_blocks: Data_Block[] &until($input.length() == 0);
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type GCC_Server_Connection_Data = record {
|
||||
key_object_length: uint16;
|
||||
key_object: uint8[key_object_length];
|
||||
connect_data_connect_pdu: uint8;
|
||||
key_object_length: uint16;
|
||||
key_object: uint8[key_object_length];
|
||||
connect_data_connect_pdu: uint8;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type GCC_Server_Create_Response = record {
|
||||
extension_bit: uint8;
|
||||
node_id: uint8[2];
|
||||
tag_length: uint8;
|
||||
tag: uint8;
|
||||
result: uint8;
|
||||
number_user_data_sets: uint8;
|
||||
user_data_value_present: uint8;
|
||||
h221_nonstandard_length: uint8;
|
||||
h221_nonstandard_key: RE/McDn/; # &check would be better here, but it is not implemented
|
||||
user_data_value_length: uint16;
|
||||
};
|
||||
extension_bit: uint8;
|
||||
node_id: uint16;
|
||||
tag_length: uint8;
|
||||
tag: uint8;
|
||||
result: uint8;
|
||||
number_user_data_sets: uint8;
|
||||
user_data_value_present: uint8;
|
||||
h221_nonstandard_length: uint8;
|
||||
h221_nonstandard_key: RE/McDn/;
|
||||
user_data_value_length: uint16;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type Server_Core_Data = record {
|
||||
version_major: uint16;
|
||||
version_minor: uint16;
|
||||
client_requested_protocols: uint32;
|
||||
};
|
||||
version_major: uint16;
|
||||
version_minor: uint16;
|
||||
client_requested_protocols: uint32;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Server_Network_Data = record {
|
||||
mcs_channel_id: uint16;
|
||||
channel_count: uint16;
|
||||
};
|
||||
mcs_channel_id: uint16;
|
||||
channel_count: uint16;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Server_Security_Data = record {
|
||||
encryption_method: uint32;
|
||||
encryption_level: uint32;
|
||||
server_random_length: uint32 &byteorder=littleendian;
|
||||
server_cert_length: uint32 &byteorder=littleendian;
|
||||
server_random: bytestring &length=server_random_length;
|
||||
server_certificate: Server_Certificate;
|
||||
};
|
||||
encryption_method: uint32;
|
||||
encryption_level: uint32;
|
||||
server_random_length: uint32;
|
||||
server_cert_length: uint32;
|
||||
server_random: bytestring &length=server_random_length;
|
||||
server_certificate: Server_Certificate &length=server_cert_length;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Server_Certificate = record {
|
||||
cert_type: uint8;
|
||||
switch: case cert_type of {
|
||||
0x01 -> proprietary: Server_Proprietary;
|
||||
0x02 -> ssl: SSL;
|
||||
};
|
||||
version: uint32;
|
||||
switch: case cert_type of {
|
||||
0x01 -> proprietary: Server_Proprietary;
|
||||
0x02 -> x509: X509;
|
||||
};
|
||||
} &let {
|
||||
cert_type: uint32 = version & 0x7FFFFFFF;
|
||||
permanent_issue: bool = (version & 0x80000000) == 0;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Server_Proprietary = record {
|
||||
cert_type: uint8[3]; # remainder of cert_type value
|
||||
signature_algorithm: uint32;
|
||||
key_algorithm: uint32;
|
||||
public_key_blob_type: uint16;
|
||||
public_key_blob_length: uint16;
|
||||
public_key_blob: Public_Key_Blob &length=public_key_blob_length;
|
||||
signature_blob_type: uint16;
|
||||
signature_blob_length: uint16;
|
||||
signature_blob: bytestring &length=signature_blob_length;
|
||||
};
|
||||
signature_algorithm: uint32;
|
||||
key_algorithm: uint32;
|
||||
public_key_blob_type: uint16;
|
||||
public_key_blob_length: uint16;
|
||||
public_key_blob: Public_Key_Blob &length=public_key_blob_length;
|
||||
signature_blob_type: uint16;
|
||||
signature_blob_length: uint16;
|
||||
signature_blob: bytestring &length=signature_blob_length;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type Public_Key_Blob = record {
|
||||
magic: bytestring &length=4;
|
||||
key_length: uint32;
|
||||
bit_length: uint32;
|
||||
public_exponent: uint32;
|
||||
modulus: bytestring &length=key_length;
|
||||
};
|
||||
magic: bytestring &length=4;
|
||||
key_length: uint32;
|
||||
bit_length: uint32;
|
||||
public_exponent: uint32;
|
||||
modulus: bytestring &length=key_length;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type SSL = record {
|
||||
pad1: padding[11];
|
||||
x509_cert: bytestring &restofdata &transient; # send to x509 analyzer
|
||||
};
|
||||
type X509 = record {
|
||||
pad1: padding[8];
|
||||
cert: bytestring &restofdata;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
######################################################################
|
||||
# ASN.1 Encodings
|
||||
|
@ -226,7 +270,7 @@ type ASN1EncodingMeta = record {
|
|||
len: uint8;
|
||||
more_len: bytestring &length = long_len ? len & 0x7f : 0;
|
||||
} &let {
|
||||
long_len: bool = len & 0x80;
|
||||
long_len: bool = (len & 0x80) > 0;
|
||||
length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f;
|
||||
};
|
||||
|
||||
|
@ -251,7 +295,7 @@ type ASN1Boolean = record {
|
|||
};
|
||||
|
||||
type ASN1Enumerated = record {
|
||||
encoding: ASN1Encoding;
|
||||
encoding: ASN1Encoding;
|
||||
};
|
||||
|
||||
######################################################################
|
||||
|
@ -261,7 +305,6 @@ type ASN1Enumerated = record {
|
|||
function binary_to_int64(bs: bytestring): int64
|
||||
%{
|
||||
int64 rval = 0;
|
||||
|
||||
for ( int i = 0; i < bs.length(); ++i )
|
||||
{
|
||||
uint64 byte = bs[i];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue