diff --git a/scripts/base/protocols/rdp/main.bro b/scripts/base/protocols/rdp/main.bro index 94aa26b6ec..0369cad3d4 100644 --- a/scripts/base/protocols/rdp/main.bro +++ b/scripts/base/protocols/rdp/main.bro @@ -14,7 +14,7 @@ export { id: conn_id &log; ## Cookie value used by the client machine. ## This is typically a username. - cookie: string &log &optional; + cookie: string &log &optional; ## Keyboard layout (language) of the client machine. keyboard_layout: string &log &optional; ## RDP client version used by the client machine. @@ -23,11 +23,8 @@ export { 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; + ## GCC result for the connection. This value is extracted from the payload for native encryption. + result: string &log &optional; ## Encryption level of the connection. encryption_level: string &log &optional; ## Encryption method of the connection. @@ -36,12 +33,6 @@ export { 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); @@ -66,17 +57,6 @@ function rdp_done(c: connection, done: bool) { 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); @@ -110,7 +90,7 @@ event rdp_tracker(c: connection) } } - # schedule the event to run again if necessary + # Schedule the event to run again if necessary schedule +5secs { rdp_tracker(c) }; } @@ -130,7 +110,7 @@ event connection_state_remove(c: connection) &priority=-5 rdp_done(c,T); } -event rdp_native_client_request(c: connection, cookie: string) &priority=5 +event rdp_client_request(c: connection, cookie: string) &priority=5 { if ( "Cookie" in clean(cookie) ) { @@ -142,7 +122,7 @@ event rdp_native_client_request(c: connection, cookie: string) &priority=5 } } -event rdp_native_client_info(c: connection, keyboard_layout: count, build: count, hostname: string, product_id: string) &priority=5 +event rdp_client_data(c: connection, keyboard_layout: count, build: count, hostname: string, product_id: string) &priority=5 { set_session(c); c$rdp$keyboard_layout = languages[keyboard_layout]; @@ -153,15 +133,15 @@ event rdp_native_client_info(c: connection, keyboard_layout: count, build: count schedule +5secs { rdp_tracker(c) }; } -event rdp_native_authentication(c: connection, result: count) &priority=5 +event rdp_result(c: connection, result: count) &priority=5 { set_session(c); - c$rdp$authentication_result = results[result]; + c$rdp$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 +event rdp_server_security(c: connection, encryption_method: count, encryption_level: count) &priority=5 { set_session(c); c$rdp$encryption_method = encryption_methods[encryption_method]; @@ -169,32 +149,3 @@ event rdp_native_server_security(c: connection, encryption_method: count, encryp 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)); - } diff --git a/src/analyzer/protocol/rdp/RDP.cc b/src/analyzer/protocol/rdp/RDP.cc index 70cad773fe..aca184d844 100644 --- a/src/analyzer/protocol/rdp/RDP.cc +++ b/src/analyzer/protocol/rdp/RDP.cc @@ -1,9 +1,6 @@ #include "RDP.h" - #include "analyzer/protocol/tcp/TCP_Reassembler.h" - #include "Reporter.h" - #include "events.bif.h" using namespace analyzer::rdp; diff --git a/src/analyzer/protocol/rdp/events.bif b/src/analyzer/protocol/rdp/events.bif index dad76f801b..65917e98be 100644 --- a/src/analyzer/protocol/rdp/events.bif +++ b/src/analyzer/protocol/rdp/events.bif @@ -1,23 +1,9 @@ -## Generated for client-to-server RDP requests when NTLM authentication is used. -## -## c: The connection record for the underlying transport-layer session/flow. -## -## server: The RDP server name requested by the client. -event rdp_ntlm_client_request%(c: connection, server: string%); - -## Generated for server-to-client RDP responses when NTLM authentication is used. -## -## c: The connection record for the underlying transport-layer session/flow. -## -## server: The RDP server name responsed by the server. -event rdp_ntlm_server_response%(c: connection, server: string%); - ## Generated for X.224 client requests when native RDP encryption is used. ## ## c: The connection record for the underlying transport-layer session/flow. ## ## cookie: The cookie included in the request. -event rdp_native_client_request%(c: connection, cookie: string%); +event rdp_client_request%(c: connection, cookie: string%); ## Generated for MCS client requests when native RDP encryption is used. ## @@ -30,14 +16,14 @@ event rdp_native_client_request%(c: connection, cookie: string%); ## hostname: The hostname of the client machine (optional). ## ## product_id: The product ID of the client machine (optional). -event rdp_native_client_info%(c: connection, keyboard_layout: count, build: count, hostname: string, product_id: string%); +event rdp_client_data%(c: connection, keyboard_layout: count, build: count, hostname: string, product_id: string%); ## Generated for MCS server responses when native RDP encryption is used. ## ## c: The connection record for the underlying transport-layer session/flow. ## ## result: The 8-bit integer representing the GCC Conference Create Response result. -event rdp_native_authentication%(c: connection, result: count%); +event rdp_result%(c: connection, result: count%); ## Generated for MCS server responses when native RDP encryption is used. ## @@ -46,15 +32,4 @@ event rdp_native_authentication%(c: connection, result: count%); ## encryption_method: The 32-bit integer representing the encryption method used in the connection. ## ## encryption_level: The 32-bit integer representing the encryption level used in the connection. -## -## random: The random value used to derive session keys (optional). -## -## certificate: The certificate containing the server's public key information. -event rdp_native_server_security%(c: connection, encryption_method: count, encryption_level: count, random: string, certificate: string%); - -## Generated for unknown elements in RDP connections. Used for debugging and development purposes only. -## -## c: The connection record for the underlying transport-layer session/flow. -## -## remainder: The data to be debugged. -event rdp_debug%(c: connection, remainder: string%); +event rdp_server_security%(c: connection, encryption_method: count, encryption_level: count%); diff --git a/src/analyzer/protocol/rdp/rdp-analyzer.pac b/src/analyzer/protocol/rdp/rdp-analyzer.pac index f95ff9f589..04d64409bd 100644 --- a/src/analyzer/protocol/rdp/rdp-analyzer.pac +++ b/src/analyzer/protocol/rdp/rdp-analyzer.pac @@ -1,101 +1,59 @@ refine flow RDP_Flow += { - function proc_rdp_debug(debug: Debug): bool - %{ - BifEvent::generate_rdp_debug(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - bytestring_to_val(${debug.remainder})); + function proc_rdp_client_request(client_request: ClientRequest): bool + %{ + BifEvent::generate_rdp_client_request(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + bytestring_to_val(${client_request.cookie})); return true; %} - function proc_rdp_ntlm_server_response(ntlm_server: NTLMServerResponse): bool + function proc_rdp_result(gcc_response: GCC_Server_CreateResponse): bool %{ - BifEvent::generate_rdp_ntlm_server_response(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - bytestring_to_val(${ntlm_server.server_name})); - - return true; - %} - - function proc_rdp_ntlm_client_request(ntlm_client: NTLMClientRequest): bool - %{ - BifEvent::generate_rdp_ntlm_client_request(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - bytestring_to_val(${ntlm_client.server_name})); - - return true; - %} - - function proc_rdp_native_client_request(client_request: ClientRequest): bool - %{ - BifEvent::generate_rdp_native_client_request(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - bytestring_to_val(${client_request.cookie})); - - return true; - %} - - - function proc_rdp_native_authentication(gcc_response: GCC_Server_CreateResponse): bool - %{ - BifEvent::generate_rdp_native_authentication(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - ${gcc_response.result}); + BifEvent::generate_rdp_result(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + ${gcc_response.result}); return true; %} - function proc_rdp_native_client_info(ccore: ClientCore): bool + function proc_rdp_client_data(ccore: ClientCore): bool %{ - BifEvent::generate_rdp_native_client_info(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - ${ccore.keyboard_layout}, - ${ccore.client_build}, - bytestring_to_val(${ccore.client_name}), - bytestring_to_val(${ccore.dig_product_id})); + BifEvent::generate_rdp_client_data(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + ${ccore.keyboard_layout}, + ${ccore.client_build}, + bytestring_to_val(${ccore.client_name}), + bytestring_to_val(${ccore.dig_product_id})); return true; %} - function proc_rdp_native_server_security(ssd: ServerSecurityData): bool + function proc_rdp_server_security(ssd: ServerSecurityData): bool %{ - BifEvent::generate_rdp_native_server_security(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - ${ssd.encryption_method}, - ${ssd.encryption_level}, - bytestring_to_val(${ssd.server_random}), - bytestring_to_val(${ssd.server_certificate})); + BifEvent::generate_rdp_server_security(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + ${ssd.encryption_method}, + ${ssd.encryption_level}); return true; %} }; -refine typeattr Debug += &let { - proc: bool = $context.flow.proc_rdp_debug(this); -}; - -refine typeattr NTLMServerResponse += &let { - proc: bool = $context.flow.proc_rdp_ntlm_server_response(this); -}; - -refine typeattr NTLMClientRequest += &let { - proc: bool = $context.flow.proc_rdp_ntlm_client_request(this); -}; - refine typeattr ClientRequest += &let { - proc: bool = $context.flow.proc_rdp_native_client_request(this); + proc: bool = $context.flow.proc_rdp_client_request(this); }; refine typeattr ClientCore += &let { - proc: bool = $context.flow.proc_rdp_native_client_info(this); + proc: bool = $context.flow.proc_rdp_client_data(this); }; refine typeattr GCC_Server_CreateResponse += &let { - proc: bool = $context.flow.proc_rdp_native_authentication(this); + proc: bool = $context.flow.proc_rdp_result(this); }; refine typeattr ServerSecurityData += &let { - proc: bool = $context.flow.proc_rdp_native_server_security(this); + proc: bool = $context.flow.proc_rdp_server_security(this); }; diff --git a/src/analyzer/protocol/rdp/rdp-protocol.pac b/src/analyzer/protocol/rdp/rdp-protocol.pac index ea68040314..d9546dbdc9 100644 --- a/src/analyzer/protocol/rdp/rdp-protocol.pac +++ b/src/analyzer/protocol/rdp/rdp-protocol.pac @@ -1,8 +1,8 @@ type RDP_PDU(is_orig: bool) = record { - type: uint16; + type: uint8; switch: case type of { - 0x1603 -> ntlm_authentication: NTLMAuthentication; # NTLM authentication appears to be flagged by this 16-bit integer - default -> native_encryption: NativeEncryption; # assume native encryption, this should be the value of the TPKT version + 0x16 -> ssl_encryption: bytestring &restofdata &transient; # send to SSL analyzer in the future + default -> native_encryption: NativeEncryption; # TPKT version }; } &byteorder=bigendian; @@ -11,8 +11,9 @@ type RDP_PDU(is_orig: bool) = record { ###################################################################### type NativeEncryption = record { - pad: padding[2]; # remaining TPKT values - cotp: COTP; + tpkt_reserved: uint8; + tpkt_length: uint16; + cotp: COTP; }; type COTP = record { @@ -20,12 +21,12 @@ type COTP = record { pdu: uint8; switch: case pdu of { 0xe0 -> cRequest: ClientRequest; - 0xf0 -> hdr: Header; + 0xf0 -> hdr: COTPHeader; default -> data: bytestring &restofdata &transient; }; } &byteorder=littleendian; -type Header = record { +type COTPHeader = 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 @@ -36,6 +37,11 @@ type Header = record { }; } &byteorder=littleendian; +type DataHdr = record { + type: uint16; + length: uint16; +} &byteorder=littleendian; + ###################################################################### # Client X.224 ###################################################################### @@ -130,7 +136,7 @@ type ServerHeader = record { network_header: DataHdr; net_data: padding[network_header.length - 4]; # skip this data security_header: DataHdr; - security_data: ServerSecurityData; # there is some issue / bug where the length reported by the security header overruns the end of the packet + security_data: ServerSecurityData; }; type GCC_Server_ConnectionData = record { @@ -152,11 +158,6 @@ type GCC_Server_CreateResponse = record { user_data_value_length: uint16; }; -type DataHdr = record { - type: uint16; - length: uint16; -} &byteorder=littleendian; - type ServerCoreData = record { version_major: uint16; version_minor: uint16; @@ -174,83 +175,40 @@ type ServerSecurityData = record { server_random_length: uint32 &byteorder=littleendian; server_cert_length: uint32 &byteorder=littleendian; server_random: bytestring &length=server_random_length; - server_certificate: bytestring &length=server_cert_length-8; # arbitrarily cutting off 8 chars so the certificate doesn't overrun the end of the packet + server_certificate: ServerCertificate; }; -###################################################################### -# NTLM Authentication -###################################################################### - -type NTLMAuthentication = record { - type: uint16; - switch: case type of { # there may be further type bytes that need to be added to this switch - 0x0100 -> client_request: NTLMClientRequest; - 0x0300 -> client_request2: NTLMClientRequest; - 0x0103 -> server_response: NTLMServerResponse; - 0x0104 -> server_response2: NTLMServerResponse; - default -> data: bytestring &restofdata &transient; +type ServerCertificate = record { + cert_type: uint8; + switch: case cert_type of { + 0x01 -> proprietary: ServerProprietary; + 0x02 -> ssl: SSL; }; +} &byteorder=littleendian; + +type ServerProprietary = 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: PublicKeyBlob &length=public_key_blob_length; + signature_blob_type: uint16; + signature_blob_length: uint16; + signature_blob: bytestring &length=signature_blob_length; }; -###################################################################### -# NTLM Client -###################################################################### - -type NTLMClientRequest = record { - payload_length: uint8; # total payload length - pad1: padding[3]; # arbitrary 3 bytes - remaining_length1: uint8; # remaining length of the payload - pad2: padding[36]; # arbitrary 36 bytes - unknown_length: uint8; # an unknown length value - unknown_value1: padding[unknown_length]; # arbitrary padding for the length value above - pad3: padding[3]; # arbitrary 3 bytes - remainder_length2: uint8; # remaining length of the payload - unknown: uint8; # this unknown field affects the length between here and the beginning of the requested server name - switch: case unknown of { - 0x00 -> case1: uint8[7]; # jump 7 bytes - 0xff -> case2: uint8[12]; # jump 12 bytes - default -> case3: Debug; # debug if an unknown value is seen - }; - server_length: uint8; - server_name: bytestring &length=server_length; - data: bytestring &restofdata &transient; +type PublicKeyBlob = record { + magic: bytestring &length=4; + key_length: uint32; + bit_length: uint32; + public_exponent: uint32; + modulus: bytestring &length=key_length; }; -###################################################################### -# NTLM Server -###################################################################### - -type NTLMServerResponse = record { - unknown_value1: uint8; # 1 variable byte - unknown_value2: uint8[3]; # 3 bytes that may be static - unknown_value3: uint8; # 1 variable byte - unknown_value4: uint8[2]; # 2 bytes that may be static - unknown_length1: uint8; # an unknown length value - pad1: padding[unknown_length1]; # arbitrary padding for the length value above - unknown_value5: uint8[3]; # 3 bytes that may be static - unknown_value6: uint8; # 1 variable byte - unknown_value7: uint8[3]; # 3 bytes that may be static - unknown_value8: uint8; # 1 variable byte - unknown_value9: uint8[7]; # 7 bytes that may be static - unknown_value10: uint8[16]; # 16 bytes that may be static - unknown_value11: uint8[16]; # 16 bytes that may be static - unknown_value12: uint8; # 1 variable byte - unknown_value13: uint8; # 1 byte that may be static - unknown_value14: uint8; # 1 variable byte - unknown_value15: uint8; # 1 byte that may be static - unknown_value16: uint8; # 1 variable byte - unknown_value17: uint8[6]; # 6 bytes that may be static - server_length: uint8; # length of server name - server_name: bytestring &length=server_length; # server name - data: bytestring &restofdata &transient; -} &byteorder=bigendian; - -###################################################################### -# Debugging -###################################################################### - -type Debug = record { - remainder: bytestring &restofdata; +type SSL = record { + pad1: padding[11]; + x509_cert: bytestring &restofdata &transient; # send to x509 analyzer }; ###################################################################### @@ -311,3 +269,4 @@ function binary_to_int64(bs: bytestring): int64 return rval; %} +