diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index bdc3a92a27..464cee886f 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2315,6 +2315,140 @@ type ntp_msg: record { }; +module NTLM; + +export { + type NTLM::Version: record { + ## The major version of the Windows operating system in use + major : count; + ## The minor version of the Windows operating system in use + minor : count; + ## The build number of the Windows operating system in use + build : count; + ## The current revision of NTLMSSP in use + ntlmssp : count; + }; + + type NTLM::NegotiateFlags: record { + ## If set, requires 56-bit encryption + negotiate_56 : bool; + ## If set, requests an explicit key exchange + negotiate_key_exch : bool; + ## If set, requests 128-bit session key negotiation + negotiate_128 : bool; + ## If set, requests the protocol version number + negotiate_version : bool; + ## If set, indicates that the TargetInfo fields in the + ## CHALLENGE_MESSAGE are populated + negotiate_target_info : bool; + ## If set, requests the usage of the LMOWF function + request_non_nt_session_key : bool; + ## If set, requests and identify level token + negotiate_identify : bool; + ## If set, requests usage of NTLM v2 session security + ## Note: NTML v2 session security is actually NTLM v1 + negotiate_extended_sessionsecurity : bool; + ## If set, TargetName must be a server name + target_type_server : bool; + ## If set, TargetName must be a domain name + target_type_domain : bool; + + ## If set, requests the presence of a signature block + ## on all messages + negotiate_always_sign : bool; + ## If set, the workstation name is provided + negotiate_oem_workstation_supplied : bool; + ## If set, the domain name is provided + negotiate_oem_domain_supplied : bool; + ## If set, the connection should be anonymous + negotiate_anonymous_connection : bool; + ## If set, requests usage of NTLM v1 + negotiate_ntlm : bool; + + ## If set, requests LAN Manager session key computation + negotiate_lm_key : bool; + ## If set, requests connectionless authentication + negotiate_datagram : bool; + ## If set, requests session key negotiation for message + ## confidentiality + negotiate_seal : bool; + ## If set, requests session key negotiation for message + ## signatures + negotiate_sign : bool; + ## If set, the TargetName field is present + request_target : bool; + + ## If set, requests OEM character set encoding + negotiate_oem : bool; + ## If set, requests Unicode character set encoding + negotiate_unicode : bool; + }; + + type NTLM::Negotiate: record { + ## The negotiate flags + flags : NTLM::NegotiateFlags; + ## The domain name of the client, if known + domain_name : string &optional; + ## The machine name of the client, if known + workstation : string &optional; + ## The Windows version information, if supplied + version : NTLM::Version &optional; + }; + + type NTLM::AVs: record { + ## The server's NetBIOS computer name + nb_computer_name : string; + ## The server's NetBIOS domain name + nb_domain_name : string; + ## The FQDN of the computer + dns_computer_name : string &optional; + ## The FQDN of the domain + dns_domain_name : string &optional; + ## The FQDN of the forest + dns_tree_name : string &optional; + + ## Indicates to the client that the account + ## authentication is constrained + constrained_auth : bool &optional; + ## The associated timestamp, if present + timestamp : time &optional; + ## Indicates that the client is providing + ## a machine ID created at computer startup to + ## identify the calling machine + single_host_id : count &optional; + + ## The SPN of the target server + target_name : string &optional; + }; + + type NTLM::Challenge: record { + ## The negotiate flags + flags : NTLM::NegotiateFlags; + ## The server authentication realm. If the server is + ## domain-joined, the name of the domain. Otherwise + ## the server name. See flags.target_type_domain + ## and flags.target_type_server + target_name : string &optional; + ## The Windows version information, if supplied + version : NTLM::Version &optional; + ## Attribute-value pairs specified by the server + target_info : NTLM::AVs &optional; + }; + + type NTLM::Authenticate: record { + ## The negotiate flags + flags : NTLM::NegotiateFlags; + ## The domain or computer name hosting the account + domain_name : string; + ## The name of the user to be authenticated. + user_name : string; + ## The name of the computer to which the user was logged on. + workstation : string; + ## The Windows version information, if supplied + version : NTLM::Version &optional; + }; +} + module SMB; export { @@ -2325,138 +2459,6 @@ export { created : time &log; changed : time &log; } &log; - - type SMB::NTLMVersion: record { - ## The major version of the Windows operating system in use - major : count; - ## The minor version of the Windows operating system in use - minor : count; - ## The build number of the Windows operating system in use - build : count; - ## The current revision of NTLMSSP in use - ntlmssp : count; - }; - - type SMB::NTLMNegotiateFlags: record { - ## If set, requires 56-bit encryption - negotiate_56 : bool; - ## If set, requests an explicit key exchange - negotiate_key_exch : bool; - ## If set, requests 128-bit session key negotiation - negotiate_128 : bool; - ## If set, requests the protocol version number - negotiate_version : bool; - ## If set, indicates that the TargetInfo fields in the - ## CHALLENGE_MESSAGE are populated - negotiate_target_info : bool; - - ## If set, requests the usage of the LMOWF function - request_non_nt_session_key : bool; - ## If set, requests and identify level token - negotiate_identify : bool; - ## If set, requests usage of NTLM v2 session security - ## Note: NTML v2 session security is actually NTLM v1 - negotiate_extended_sessionsecurity : bool; - ## If set, TargetName must be a server name - target_type_server : bool; - ## If set, TargetName must be a domain name - target_type_domain : bool; - - ## If set, requests the presence of a signature block - ## on all messages - negotiate_always_sign : bool; - ## If set, the workstation name is provided - negotiate_oem_workstation_supplied : bool; - ## If set, the domain name is provided - negotiate_oem_domain_supplied : bool; - ## If set, the connection should be anonymous - negotiate_anonymous_connection : bool; - ## If set, requests usage of NTLM v1 - negotiate_ntlm : bool; - - ## If set, requests LAN Manager session key computation - negotiate_lm_key : bool; - ## If set, requests connectionless authentication - negotiate_datagram : bool; - ## If set, requests session key negotiation for message - ## confidentiality - negotiate_seal : bool; - ## If set, requests session key negotiation for message - ## signatures - negotiate_sign : bool; - ## If set, the TargetName field is present - request_target : bool; - - ## If set, requests OEM character set encoding - negotiate_oem : bool; - ## If set, requests Unicode character set encoding - negotiate_unicode : bool; - }; - - type SMB::NTLMNegotiate: record { - ## The negotiate flags - flags : SMB::NTLMNegotiateFlags; - ## The domain name of the client, if known - domain_name : string &optional; - ## The machine name of the client, if known - workstation : string &optional; - ## The Windows version information, if supplied - version : SMB::NTLMVersion &optional; - }; - - type SMB::NTLMAVs: record { - ## The server's NetBIOS computer name - nb_computer_name : string; - ## The server's NetBIOS domain name - nb_domain_name : string; - ## The FQDN of the computer - dns_computer_name : string &optional; - ## The FQDN of the domain - dns_domain_name : string &optional; - ## The FQDN of the forest - dns_tree_name : string &optional; - - ## Indicates to the client that the account - ## authentication is constrained - constrained_auth : bool &optional; - ## The associated timestamp, if present - timestamp : time &optional; - ## Indicates that the client is providing - ## mess achine ID created at computer startup to - ## identify the calling machine - single_host_id : count &optional; - - ## The SPN of the target server - target_name : string &optional; - }; - - type SMB::NTLMChallenge: record { - ## The negotiate flags - flags : SMB::NTLMNegotiateFlags; - ## The server authentication realm. If the server is - ## domain-joined, the name of the domain. Otherwise - ## the server name. See flags.target_type_domain - ## and flags.target_type_server - target_name : string &optional; - ## The Windows version information, if supplied - version : SMB::NTLMVersion &optional; - ## Attribute-value pairs specified by the server - target_info : SMB::NTLMAVs &optional; - }; - - type SMB::NTLMAuthenticate: record { - ## The negotiate flags - flags : SMB::NTLMNegotiateFlags; - ## The domain or computer name hosting the account - domain_name : string; - ## The name of the user to be authenticated. - user_name : string; - ## The name of the computer to which the user was logged on. - workstation : string; - ## The Windows version information, if supplied - version : SMB::NTLMVersion &optional; - }; - } module SMB1; diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index 7df08dd7ef..1b45d81d21 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -53,6 +53,7 @@ @load base/protocols/krb @load base/protocols/modbus @load base/protocols/mysql +@load base/protocols/ntlm @load base/protocols/pop3 @load base/protocols/radius @load base/protocols/rdp diff --git a/scripts/base/protocols/ntlm/__load__.bro b/scripts/base/protocols/ntlm/__load__.bro new file mode 100644 index 0000000000..d551be57d3 --- /dev/null +++ b/scripts/base/protocols/ntlm/__load__.bro @@ -0,0 +1 @@ +@load ./main \ No newline at end of file diff --git a/scripts/base/protocols/ntlm/main.bro b/scripts/base/protocols/ntlm/main.bro new file mode 100644 index 0000000000..365ebcdd81 --- /dev/null +++ b/scripts/base/protocols/ntlm/main.bro @@ -0,0 +1,54 @@ +module NTLM; + +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; + + username: string &log &optional; + hostname: string &log &optional; + domainname: string &log &optional; + }; +} + +redef record connection += { + ntlm: Info &optional; +}; + +event bro_init() &priority=5 + { + Log::create_stream(NTLM::LOG, [$columns=Info, $path="ntlm"]); + } + +event ntlm_negotiate(c: connection, request: NTLM::Negotiate) &priority=5 + { + #print request; + } + +event ntlm_challenge(c: connection, challenge: NTLM::Challenge) &priority=5 + { + #print "challenge!!!!!"; + #print challenge; + } + +event ntlm_authenticate(c: connection, request: NTLM::Authenticate) &priority=5 + { + c$ntlm = NTLM::Info($ts=network_time(), $uid=c$uid, $id=c$id); + if ( request?$domain_name ) + c$ntlm$domainname = request$domain_name; + if ( request?$workstation ) + c$ntlm$hostname = request$workstation; + if ( request?$user_name ) + c$ntlm$username = request$user_name; + } + +event ntlm_authenticate(c: connection, request: NTLM::Authenticate) &priority=-5 + { + Log::write(NTLM::LOG, c$ntlm); + } diff --git a/scripts/base/protocols/smb/smb1-main.bro b/scripts/base/protocols/smb/smb1-main.bro index a6deeee812..236e4d6984 100644 --- a/scripts/base/protocols/smb/smb1-main.bro +++ b/scripts/base/protocols/smb/smb1-main.bro @@ -281,51 +281,6 @@ event smb1_session_setup_andx_response(c: connection, hdr: SMB1::Header, respons } } -event smb_ntlm_negotiate(c: connection, hdr: SMB1::Header, request: SMB::NTLMNegotiate) - { - c$smb_state$current_cmd$sub_command = "NTLMSSP_NEGOTIATE"; - } - -event smb_ntlm_authenticate(c: connection, hdr: SMB1::Header, request: SMB::NTLMAuthenticate) &priority=5 - { - c$smb_state$current_cmd$sub_command = "NTLMSSP_AUTHENTICATE"; - - c$smb_state$current_auth = SMB::AuthInfo($ts=network_time(), $uid=c$uid, $id=c$id); - if ( request?$domain_name ) - c$smb_state$current_auth$domainname = request$domain_name; - if ( request?$workstation ) - c$smb_state$current_auth$hostname = request$workstation; - if ( request?$user_name ) - c$smb_state$current_auth$username = request$user_name; - - local user: string = ""; - if ( ( request?$domain_name && request$domain_name != "" ) && ( request?$user_name && request$user_name != "" ) ) - user = fmt("%s\\%s", request$domain_name, request$user_name); - else if ( ( request?$workstation && request$workstation != "" ) && ( request?$user_name && request$user_name != "" ) ) - user = fmt("%s\\%s", request$workstation, request$user_name); - else if ( request?$user_name && request$user_name != "" ) - user = request$user_name; - else if ( request?$domain_name && request$domain_name != "" ) - user = fmt("%s\\", request$domain_name); - else if ( request?$workstation && request$workstation != "" ) - user = fmt("%s", request$workstation); - - if ( user != "" ) - { - c$smb_state$current_cmd$argument = user; - } - - if ( hdr$uid !in c$smb_state$uid_map ) - { - c$smb_state$uid_map[hdr$uid] = user; - } - } - -event smb_ntlm_authenticate(c: connection, hdr: SMB1::Header, request: SMB::NTLMAuthenticate) &priority=5 - { - Log::write(SMB::AUTH_LOG, c$smb_state$current_auth); - } - event smb1_transaction_request(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count) { c$smb_state$current_cmd$sub_command = SMB1::trans_sub_commands[sub_cmd]; diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 467fce83ee..91776e3fe4 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(file) add_subdirectory(finger) add_subdirectory(ftp) add_subdirectory(gnutella) +add_subdirectory(gssapi) add_subdirectory(gtpv1) add_subdirectory(http) add_subdirectory(icmp) @@ -25,6 +26,7 @@ add_subdirectory(modbus) add_subdirectory(mysql) add_subdirectory(ncp) add_subdirectory(netbios) +add_subdirectory(ntlm) add_subdirectory(ntp) add_subdirectory(pia) add_subdirectory(pop3) diff --git a/src/analyzer/protocol/dce-rpc/CMakeLists.txt b/src/analyzer/protocol/dce-rpc/CMakeLists.txt index a206c3db13..e02887fe83 100644 --- a/src/analyzer/protocol/dce-rpc/CMakeLists.txt +++ b/src/analyzer/protocol/dce-rpc/CMakeLists.txt @@ -10,7 +10,9 @@ bro_plugin_pac( dce_rpc.pac dce_rpc-protocol.pac dce_rpc-analyzer.pac + dce_rpc-gssapi.pac + endpoint-atsvc.pac endpoint-epmapper.pac - endpoint-atsvc.pac) + ) bro_plugin_end() diff --git a/src/analyzer/protocol/dce-rpc/dce_rpc-gssapi.pac b/src/analyzer/protocol/dce-rpc/dce_rpc-gssapi.pac new file mode 100644 index 0000000000..293bb643ad --- /dev/null +++ b/src/analyzer/protocol/dce-rpc/dce_rpc-gssapi.pac @@ -0,0 +1,42 @@ +refine connection DCE_RPC_Conn += { + %member{ + analyzer::Analyzer *gssapi; + analyzer::Analyzer *ntlm; + %} + + %init{ + gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn()); + ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer->Conn()); + %} + + %cleanup{ + if ( gssapi ) + delete gssapi; + if ( ntlm ) + delete ntlm; + %} + + function forward_auth(auth: DCE_RPC_Auth, is_orig: bool): bool + %{ + switch ( ${auth.type} ) + { + case 0x0a: + if ( ntlm ) + ntlm->DeliverStream(${auth.blob}.length(), ${auth.blob}.begin(), is_orig); + break; + //case 0xXX: + // if ( gssapi ) + // gssapi->DeliverStream(${data}.length(), ${data}.begin(), is_orig); + // break; + default: + bro_analyzer()->Weird(fmt("unknown_dce_rpc_auth_type_%d",${auth.type})); + break; + } + + return true; + %} +}; + +refine typeattr DCE_RPC_Auth += &let { + proc = $context.connection.forward_auth(this, true); +} diff --git a/src/analyzer/protocol/dce-rpc/dce_rpc.pac b/src/analyzer/protocol/dce-rpc/dce_rpc.pac index 616b4e7770..b36916635d 100644 --- a/src/analyzer/protocol/dce-rpc/dce_rpc.pac +++ b/src/analyzer/protocol/dce-rpc/dce_rpc.pac @@ -23,5 +23,6 @@ flow DCE_RPC_Flow(is_orig: bool) { flowunit = DCE_RPC_PDU(is_orig) withcontext(connection, this); }; -%include epmapper.pac +%include endpoint-atsvc.pac +%include endpoint-epmapper.pac %include dce_rpc-analyzer.pac diff --git a/src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac b/src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac index aa894ff649..2712181d16 100644 --- a/src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac +++ b/src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac @@ -1,38 +1,41 @@ -type ATSVC_Request(unicode: bool, opnum: uint8) = record { - empty: padding[1]; - op: case opnum of { - 0 -> add : ATSVC_NetrJobAdd(unicode); - default -> unknown : bytestring &restofdata; - }; -}; - -type ATSVC_String_Pointer(unicode: bool) = record { - referent_id : uint32; - max_count : uint32; - offset : uint32; - actual_count : uint32; - string : SMB_string(unicode, offsetof(string)); -}; - -type ATSVC_NetrJobAdd(unicode: bool) = record { - server : ATSVC_String_Pointer(unicode); - unknown : padding[2]; - job_time : uint32; - days_of_month : uint32; - days_of_week : uint8; - flags : uint8; - unknown2 : padding[2]; - command : ATSVC_String_Pointer(unicode); -}; - -type ATSVC_Reply(unicode: bool, opnum: uint16) = record { - op: case opnum of { - 0 -> add: ATSVC_JobID(unicode); - default -> unknown: bytestring &restofdata; - }; -}; - -type ATSVC_JobID(unicode: bool) = record { - id : uint32; - status : uint32; -}; +#%include ../smb/smb-strings.pac +# +#type ATSVC_Request(unicode: bool, opnum: uint8) = record { +# empty: padding[1]; +# op: case opnum of { +# 0 -> add : ATSVC_NetrJobAdd(unicode); +# default -> unknown : bytestring &restofdata; +# }; +#}; +# +#type ATSVC_String_Pointer(unicode: bool) = record { +# referent_id : uint32; +# max_count : uint32; +# offset : uint32; +# actual_count : uint32; +# string : SMB_string(unicode, offsetof(string)); +#}; +# +#type ATSVC_NetrJobAdd(unicode: bool) = record { +# server : ATSVC_String_Pointer(unicode); +# unknown : padding[2]; +# job_time : uint32; +# days_of_month : uint32; +# days_of_week : uint8; +# flags : uint8; +# unknown2 : padding[2]; +# command : ATSVC_String_Pointer(unicode); +#}; +# +#type ATSVC_Reply(unicode: bool, opnum: uint16) = record { +# op: case opnum of { +# 0 -> add: ATSVC_JobID(unicode); +# default -> unknown: bytestring &restofdata; +# }; +#}; +# +#type ATSVC_JobID(unicode: bool) = record { +# id : uint32; +# status : uint32; +#}; +# \ No newline at end of file diff --git a/src/analyzer/protocol/smb/CMakeLists.txt b/src/analyzer/protocol/smb/CMakeLists.txt index b95a77f924..9cb9e36113 100644 --- a/src/analyzer/protocol/smb/CMakeLists.txt +++ b/src/analyzer/protocol/smb/CMakeLists.txt @@ -5,10 +5,7 @@ include_directories(AFTER ${CMAKE_CURRENT_BINARY_DIR}/../dce-rpc) bro_plugin_begin(Bro SMB) bro_plugin_cc(SMB.cc Plugin.cc) -bro_plugin_bif( - smb_ntlmssp.bif - smb_pipe.bif - +bro_plugin_bif( smb1_com_check_directory.bif smb1_com_close.bif smb1_com_create_directory.bif @@ -40,6 +37,7 @@ bro_plugin_bif( smb2_com_write.bif smb2_events.bif + smb_pipe.bif types.bif) bro_plugin_pac( smb.pac @@ -47,8 +45,8 @@ bro_plugin_pac( smb-strings.pac smb-time.pac smb-pipe.pac + smb-gssapi.pac smb-mailslot.pac - smb-ntlmssp.pac smb1-protocol.pac smb1-com-check-directory.pac diff --git a/src/analyzer/protocol/smb/SMB.h b/src/analyzer/protocol/smb/SMB.h index 0b47c05071..2a91b5dc54 100644 --- a/src/analyzer/protocol/smb/SMB.h +++ b/src/analyzer/protocol/smb/SMB.h @@ -10,14 +10,6 @@ namespace analyzer { namespace smb { -enum IPC_named_pipe { - IPC_NONE, - IPC_LOCATOR, - IPC_EPMAPPER, - IPC_SAMR, // Security Account Manager -}; - - class Contents_SMB : public tcp::TCP_SupportAnalyzer { public: Contents_SMB(Connection* conn, bool orig); diff --git a/src/analyzer/protocol/smb/smb-gssapi.pac b/src/analyzer/protocol/smb/smb-gssapi.pac new file mode 100644 index 0000000000..9372df7f47 --- /dev/null +++ b/src/analyzer/protocol/smb/smb-gssapi.pac @@ -0,0 +1,11 @@ + +refine connection SMB_Conn += { + + function forward_gssapi(data: bytestring, is_orig: bool): bool + %{ + if ( gssapi ) + gssapi->DeliverStream(${data}.length(), ${data}.begin(), is_orig); + + return true; + %} +}; diff --git a/src/analyzer/protocol/smb/smb-ntlmssp-asn1.pac b/src/analyzer/protocol/smb/smb-ntlmssp-asn1.pac deleted file mode 100644 index 0cb459d26c..0000000000 --- a/src/analyzer/protocol/smb/smb-ntlmssp-asn1.pac +++ /dev/null @@ -1,57 +0,0 @@ -# Supporting types for ASN.1 -# -# From the Kerberos analyzer -# -# TODO: Figure out a way to include this code only once. - -type ASN1Encoding = record { - meta: ASN1EncodingMeta; - content: bytestring &length = meta.length; -}; - -type ASN1EncodingMeta = record { - tag: uint8; - len: uint8; - more_len: bytestring &length = long_len ? len & 0x7f : 0; -} &let { - long_len: bool = len & 0x80; - length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f; - index: uint8 = tag - 160; -}; - -type ASN1Integer = record { - encoding: ASN1Encoding; -}; - -type ASN1OctetString = record { - encoding: ASN1Encoding; -}; - -type SequenceElement(grab_content: bool) = record { - index_meta: ASN1EncodingMeta; - have_content: case grab_content of { - true -> data: ASN1Encoding; - false -> meta: ASN1EncodingMeta; - }; -} &let { - index: uint8 = index_meta.index; - length: uint64 = index_meta.length; -}; - -type Array = record { - array_meta: ASN1EncodingMeta; - data: ASN1Encoding[]; -}; - -function binary_to_int64(bs: bytestring): int64 - %{ - int64 rval = 0; - - for ( int i = 0; i < bs.length(); ++i ) - { - uint64 byte = bs[i]; - rval |= byte << (8 * (bs.length() - (i + 1))); - } - - return rval; - %} \ No newline at end of file diff --git a/src/analyzer/protocol/smb/smb-ntlmssp.pac b/src/analyzer/protocol/smb/smb-ntlmssp.pac deleted file mode 100644 index 0aef66d353..0000000000 --- a/src/analyzer/protocol/smb/smb-ntlmssp.pac +++ /dev/null @@ -1,430 +0,0 @@ -refine connection SMB_Conn += { - function build_negotiate_flag_record(val: SMB_NTLM_Negotiate_Flags): BroVal - %{ - RecordVal* flags = new RecordVal(BifType::Record::SMB::NTLMNegotiateFlags); - flags->Assign(0, new Val(${val.negotiate_56}, TYPE_BOOL)); - flags->Assign(1, new Val(${val.negotiate_key_exch}, TYPE_BOOL)); - flags->Assign(2, new Val(${val.negotiate_128}, TYPE_BOOL)); - flags->Assign(3, new Val(${val.negotiate_version}, TYPE_BOOL)); - flags->Assign(4, new Val(${val.negotiate_target_info}, TYPE_BOOL)); - - flags->Assign(5, new Val(${val.request_non_nt_session_key}, TYPE_BOOL)); - flags->Assign(6, new Val(${val.negotiate_identify}, TYPE_BOOL)); - flags->Assign(7, new Val(${val.negotiate_extended_sessionsecurity}, TYPE_BOOL)); - flags->Assign(8, new Val(${val.target_type_server}, TYPE_BOOL)); - flags->Assign(9, new Val(${val.target_type_domain}, TYPE_BOOL)); - - flags->Assign(10, new Val(${val.negotiate_always_sign}, TYPE_BOOL)); - flags->Assign(11, new Val(${val.negotiate_oem_workstation_supplied}, TYPE_BOOL)); - flags->Assign(12, new Val(${val.negotiate_oem_domain_supplied}, TYPE_BOOL)); - flags->Assign(13, new Val(${val.negotiate_anonymous_connection}, TYPE_BOOL)); - flags->Assign(14, new Val(${val.negotiate_ntlm}, TYPE_BOOL)); - - flags->Assign(15, new Val(${val.negotiate_lm_key}, TYPE_BOOL)); - flags->Assign(16, new Val(${val.negotiate_datagram}, TYPE_BOOL)); - flags->Assign(17, new Val(${val.negotiate_seal}, TYPE_BOOL)); - flags->Assign(18, new Val(${val.negotiate_sign}, TYPE_BOOL)); - flags->Assign(19, new Val(${val.request_target}, TYPE_BOOL)); - - flags->Assign(20, new Val(${val.negotiate_oem}, TYPE_BOOL)); - flags->Assign(21, new Val(${val.negotiate_unicode}, TYPE_BOOL)); - - return flags; - %} - - function build_version_record(val: SMB_NTLM_Version): BroVal - %{ - RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMVersion); - result->Assign(0, new Val(${val.major_version}, TYPE_COUNT)); - result->Assign(1, new Val(${val.minor_version}, TYPE_COUNT)); - result->Assign(2, new Val(${val.build_number}, TYPE_COUNT)); - result->Assign(3, new Val(${val.ntlm_revision}, TYPE_COUNT)); - - return result; - %} - - function build_av_record(val: SMB_NTLM_AV_Pair_Sequence): BroVal - %{ - RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMAVs); - for ( uint i = 0; ${val.pairs[i].id} != 0; i++ ) - { - switch ( ${val.pairs[i].id} ) - { - case 1: - result->Assign(0, uint8s_to_stringval(${val.pairs[i].nb_computer_name.data})); - break; - case 2: - result->Assign(1, uint8s_to_stringval(${val.pairs[i].nb_domain_name.data})); - break; - case 3: - result->Assign(2, uint8s_to_stringval(${val.pairs[i].dns_computer_name.data})); - break; - case 4: - result->Assign(3, uint8s_to_stringval(${val.pairs[i].dns_domain_name.data})); - break; - case 5: - result->Assign(4, uint8s_to_stringval(${val.pairs[i].dns_tree_name.data})); - break; - case 6: - result->Assign(5, new Val(${val.pairs[i].constrained_auth}, TYPE_BOOL)); - break; - case 7: - result->Assign(6, filetime2brotime(${val.pairs[i].timestamp})); - break; - case 8: - result->Assign(7, new Val(${val.pairs[i].single_host.machine_id}, TYPE_COUNT)); - break; - case 9: - result->Assign(8, uint8s_to_stringval(${val.pairs[i].target_name.data})); - break; - } - } - return result; - %} - - function proc_smb_ntlm_ssp(header: SMB_Header, val:SMB_NTLM_SSP): bool - %{ - if ( ${val.gssapi.is_init} ) - return true; - - for ( uint i = 0; i < ${val.gssapi.resp.args}->size(); ++i ) - { - switch ( ${val.gssapi.resp.args[i].seq_meta.index} ) - { - case 0: - if ( ${val.gssapi.resp.args[i].args.neg_state} == 0 ) - BifEvent::generate_smb_ntlm_accepted(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header)); - break; - default: - break; - } - } - return true; - %} - - function proc_smb_ntlm_negotiate(header: SMB_Header, val: SMB_NTLM_Negotiate): bool - %{ - RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMNegotiate); - result->Assign(0, build_negotiate_flag_record(${val.flags})); - - if ( ${val.flags.negotiate_oem_domain_supplied} ) - result->Assign(1, uint8s_to_stringval(${val.domain_name.string.data})); - - if ( ${val.flags.negotiate_oem_workstation_supplied} ) - result->Assign(2, uint8s_to_stringval(${val.workstation.string.data})); - - if ( ${val.flags.negotiate_version} ) - result->Assign(3, build_version_record(${val.version})); - - BifEvent::generate_smb_ntlm_negotiate(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result); - - return true; - %} - - function proc_smb_ntlm_challenge(header: SMB_Header, val: SMB_NTLM_Challenge): bool - %{ - RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMChallenge); - result->Assign(0, build_negotiate_flag_record(${val.flags})); - - if ( ${val.flags.request_target} ) - result->Assign(1, uint8s_to_stringval(${val.target_name.string.data})); - - if ( ${val.flags.negotiate_version} ) - result->Assign(2, build_version_record(${val.version})); - - if ( ${val.flags.negotiate_target_info} ) - result->Assign(3, build_av_record(${val.target_info})); - - BifEvent::generate_smb_ntlm_challenge(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result); - - return true; - %} - - function proc_smb_ntlm_authenticate(header: SMB_Header, val: SMB_NTLM_Authenticate): bool - %{ - RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMAuthenticate); - result->Assign(0, build_negotiate_flag_record(${val.flags})); - - if ( ${val.domain_name_fields.length} > 0 ) - result->Assign(1, uint8s_to_stringval(${val.domain_name.string.data})); - - if ( ${val.user_name_fields.length} > 0 ) - result->Assign(2, uint8s_to_stringval(${val.user_name.string.data})); - - if ( ${val.workstation_fields.length} > 0 ) - result->Assign(3, uint8s_to_stringval(${val.workstation.string.data})); - - if ( ${val.flags.negotiate_version} ) - result->Assign(4, build_version_record(${val.version})); - - BifEvent::generate_smb_ntlm_authenticate(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result); - - return true; - %} -}; - -type GSSAPI_NEG_TOKEN(header: SMB_Header) = record { - wrapper : ASN1EncodingMeta; - have_oid : case is_init of { - true -> oid : ASN1Encoding; - false -> no_oid : empty; - }; - have_init_wrapper : case is_init of { - true -> init_wrapper : ASN1EncodingMeta; - false -> no_init_wrapper : empty; - }; - msg_type : case is_init of { - true -> init: GSSAPI_NEG_TOKEN_INIT(header); - false -> resp: GSSAPI_NEG_TOKEN_RESP(header); - }; -} &let { - is_init: bool = (wrapper.tag == 0x60); -}; - -type GSSAPI_NEG_TOKEN_INIT(header: SMB_Header) = record { - seq_meta : ASN1EncodingMeta; - args : GSSAPI_NEG_TOKEN_INIT_Arg(header)[]; -}; - -type GSSAPI_NEG_TOKEN_INIT_Arg(header: SMB_Header) = record { - seq_meta : ASN1EncodingMeta; - args : GSSAPI_NEG_TOKEN_INIT_Arg_Data(header, seq_meta.index) &length=seq_meta.length; -}; - -type GSSAPI_NEG_TOKEN_INIT_Arg_Data(header: SMB_Header, index: uint8) = case index of { - 0 -> mech_type_list : ASN1Encoding; - 1 -> req_flags : ASN1Encoding; - 2 -> mech_token : SMB_NTLM_SSP_Token(header); - 3 -> mech_list_mic : ASN1OctetString; -}; - -type GSSAPI_NEG_TOKEN_RESP(header: SMB_Header) = record { - seq_meta : ASN1EncodingMeta; - args : GSSAPI_NEG_TOKEN_RESP_Arg(header)[]; -}; - -type GSSAPI_NEG_TOKEN_RESP_Arg(header: SMB_Header) = record { - seq_meta : ASN1EncodingMeta; - args : GSSAPI_NEG_TOKEN_RESP_Arg_Data(header, seq_meta.index) &length=seq_meta.length; -}; - -type GSSAPI_NEG_TOKEN_RESP_Arg_Data(header: SMB_Header, index: uint8) = case index of { - 0 -> neg_state : ASN1Integer; - 1 -> supported_mech : ASN1Encoding; - 2 -> response_token : SMB_NTLM_SSP_Token(header); - 3 -> mech_list_mic : ASN1OctetString; - default -> def : bytestring &restofdata &transient; -}; - -type SMB_NTLM_SSP(header: SMB_Header) = record { - gssapi: GSSAPI_NEG_TOKEN(header); -} &let { - proc: bool = $context.connection.proc_smb_ntlm_ssp(header, this); -}; - -type SMB_NTLM_SSP_Token(header: SMB_Header) = record { - meta : ASN1EncodingMeta; - signature : bytestring &length=8; - msg_type : uint32; - msg : case msg_type of { - 1 -> negotiate : SMB_NTLM_Negotiate(header, offsetof(msg) - offsetof(signature)); - 2 -> challenge : SMB_NTLM_Challenge(header, offsetof(msg) - offsetof(signature)); - 3 -> authenticate : SMB_NTLM_Authenticate(header, offsetof(msg) - offsetof(signature)); - default -> def : bytestring &restofdata &transient; - }; -}; - -type SMB_NTLM_Negotiate(header: SMB_Header, offset: uint16) = record { - flags : SMB_NTLM_Negotiate_Flags; - domain_name_fields : SMB_NTLM_StringData; - workstation_fields : SMB_NTLM_StringData; - version_present : case flags.negotiate_version of { - true -> version : SMB_NTLM_Version; - false -> no_version : empty; - }; - payload : bytestring &restofdata; -} &let { - absolute_offset : uint16 = offsetof(payload) + offset; - domain_name : SMB_NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_domain_supplied); - workstation : SMB_NTLM_String(workstation_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_workstation_supplied); - - proc : bool = $context.connection.proc_smb_ntlm_negotiate(header, this); -}; - -type SMB_NTLM_Challenge(header: SMB_Header, offset: uint16) = record { - target_name_fields : SMB_NTLM_StringData; - flags : SMB_NTLM_Negotiate_Flags; - challenge : uint64; - reserved : padding[8]; - target_info_fields : SMB_NTLM_StringData; - version_present : case flags.negotiate_version of { - true -> version : SMB_NTLM_Version; - false -> no_version : empty; - }; - payload : bytestring &restofdata; -} &let { - absolute_offset : uint16 = offsetof(payload) + offset; - target_name : SMB_NTLM_String(target_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.request_target); - target_info : SMB_NTLM_AV_Pair_Sequence(target_info_fields.offset - absolute_offset) withinput payload &if(flags.negotiate_target_info); - - proc : bool = $context.connection.proc_smb_ntlm_challenge(header, this); -}; - -type SMB_NTLM_Authenticate(header: SMB_Header, offset: uint16) = record { - lm_challenge_response_fields : SMB_NTLM_StringData; - nt_challenge_response_fields : SMB_NTLM_StringData; - domain_name_fields : SMB_NTLM_StringData; - user_name_fields : SMB_NTLM_StringData; - workstation_fields : SMB_NTLM_StringData; - encrypted_session_key_fields : SMB_NTLM_StringData; - flags : SMB_NTLM_Negotiate_Flags; - version_present : case flags.negotiate_version of { - true -> version : SMB_NTLM_Version; - false -> no_version : empty; - }; - -# Windows NT, 2000, XP, and 2003 don't have the MIC field -# TODO - figure out how to parse this for those that do have it -# mic : bytestring &length=16; - - payload : bytestring &restofdata; -} &let { - absolute_offset : uint16 = offsetof(payload) + offset; - domain_name : SMB_NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(domain_name_fields.length > 0); - user_name : SMB_NTLM_String(user_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(user_name_fields.length > 0); - workstation : SMB_NTLM_String(workstation_fields, absolute_offset , flags.negotiate_unicode) withinput payload &if(workstation_fields.length > 0); - encrypted_session_key : SMB_NTLM_String(encrypted_session_key_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_key_exch); - - proc : bool = $context.connection.proc_smb_ntlm_authenticate(header, this); -}; - -type SMB_NTLM_Version = record { - major_version : uint8; - minor_version : uint8; - build_number : uint16; - reserved : padding[3]; - ntlm_revision : uint8; -}; - -type SMB_NTLM_StringData = record { - length : uint16; - max_length : uint16; - offset : uint32; -}; - -type SMB_Fixed_Length_String(unicode: bool) = record { - data: uint8[] &restofdata; -}; - -type SMB_NTLM_String(fields: SMB_NTLM_StringData, offset: uint16, unicode: bool) = record { - pad1 : padding to fields.offset - offset; - string : SMB_Fixed_Length_String(unicode) &length=fields.length; -}; - -type SMB_NTLM_AV_Pair_Sequence(offset: uint16) = record { - pad1 : padding to offset; - pairs : SMB_NTLM_AV_Pair[] &until($element.last); -}; - -type SMB_NTLM_AV_Pair = record { - id : uint16; - length : uint16; - value_case : case id of { - 0x0000 -> av_eol : empty; - 0x0001 -> nb_computer_name : SMB_Fixed_Length_String(true) &length=length; - 0x0002 -> nb_domain_name : SMB_Fixed_Length_String(true) &length=length; - 0x0003 -> dns_computer_name : SMB_Fixed_Length_String(true) &length=length; - 0x0004 -> dns_domain_name : SMB_Fixed_Length_String(true) &length=length; - 0x0005 -> dns_tree_name : SMB_Fixed_Length_String(true) &length=length; - 0x0006 -> av_flags : uint32; - 0x0007 -> timestamp : uint64; - 0x0008 -> single_host : SMB_NTLM_Single_Host; - 0x0009 -> target_name : SMB_Fixed_Length_String(true) &length=length; - 0x000a -> channel_bindings : uint16; - }; -} &let { - last : bool = ( id == 0x0000); - # av_flags refinement - constrained_auth: bool = (av_flags & 0x00000001) > 0 &if ( id == 0x0006); - mic_present : bool = (av_flags & 0x00000002) > 0 &if ( id == 0x0006); - untrusted_source: bool = (av_flags & 0x00000004) > 0 &if ( id == 0x0006); -}; - -type SMB_NTLM_Single_Host = record { - size : uint32; - padpad : padding[4]; - data_present : uint32; - optional : case custom_data_present of { - true -> custom_data : bytestring &length=4; - false -> nothing : empty; - }; - machine_id : uint32; -} &let { - custom_data_present: bool = (data_present & 0x00000001) > 0; -}; - -type SMB_LM_Response(offset: uint16) = record { - # This can be either LM (24 byte response) or - # LMv2 (16 byte response + 8 byte client challenge. No way to - # know for sure. - padpad : padding to offset; - response : bytestring &length=24; -}; - -type SMB_NTLM_Response(offset: uint16) = record { - padpad : padding to offset; - response : bytestring &length=24; -}; - -type SMB_NTLMv2_Response(flags: SMB_NTLM_Negotiate_Flags, offset: uint16) = record { - padpad : padding to offset; - response : bytestring &length=16; - client_challenge : SMB_NTLMv2_Client_Challenge(flags); -}; - -type SMB_NTLMv2_Client_Challenge(flags: SMB_NTLM_Negotiate_Flags) = record { - resp_type : uint8; - max_resp_type : uint8; - reserved : padding[6]; - timestamp : uint64; - client_challenge : bytestring &length=8; - reserved2 : padding[4]; - av_pairs : SMB_NTLM_AV_Pair_Sequence(0); -}; - -type SMB_NTLM_Negotiate_Flags = record { - flags: uint32; -} &let { - negotiate_56 : bool = (flags & 0x80000000) > 0; - negotiate_key_exch : bool = (flags & 0x40000000) > 0; - negotiate_128 : bool = (flags & 0x20000000) > 0; - - negotiate_version : bool = (flags & 0x02000000) > 0; - - negotiate_target_info : bool = (flags & 0x00800000) > 0; - request_non_nt_session_key : bool = (flags & 0x00400000) > 0; - negotiate_identify : bool = (flags & 0x00100000) > 0; - - negotiate_extended_sessionsecurity : bool = (flags & 0x00040000) > 0; - target_type_server : bool = (flags & 0x00020000) > 0; - target_type_domain : bool = (flags & 0x00010000) > 0; - - negotiate_always_sign : bool = (flags & 0x00008000) > 0; - negotiate_oem_workstation_supplied : bool = (flags & 0x00002000) > 0; - negotiate_oem_domain_supplied : bool = (flags & 0x00001000) > 0; - - negotiate_anonymous_connection : bool = (flags & 0x00000400) > 0; - negotiate_ntlm : bool = (flags & 0x00000100) > 0; - - negotiate_lm_key : bool = (flags & 0x00000080) > 0; - negotiate_datagram : bool = (flags & 0x00000040) > 0; - negotiate_seal : bool = (flags & 0x00000020) > 0; - - negotiate_sign : bool = (flags & 0x00000008) > 0; - request_target : bool = (flags & 0x00000004) > 0; - negotiate_oem : bool = (flags & 0x00000002) > 0; - negotiate_unicode : bool = (flags & 0x00000001) > 0; - - is_oem : bool = !negotiate_unicode && negotiate_oem; - is_invalid : bool = !negotiate_unicode && !negotiate_oem; -}; diff --git a/src/analyzer/protocol/smb/smb.pac b/src/analyzer/protocol/smb/smb.pac index 76fecc8679..e6f63db25c 100644 --- a/src/analyzer/protocol/smb/smb.pac +++ b/src/analyzer/protocol/smb/smb.pac @@ -4,16 +4,12 @@ %extern{ #include "analyzer/Manager.h" #include "analyzer/Analyzer.h" -// #include "analyzer/protocol/dce-rpc/DCE_RPC.h" #include "smb1_events.bif.h" #include "smb2_events.bif.h" #include "types.bif.h" -#include "smb_ntlmssp.bif.h" -#include "smb_pipe.bif.h" - #include "smb1_com_check_directory.bif.h" #include "smb1_com_close.bif.h" #include "smb1_com_create_directory.bif.h" @@ -57,9 +53,9 @@ connection SMB_Conn(bro_analyzer: BroAnalyzer) { %include smb-strings.pac %include smb-common.pac %include smb-time.pac - -%include smb-ntlmssp-asn1.pac -%include smb-ntlmssp.pac +%include smb-mailslot.pac +%include smb-pipe.pac +%include smb-gssapi.pac # SMB1 Commands %include smb1-com-check-directory.pac @@ -82,9 +78,6 @@ connection SMB_Conn(bro_analyzer: BroAnalyzer) { %include smb1-com-tree-disconnect.pac %include smb1-com-write-andx.pac -%include smb-mailslot.pac -%include smb-pipe.pac - # SMB2 Commands %include smb2-com-close.pac %include smb2-com-create.pac @@ -146,14 +139,18 @@ flow SMB_Flow(is_orig: bool) { refine connection SMB_Conn += { %member{ analyzer::Analyzer *dcerpc; + analyzer::Analyzer *gssapi; %} %init{ dcerpc = analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer->Conn()); + gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn()); %} %cleanup{ if ( dcerpc ) delete dcerpc; + if ( gssapi ) + delete gssapi; %} }; diff --git a/src/analyzer/protocol/smb/smb1-com-negotiate.pac b/src/analyzer/protocol/smb/smb1-com-negotiate.pac index e16c144a8c..17b6242a01 100644 --- a/src/analyzer/protocol/smb/smb1-com-negotiate.pac +++ b/src/analyzer/protocol/smb/smb1-com-negotiate.pac @@ -161,7 +161,6 @@ refine connection SMB_Conn += { else { ntlm->Assign(12, bytestring_to_val(${val.ntlm.server_guid})); - // ntlm->Assign(13, bytestring_to_val(${val.ntlm.security_blob})); } response->Assign(2, ntlm); @@ -204,78 +203,80 @@ type SMB1_negotiate_core_response = record { }; type SMB1_negotiate_lanman_response(header: SMB_Header) = record { - security_flags: uint16; # expanded in &let - max_buffer_size: uint16; - max_mpx_count: uint16; - max_number_vcs: uint16; - raw_mode: uint16; # expanded in &let - session_key: uint32; - server_time: SMB_time; - server_date: SMB_date; - server_tz: uint16; - encryption_key_length: uint16; - reserved: uint16; # must be zero - byte_count: uint16; # count of data bytes - encryption_key: bytestring &length=encryption_key_length; - primary_domain: SMB_string(header.unicode, offsetof(primary_domain)); + security_flags : uint16; # expanded in &let + max_buffer_size : uint16; + max_mpx_count : uint16; + max_number_vcs : uint16; + raw_mode : uint16; # expanded in &let + session_key : uint32; + server_time : SMB_time; + server_date : SMB_date; + server_tz : uint16; + encryption_key_length : uint16; + reserved : uint16; # must be zero + byte_count : uint16; # count of data bytes + encryption_key : bytestring &length=encryption_key_length; + primary_domain : SMB_string(header.unicode, offsetof(primary_domain)); } &let { - security_user_level: bool = ( security_flags & 0x1 ) > 0; - security_challenge_response: bool = ( security_flags & 0x2 ) > 0; - raw_read_supported: bool = ( raw_mode & 0x1 ) > 0; - raw_write_supported: bool = ( raw_mode & 0x2 ) > 0; + security_user_level : bool = ( security_flags & 0x1 ) > 0; + security_challenge_response : bool = ( security_flags & 0x2 ) > 0; + raw_read_supported : bool = ( raw_mode & 0x1 ) > 0; + raw_write_supported : bool = ( raw_mode & 0x2 ) > 0; }; type SMB1_negotiate_ntlm_response(header: SMB_Header) = record { - security_flags: uint8; # Expanded in &let - max_mpx_count: uint16; - max_number_vcs: uint16; - max_buffer_size: uint32; - max_raw_size: uint32; - session_key: uint32; - capabilities: uint32; # Expanded in &let - server_time: uint64; - server_tz: uint16; - encryption_key_length: uint8; - byte_count: uint16; + security_flags : uint8; # Expanded in &let + max_mpx_count : uint16; + max_number_vcs : uint16; + max_buffer_size : uint32; + max_raw_size : uint32; + session_key : uint32; + capabilities : uint32; # Expanded in &let + server_time : uint64; + server_tz : uint16; + encryption_key_length : uint8; + byte_count : uint16; encryption_key_present: case capabilities_extended_security of { - false -> encryption_key: bytestring &length=encryption_key_length; - true -> no_key: empty; + false -> encryption_key : bytestring &length=encryption_key_length; + true -> no_key : empty; } &requires(capabilities_extended_security); domain_name_present: case capabilities_extended_security of { - false -> domain_name: SMB_string(header.unicode, offsetof(domain_name_present)); - true -> no_name: empty; + false -> domain_name : SMB_string(header.unicode, offsetof(domain_name_present)); + true -> no_name : empty; } &requires(capabilities_extended_security); server_guid_present: case capabilities_extended_security of { - true -> server_guid: bytestring &length=16; - false -> no_guid: empty; + true -> server_guid : bytestring &length=16; + false -> no_guid : empty; } &requires(capabilities_extended_security); security_blob_present: case capabilities_extended_security of { - true -> security_blob: SMB_NTLM_SSP(header) &length=(byte_count-16); - false -> no_blob: empty; + true -> security_blob : bytestring &length=(byte_count-16); + false -> no_blob : empty; } &requires(capabilities_extended_security); } &let { - security_user_level: bool = ( security_flags & 0x1 ) > 0; - security_challenge_response: bool = ( security_flags & 0x2 ) > 0; - security_signatures_enabled: bool = ( security_flags & 0x4 ) > 0; - security_signatures_required: bool = ( security_flags & 0x8 ) > 0; - capabilities_raw_mode: bool = (capabilities & 0x1 ) > 0; - capabilities_mpx_mode: bool = (capabilities & 0x2 ) > 0; - capabilities_unicode: bool = (capabilities & 0x4 ) > 0; - capabilities_large_files: bool = (capabilities & 0x8 ) > 0; - capabilities_nt_smbs: bool = (capabilities & 0x10 ) > 0; - capabilities_rpc_remote_apis: bool = (capabilities & 0x20 ) > 0; - capabilities_status32: bool = (capabilities & 0x40 ) > 0; - capabilities_level_2_oplocks: bool = (capabilities & 0x80 ) > 0; - capabilities_lock_and_read: bool = (capabilities & 0x100 ) > 0; - capabilities_nt_find: bool = (capabilities & 0x200 ) > 0; - capabilities_dfs: bool = (capabilities & 0x1000 ) > 0; - capabilities_infolevel_passthru: bool = (capabilities & 0x2000 ) > 0; - capabilities_large_readx: bool = (capabilities & 0x4000 ) > 0; - capabilities_large_writex: bool = (capabilities & 0x8000 ) > 0; - capabilities_unix: bool = (capabilities & 0x00800000 ) > 0; - capabilities_reserved: bool = (capabilities & 0x02000000 ) > 0; - capabilities_bulk_transfer: bool = (capabilities & 0x20000000 ) > 0; - capabilities_compressed_data: bool = (capabilities & 0x40000000 ) > 0; - capabilities_extended_security: bool = (capabilities & 0x80000000 ) > 0; + security_user_level : bool = (security_flags & 0x1) > 0; + security_challenge_response : bool = (security_flags & 0x2) > 0; + security_signatures_enabled : bool = (security_flags & 0x4) > 0; + security_signatures_required : bool = (security_flags & 0x8) > 0; + capabilities_raw_mode : bool = (capabilities & 0x1) > 0; + capabilities_mpx_mode : bool = (capabilities & 0x2) > 0; + capabilities_unicode : bool = (capabilities & 0x4) > 0; + capabilities_large_files : bool = (capabilities & 0x8) > 0; + capabilities_nt_smbs : bool = (capabilities & 0x10) > 0; + capabilities_rpc_remote_apis : bool = (capabilities & 0x20) > 0; + capabilities_status32 : bool = (capabilities & 0x40) > 0; + capabilities_level_2_oplocks : bool = (capabilities & 0x80) > 0; + capabilities_lock_and_read : bool = (capabilities & 0x100) > 0; + capabilities_nt_find : bool = (capabilities & 0x200) > 0; + capabilities_dfs : bool = (capabilities & 0x1000) > 0; + capabilities_infolevel_passthru : bool = (capabilities & 0x2000) > 0; + capabilities_large_readx : bool = (capabilities & 0x4000) > 0; + capabilities_large_writex : bool = (capabilities & 0x8000) > 0; + capabilities_unix : bool = (capabilities & 0x00800000) > 0; + capabilities_reserved : bool = (capabilities & 0x02000000) > 0; + capabilities_bulk_transfer : bool = (capabilities & 0x20000000) > 0; + capabilities_compressed_data : bool = (capabilities & 0x40000000) > 0; + capabilities_extended_security : bool = (capabilities & 0x80000000) > 0; + + gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false) &if(capabilities_extended_security); }; diff --git a/src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac b/src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac index acf4bfc20a..c5cfe02969 100644 --- a/src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac +++ b/src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac @@ -47,11 +47,10 @@ refine connection SMB_Conn += { request->Assign(5, smb_string2stringval(${val.ntlm_extended_security.native_os})); request->Assign(6, smb_string2stringval(${val.ntlm_extended_security.native_lanman})); - //request->Assign(12, bytestring_to_val(${val.ntlm_extended_security.security_blob})); request->Assign(13, capabilities); break; - case 13: // NT LM 0.12 without extended security + case 13: // NT LM 0.12 without extended security capabilities = new RecordVal(BifType::Record::SMB1::SessionSetupAndXCapabilities); capabilities->Assign(0, new Val(${val.ntlm_nonextended_security.capabilities.unicode}, TYPE_BOOL)); capabilities->Assign(1, new Val(${val.ntlm_nonextended_security.capabilities.large_files}, TYPE_BOOL)); @@ -90,24 +89,27 @@ refine connection SMB_Conn += { response->Assign(0, new Val(${val.word_count}, TYPE_COUNT)); switch ( ${val.word_count} ) { - case 3: // pre NT LM 0.12 + case 3: // pre NT LM 0.12 response->Assign(1, new Val(${val.lanman.is_guest}, TYPE_BOOL)); response->Assign(2, smb_string2stringval(${val.lanman.native_os})); response->Assign(3, smb_string2stringval(${val.lanman.native_lanman})); response->Assign(4, smb_string2stringval(${val.lanman.primary_domain})); break; - case 4: // NT LM 0.12 + case 4: // NT LM 0.12 response->Assign(1, new Val(${val.ntlm.is_guest}, TYPE_BOOL)); response->Assign(2, smb_string2stringval(${val.ntlm.native_os})); response->Assign(3, smb_string2stringval(${val.ntlm.native_lanman})); response->Assign(4, smb_string2stringval(${val.ntlm.primary_domain})); //response->Assign(5, bytestring_to_val(${val.ntlm.security_blob})); break; - default: // Error! + default: // Error! break; } - BifEvent::generate_smb1_session_setup_andx_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), response); + BifEvent::generate_smb1_session_setup_andx_response(bro_analyzer(), + bro_analyzer()->Conn(), + BuildHeaderVal(header), + response); } return true; @@ -118,17 +120,17 @@ refine connection SMB_Conn += { type SMB1_session_setup_andx_request(header: SMB_Header) = record { word_count : uint8; lanman_or_ntlm : case word_count of { - 0x0a -> lanman: SMB1_session_setup_andx_request_lanman(header); - 0x0c -> ntlm_extended_security: SMB1_session_setup_andx_request_ntlm_extended_security(header); - 0x0d -> ntlm_nonextended_security: SMB1_session_setup_andx_request_ntlm_nonextended_security(header); + 0x0a -> lanman : SMB1_session_setup_andx_request_lanman(header); + 0x0c -> ntlm_extended_security : SMB1_session_setup_andx_request_ntlm_extended_security(header); + 0x0d -> ntlm_nonextended_security : SMB1_session_setup_andx_request_ntlm_nonextended_security(header); }; } &let { proc: bool = $context.connection.proc_smb1_session_setup_andx_request(header, this); }; type SMB1_session_setup_andx_response(header: SMB_Header) = record { - word_count : uint8; - lanman_or_ntlm : case word_count of { + word_count : uint8; + lanman_or_ntlm : case word_count of { 0x03 -> lanman: SMB1_session_setup_andx_response_lanman(header); 0x04 -> ntlm: SMB1_session_setup_andx_response_ntlm(header); default -> error: uint16; @@ -138,25 +140,25 @@ type SMB1_session_setup_andx_response(header: SMB_Header) = record { }; type SMB1_session_setup_andx_request_lanman(header: SMB_Header) = record { - andx : SMB_andx; - max_buffer_size : uint16; - max_mpx_count : uint16; - vc_number : uint16; - session_key : uint32; - password_length : uint16; - reserved : uint32; - byte_count : uint16; + andx : SMB_andx; + max_buffer_size : uint16; + max_mpx_count : uint16; + vc_number : uint16; + session_key : uint32; + password_length : uint16; + reserved : uint32; + byte_count : uint16; account_password : bytestring &length=password_length; # offset + 1 due to word_count in the parent type - account_name : SMB_string(header.unicode, offsetof(account_name) + 1); - primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); - native_os : SMB_string(header.unicode, offsetof(native_os) + 1); - native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); + account_name : SMB_string(header.unicode, offsetof(account_name) + 1); + primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); + native_os : SMB_string(header.unicode, offsetof(native_os) + 1); + native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); }; type SMB1_session_setup_andx_response_lanman(header: SMB_Header) = record { - andx : SMB_andx; - action : uint16; + andx : SMB_andx; + action : uint16; byte_count : uint16; # offset + 1 due to word_count in the parent type native_os : SMB_string(header.unicode, offsetof(native_os) + 1); @@ -167,63 +169,66 @@ type SMB1_session_setup_andx_response_lanman(header: SMB_Header) = record { }; type SMB1_session_setup_andx_request_ntlm_capabilities = record { - capabilities : uint32; + capabilities: uint32; } &let { unicode : bool = ( capabilities & 0x0004 ) > 0; large_files : bool = ( capabilities & 0x0008 ) > 0; nt_smbs : bool = ( capabilities & 0x0010 ) > 0; status32 : bool = ( capabilities & 0x0040 ) > 0; level_2_oplocks : bool = ( capabilities & 0x0080 ) > 0; - nt_find : bool = ( capabilities & 0x0200 ) > 0; + nt_find : bool = ( capabilities & 0x0200 ) > 0; }; type SMB1_session_setup_andx_request_ntlm_nonextended_security(header: SMB_Header) = record { - andx : SMB_andx; - max_buffer_size : uint16; - max_mpx_count : uint16; - vc_number : uint16; - session_key : uint32; + andx : SMB_andx; + max_buffer_size : uint16; + max_mpx_count : uint16; + vc_number : uint16; + session_key : uint32; case_insensitive_password_length : uint16; case_sensitive_password_length : uint16; - reserved : uint32; - capabilities : SMB1_session_setup_andx_request_ntlm_capabilities; - byte_count : uint16; - case_insensitive_password : bytestring &length=case_insensitive_password_length; - case_sensitive_password : bytestring &length=case_sensitive_password_length; + reserved : uint32; + capabilities : SMB1_session_setup_andx_request_ntlm_capabilities; + byte_count : uint16; + case_insensitive_password : bytestring &length=case_insensitive_password_length; + case_sensitive_password : bytestring &length=case_sensitive_password_length; # offset + 1 due to word_count in the parent type - account_name : SMB_string(header.unicode, offsetof(account_name) + 1); - primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); - native_os : SMB_string(header.unicode, offsetof(native_os) + 1); - native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); + account_name : SMB_string(header.unicode, offsetof(account_name) + 1); + primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); + native_os : SMB_string(header.unicode, offsetof(native_os) + 1); + native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); }; type SMB1_session_setup_andx_request_ntlm_extended_security(header: SMB_Header) = record { - andx : SMB_andx; - max_buffer_size : uint16; - max_mpx_count : uint16; - vc_number : uint16; - session_key : uint32; - security_blob_length : uint16; - reserved : uint32; - capabilities : SMB1_session_setup_andx_request_ntlm_capabilities; - byte_count : uint16; - security_blob : SMB_NTLM_SSP(header) &length=security_blob_length; + andx : SMB_andx; + max_buffer_size : uint16; + max_mpx_count : uint16; + vc_number : uint16; + session_key : uint32; + security_blob_length : uint16; + reserved : uint32; + capabilities : SMB1_session_setup_andx_request_ntlm_capabilities; + byte_count : uint16; + security_blob : bytestring &length=security_blob_length; # offset + 1 due to word_count in the parent type - native_os : SMB_string(header.unicode, offsetof(native_os) + 1); - native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); + native_os : SMB_string(header.unicode, offsetof(native_os) + 1); + native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); +} &let { + pipe_proc : bool = $context.connection.forward_gssapi(security_blob, true); }; type SMB1_session_setup_andx_response_ntlm(header: SMB_Header) = record { - andx : SMB_andx; - action : uint16; + andx : SMB_andx; + action : uint16; security_blob_length : uint16; - byte_count : uint16; - security_blob : SMB_NTLM_SSP(header) &length=security_blob_length; + byte_count : uint16; + security_blob : bytestring &length=security_blob_length; # offset + 1 due to word_count in the parent type - native_os : SMB_string(header.unicode, offsetof(native_os) + 1); - native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); - primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); + native_os : SMB_string(header.unicode, offsetof(native_os) + 1); + native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1); + primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1); } &let { - is_guest: bool = ( action & 0x1 ) > 0; + is_guest : bool = ( action & 0x1 ) > 0; + gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false); }; diff --git a/src/analyzer/protocol/smb/smb2-com-negotiate.pac b/src/analyzer/protocol/smb/smb2-com-negotiate.pac index c95eec49dc..55e65ccdf2 100644 --- a/src/analyzer/protocol/smb/smb2-com-negotiate.pac +++ b/src/analyzer/protocol/smb/smb2-com-negotiate.pac @@ -62,7 +62,12 @@ type SMB2_negotiate_response(header: SMB2_Header) = record { max_write_size : uint32; system_time : SMB_timestamp; server_start_time : SMB_timestamp; - security : SMB2_security; + security_offset : uint16; + security_length : uint16; + pad1 : padding to security_offset - header.head_length; + security_blob : bytestring &length=security_length; } &byteorder=littleendian, &let { proc : bool = $context.connection.proc_smb2_negotiate_response(header, this); + gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false); + }; \ No newline at end of file diff --git a/src/analyzer/protocol/smb/smb2-com-session-setup.pac b/src/analyzer/protocol/smb/smb2-com-session-setup.pac index ecf7e757be..39ef04ead8 100644 --- a/src/analyzer/protocol/smb/smb2-com-session-setup.pac +++ b/src/analyzer/protocol/smb/smb2-com-session-setup.pac @@ -45,20 +45,27 @@ type SMB2_session_setup_request(header: SMB2_Header) = record { security_mode : uint8; capabilities : uint32; channel : uint32; - security : SMB2_security; + security_offset : uint16; + security_length : uint16; + pad1 : padding to security_offset - header.head_length; + security_blob : bytestring &length=security_length; } &let { proc: bool = $context.connection.proc_smb2_session_setup_request(header, this); + gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, true); }; type SMB2_session_setup_response(header: SMB2_Header) = record { structure_size : uint16; session_flags : uint16; - security : SMB2_security; + security_offset : uint16; + security_length : uint16; + pad1 : padding to security_offset - header.head_length; + security_blob : bytestring &length=security_length; } &let { flag_guest = (session_flags & 0x1) > 0; flag_anonymous = (session_flags & 0x2) > 0; - flag_encrypt = (session_flags & 0x4) > 0; + flag_encrypt = (session_flags & 0x4) > 0; -} &let { proc: bool = $context.connection.proc_smb2_session_setup_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 d9386a8e86..222a8f9d13 100644 --- a/src/analyzer/protocol/smb/smb2-protocol.pac +++ b/src/analyzer/protocol/smb/smb2-protocol.pac @@ -202,14 +202,6 @@ type SMB2_Header(is_orig: bool) = record { proc : bool = $context.connection.proc_smb2_message(this, is_orig); } &byteorder=littleendian; -type SMB2_security = record { - buffer_offset : uint16; - buffer_len : uint16; - # TODO: handle previous session IDs - sec_buffer : bytestring &length = buffer_len; -} &byteorder = littleendian; - - # file ids and guids are the same thing and need unified somehow. type SMB2_guid = record { persistent : uint64; diff --git a/src/analyzer/protocol/smb/smb_ntlmssp.bif b/src/analyzer/protocol/smb/smb_ntlmssp.bif index 4b2f99a482..e69de29bb2 100644 --- a/src/analyzer/protocol/smb/smb_ntlmssp.bif +++ b/src/analyzer/protocol/smb/smb_ntlmssp.bif @@ -1,64 +0,0 @@ -## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message of type *negotiate*. -## -## See `Wikipedia `__ for -## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses -## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445. -## -## c: The connection. -## -## hdr: The parsed header of the SMB message. -## -## negotiate: The parsed data of the NTLM message. See init-bare for more details. -## -event smb_ntlm_negotiate%(c: connection, hdr: SMB1::Header, request: SMB::NTLMNegotiate%); - -## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message of type *challenge*. -## -## See `Wikipedia `__ for -## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses -## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445. -## -## c: The connection. -## -## hdr: The parsed header of the SMB message. -## -## negotiate: The parsed data of the NTLM message. See init-bare for more details. -## -event smb_ntlm_challenge%(c: connection, hdr: SMB1::Header, request: SMB::NTLMChallenge%); - -## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message of type *authenticate*. -## -## See `Wikipedia `__ for -## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses -## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445. -## -## c: The connection. -## -## hdr: The parsed header of the SMB message. -## -## negotiate: The parsed data of the NTLM message. See init-bare for more details. -## -event smb_ntlm_authenticate%(c: connection, hdr: SMB1::Header, request: SMB::NTLMAuthenticate%); - -## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI message of type *accept-completed*. -## -## See `Wikipedia `__ for -## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses -## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445. -## -## c: The connection. -## -## hdr: The parsed header of the SMB message. -## -event smb_ntlm_accepted%(c: connection, hdr: SMB1::Header%); - - -#### Types - -type SMB::NTLMNegotiate: record; -type SMB::NTLMChallenge: record; -type SMB::NTLMAuthenticate: record; - -type SMB::NTLMNegotiateFlags: record; -type SMB::NTLMVersion: record; -type SMB::NTLMAVs: record;