From 4330b7922c236140b9cc66bb2d22d6cbbd8fbda3 Mon Sep 17 00:00:00 2001 From: mauro Date: Mon, 4 Feb 2019 17:05:50 +0100 Subject: [PATCH] smb3.1.1 additions to negotiate-response command --- aux/broker | 2 +- doc | 2 +- scripts/base/init-bare.bro | 49 +++++++++ src/3rdparty | 2 +- .../protocol/smb/smb2-com-negotiate.pac | 103 ++++++++++++++---- src/analyzer/protocol/smb/smb2-protocol.pac | 42 +++++++ src/analyzer/protocol/smb/types.bif | 7 +- 7 files changed, 180 insertions(+), 27 deletions(-) diff --git a/aux/broker b/aux/broker index bf734622dc..c7b1dfd38e 160000 --- a/aux/broker +++ b/aux/broker @@ -1 +1 @@ -Subproject commit bf734622dceaafaf7a481185efd22bd7cc805f9b +Subproject commit c7b1dfd38ec6c42729f8c462eef6457a8dd948b6 diff --git a/doc b/doc index 5acafa0d34..c0092fab7b 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 5acafa0d340a6f4096dccbe69b8fb62d7c9ce87f +Subproject commit c0092fab7b28c029eddb6b9b654f6096d8e4456a diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 600a507d4f..0a23ed4e13 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3226,6 +3226,49 @@ export { attrs : SMB2::FileAttrs; }; + ## Preauthentication information as defined in SMB v. 3.1.1 + ## + ## For more information, see MS-SMB2:2.3.1.1 + ## + type SMB2::preauth: record { + ## the number of hash algorithms + hash_alg_count : count; + ## the salt length + salt_length : count; + ## an array of hash algorithms (counts) + hash_alg : vector of count; + ## the salt + salt : string; + }; + + ## Encryption information as defined in SMB v. 3.1.1 + ## + ## For more information, see MS-SMB2:2.3.1.2 + ## + type SMB2::encryption: record { + ## the number of ciphers + cipher_count : count; + ## an array of ciphers + ciphers : vector of count; + }; + + ## The context type information as defined in SMB v. 3.1.1 + ## + ## For more information, see MS-SMB2:2.3.1 + ## + type SMB2::context_value: record { + ## specifies the type of context (preauth or encryption) + context_type : count; + ## the length in byte of the data field + data_length : count; + ## the preauthentication information + preauth_info : SMB2::preauth; + ## the encryption information + encryption_info : SMB2::encryption; + }; + + type SMB2::context_values: vector of context_value; + ## The response to an SMB2 *negotiate* request, which is used by tghe client to notify the server ## what dialects of the SMB2 protocol the client understands. ## @@ -3244,6 +3287,11 @@ export { system_time : time; ## The SMB2 server start time. server_start_time : time; + + ## The number of negotiate context values in SMB v. 3.1.1, otherwise reserved to 0 + negotiate_context_count : count; + ## An array of context values in SMB v. 3.1.1 + negotiate_context_values : context_values; }; ## The request sent by the client to request a new authenticated session @@ -3327,6 +3375,7 @@ export { ## The action taken in establishing the open. create_action : count; }; + } module GLOBAL; diff --git a/src/3rdparty b/src/3rdparty index 6e93c5546a..b822eeed58 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 6e93c5546a4770d513fb57213d7b29e39e12bf4d +Subproject commit b822eeed58c4a1ee3781f1f8c8a19fd590dc4a04 diff --git a/src/analyzer/protocol/smb/smb2-com-negotiate.pac b/src/analyzer/protocol/smb/smb2-com-negotiate.pac index 39311e4ee3..f03422c212 100644 --- a/src/analyzer/protocol/smb/smb2-com-negotiate.pac +++ b/src/analyzer/protocol/smb/smb2-com-negotiate.pac @@ -1,3 +1,19 @@ +enum smb3_capabilities { + SMB2_GLOBAL_CAP_DFS = 0, + SMB2_GLOBAL_CAP_LEASING = 2, + SMB2_GLOBAL_CAP_LARGE_MTU = 4, + SMB2_GLOBAL_CAP_MULTI_CHANNEL = 8, + SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 10, + SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 20, + SMB2_GLOBAL_CAP_ENCRYPTION = 40, +}; + +enum smb3_context_type { + SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001, + SMB2_ENCRYPTION_CAPABILITIES = 0x0002, +}; + + refine connection SMB_Conn += { function proc_smb2_negotiate_request(h: SMB2_Header, val: SMB2_negotiate_request) : bool @@ -25,9 +41,21 @@ refine connection SMB_Conn += { nr->Assign(0, val_mgr->GetCount(${val.dialect_revision})); nr->Assign(1, val_mgr->GetCount(${val.security_mode})); - nr->Assign(2, BuildSMB2GUID(${val.server_guid})), + nr->Assign(2, BuildSMB2GUID(${val.server_guid})); nr->Assign(3, filetime2brotime(${val.system_time})); nr->Assign(4, filetime2brotime(${val.server_start_time})); + nr->Assign(5, val_mgr->GetCount(${val.negotiate_context_count})); + + VectorVal* cv = new VectorVal(BifType::Vector::SMB2::context_values); + int num_context_values = ${val.negotiate_context_count}; + if (num_context_values > 0) // check if there are context_values, i.e. SMB v.3.1.1 + for ( int i = 0; i < num_context_values; ++i ) + { + cv->Assign(i, BuildSMB2ContextVal(${val.smb3_ncl[i]})); + } + + nr->Assign(6, cv); // empty vector if not SMB v.3.1.1 + BifEvent::generate_smb2_negotiate_response(bro_analyzer(), bro_analyzer()->Conn(), BuildSMB2HeaderVal(h), nr); @@ -37,35 +65,64 @@ refine connection SMB_Conn += { %} }; +type SMB3_preauth_integrity_capabilities = record { + hash_alg_count : uint16; + salt_length : uint16; + hash_alg : uint16[hash_alg_count]; + salt : bytestring &length = salt_length; #TODO is a bytestring ok for this field? +}; + +type SMB3_encryption_capabilities = record { + cipher_count : uint16; + ciphers : uint16[cipher_count]; +}; + +type SMB3_negotiate_context_values = record { + context_type : uint16; # specify the type of context + data_length : uint16; # the length of the data field + reserved : uint32; # ignored + data : case context_type of { + SMB2_PREAUTH_INTEGRITY_CAPABILITIES -> preauth_integrity_capabilities : SMB3_preauth_integrity_capabilities; + SMB2_ENCRYPTION_CAPABILITIES -> encryption_capabilities : SMB3_encryption_capabilities; + }; + pad : padding align 4; +}; + type SMB2_negotiate_request(header: SMB2_Header) = record { - structure_size : uint16; # client MUST set this to 36 - dialect_count : uint16; # must be > 0 - security_mode : uint16; # there is a list of required modes - reserved : padding[2]; # must be set to 0 - capabilities : uint32; # must be set to 0 - client_guid : SMB2_guid; # guid if client implements SMB 2.1 dialect, otherwise set to 0 - client_start_time : SMB_timestamp; # must be set to 0 + structure_size : uint16; # client MUST set this to 36 + dialect_count : uint16; # must be > 0 + security_mode : uint16; # there is a list of required modes + reserved : padding[2]; # must be set to 0 + capabilities : uint32; # must be set to 0 if SMB 2.x, otherwise if SMB 3.x one of enum smb2_capabilities + client_guid : SMB2_guid; # guid if client implements SMB 2.1 dialect, otherwise set to 0 + client_start_time : SMB_timestamp; dialects : uint16[dialect_count]; } &byteorder=littleendian, &let { proc : bool = $context.connection.proc_smb2_negotiate_request(header, this); }; type SMB2_negotiate_response(header: SMB2_Header) = record { - structure_size : uint16; - security_mode : uint16; - dialect_revision : uint16; - reserved : padding[2]; - server_guid : SMB2_guid; - capabilities : uint32; - max_transact_size : uint32; - max_read_size : uint32; - max_write_size : uint32; - system_time : SMB_timestamp; - server_start_time : SMB_timestamp; - security_offset : uint16; - security_length : uint16; - pad1 : padding to security_offset - header.head_length; - security_blob : bytestring &length=security_length; + structure_size : uint16; + security_mode : uint16; + dialect_revision : uint16; + negotiate_context_count : uint16; # reserved to 0 if not smb 3.1.1 + server_guid : SMB2_guid; + capabilities : uint32; + max_transact_size : uint32; + max_read_size : uint32; + max_write_size : uint32; + system_time : SMB_timestamp; + server_start_time : SMB_timestamp; + security_offset : uint16; + security_length : uint16; + negotiate_context_offset : uint32; + pad1 : padding to security_offset - header.head_length; + security_blob : bytestring &length=security_length; + pad2 : padding align 8; # optional padding + negotiate_context_list : case dialect_revision of { # check the dialect + 0x0311 -> smb3_ncl: SMB3_negotiate_context_values[negotiate_context_count]; # if it is v. 3.1.1 + default -> unknown : empty; # any other version + }; } &byteorder=littleendian, &let { proc : bool = $context.connection.proc_smb2_negotiate_response(header, this); gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false); diff --git a/src/analyzer/protocol/smb/smb2-protocol.pac b/src/analyzer/protocol/smb/smb2-protocol.pac index f5095a66d1..7579c09dff 100644 --- a/src/analyzer/protocol/smb/smb2-protocol.pac +++ b/src/analyzer/protocol/smb/smb2-protocol.pac @@ -100,6 +100,48 @@ refine connection SMB_Conn += { std::map smb2_request_tree_id; %} + function BuildSMB2ContextVal(ncv: SMB3_negotiate_context_values): BroVal + %{ + RecordVal* r = new RecordVal(BifType::Record::SMB2::context_value); + + r->Assign(0, val_mgr->GetCount(${ncv.context_type})); + r->Assign(1, val_mgr->GetCount(${ncv.data_length})); + + RecordVal* rpreauth = new RecordVal(BifType::Record::SMB2::preauth); + RecordVal* rencr = new RecordVal(BifType::Record::SMB2::encryption); + if (${ncv.context_type} == 1) // it is a preauth context type + { + rpreauth->Assign(0, val_mgr->GetCount(${ncv.preauth_integrity_capabilities.hash_alg_count})); + rpreauth->Assign(1, val_mgr->GetCount(${ncv.preauth_integrity_capabilities.salt_length})); + + VectorVal* ha = new VectorVal(internal_type("index_vec")->AsVectorType()); + for ( int i = 0; i < (${ncv.preauth_integrity_capabilities.hash_alg_count}); ++i ) + { + ha->Assign(i, val_mgr->GetCount(${ncv.preauth_integrity_capabilities.hash_alg[i]})); + } + + rpreauth->Assign(2, ha); + rpreauth->Assign(3, bytestring_to_val(${ncv.preauth_integrity_capabilities.salt})); + } + else if (${ncv.context_type} == 2) // it is a encryption context type + { + rencr->Assign(0, val_mgr->GetCount(${ncv.encryption_capabilities.cipher_count})); + + VectorVal* c = new VectorVal(internal_type("index_vec")->AsVectorType()); + for ( int i = 0; i < (${ncv.encryption_capabilities.cipher_count}); ++i ) + { + c->Assign(i, val_mgr->GetCount(${ncv.encryption_capabilities.ciphers[i]})); + } + + rencr->Assign(1, c); + } + + r->Assign(2, rpreauth); + r->Assign(3, rencr); + + return r; + %} + function BuildSMB2HeaderVal(hdr: SMB2_Header): BroVal %{ RecordVal* r = new RecordVal(BifType::Record::SMB2::Header); diff --git a/src/analyzer/protocol/smb/types.bif b/src/analyzer/protocol/smb/types.bif index 4714046a62..9a037ddba6 100644 --- a/src/analyzer/protocol/smb/types.bif +++ b/src/analyzer/protocol/smb/types.bif @@ -4,4 +4,9 @@ type SMB1::Header: record; type SMB2::Header: record; type SMB2::GUID: record; -type SMB2::FileAttrs: record; \ No newline at end of file +type SMB2::FileAttrs: record; + +type SMB2::preauth: record; +type SMB2::encryption: record; +type SMB2::context_value: record; +type SMB2::context_values: vector;