diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 431e172d6e..a8bd2ba8c9 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3027,6 +3027,38 @@ export { }; type KRB::Type_Value_Vector: vector of KRB::Type_Value; + + + ## A Kerberos host address See :rfc:`4120`. + type KRB::Host_Address: record { + ## IPv4 or IPv6 address + ip : addr &log &optional; + ## NetBIOS address + netbios : string &log &optional; + ## Some other type that we don't support yet + unknown : KRB::Type_Value &optional; + }; + + type KRB::Host_Address_Vector: vector of KRB::Host_Address; + + ## The data from the SAFE message. See :rfc:`4120`. + type KRB::SAFE_Msg: record { + ## Protocol version number (5 for KRB5) + pvno : count; + ## The message type (20 for SAFE_MSG) + msg_type : count; + ## The application-specific data that is being passed + ## from the sender to the reciever + data : string; + ## Current time from the sender of the message + timestamp : time &optional; + ## Sequence number used to detect replays + seq : count &optional; + ## Sender address + sender : Host_Address &optional; + ## Recipient address + recipient : Host_Address &optional; + }; ## The data from the ERROR_MSG message. See :rfc:`4120`. type KRB::Error_Msg: record { @@ -3069,18 +3101,6 @@ export { type KRB::Ticket_Vector: vector of KRB::Ticket; - ## A Kerberos host address See :rfc:`4120`. - type KRB::Host_Address: record { - ## IPv4 or IPv6 address - ip : addr &log &optional; - ## NetBIOS address - netbios : string &log &optional; - ## Some other type that we don't support yet - unknown : KRB::Type_Value &optional; - }; - - type KRB::Host_Address_Vector: vector of KRB::Host_Address; - ## The data from the AS_REQ and TGS_REQ messages. See :rfc:`4120`. type KRB::KDC_Request: record { ## Protocol version number (5 for KRB5) diff --git a/src/analyzer/protocol/krb/events.bif b/src/analyzer/protocol/krb/events.bif index 052863cbb7..93dcb6c462 100644 --- a/src/analyzer/protocol/krb/events.bif +++ b/src/analyzer/protocol/krb/events.bif @@ -67,6 +67,14 @@ event krb_priv%(c: connection%); ## msg: A Kerberos KDC request message data structure. event krb_cred%(c: connection, tickets: KRB::Ticket_Vector%); +## A Kerberos 5 ``Credential Message`` as defined +## in :rfc:`4120`. +## +## c: The connection over which this Kerberos message was sent. +## +## msg: A Kerberos KDC request message data structure. +event krb_safe_msg%(c: connection, msg: KRB::SAFE_Msg%); + ## A Kerberos 5 ``ERROR_MSG`` as defined in :rfc:`4120`. ## ## c: The connection over which this Kerberos message was sent. diff --git a/src/analyzer/protocol/krb/krb-analyzer.pac b/src/analyzer/protocol/krb/krb-analyzer.pac index 07e034e075..cc987db3dd 100644 --- a/src/analyzer/protocol/krb/krb-analyzer.pac +++ b/src/analyzer/protocol/krb/krb-analyzer.pac @@ -27,76 +27,6 @@ RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts) return rv; } -bool proc_error_arguments(RecordVal* rv, const std::vector* args, int64 error_code ) -{ - uint ctime_i = 0, ctime_usecs_i = 0, stime_i = 0, stime_usecs_i = 0; - int64 ctime_usecs = 0, stime_usecs = 0; - - // We need to do a pass first, to see if we have microseconds for the timestamp values, which are optional - - for ( uint i = 0; i < args->size(); i++ ) - { - switch ( (*args)[i]->seq_meta()->index() ) - { - case 2: - ctime_i = i; - break; - case 3: - ctime_usecs_i = i; - break; - case 4: - stime_i = i; - break; - case 5: - stime_usecs_i = i; - break; - } - } - - if ( ctime_usecs_i ) ctime_usecs = binary_to_int64((*args)[ctime_usecs_i]->args()->cusec()->encoding()->content()); - if ( ctime_i ) rv->Assign(2, GetTimeFromAsn1((*args)[ctime_i]->args()->ctime(), ctime_usecs)); - - if ( stime_usecs_i ) stime_usecs = binary_to_int64((*args)[stime_usecs_i]->args()->susec()->encoding()->content()); - if ( stime_i ) rv->Assign(3, GetTimeFromAsn1((*args)[stime_i]->args()->stime(), stime_usecs)); - - for ( uint i = 0; i < args->size(); i++ ) - { - switch ( (*args)[i]->seq_meta()->index() ) - { - case 0: - rv->Assign(0, asn1_integer_to_val((*args)[i]->args()->pvno(), TYPE_COUNT)); - break; - case 1: - rv->Assign(1, asn1_integer_to_val((*args)[i]->args()->msg_type(), TYPE_COUNT)); - break; - // ctime/stime handled above - case 7: - rv->Assign(5, bytestring_to_val((*args)[i]->args()->crealm()->encoding()->content())); - break; - case 8: - rv->Assign(6, GetStringFromPrincipalName((*args)[i]->args()->cname())); - break; - case 9: - rv->Assign(7, bytestring_to_val((*args)[i]->args()->realm()->encoding()->content())); - break; - case 10: - rv->Assign(8, GetStringFromPrincipalName((*args)[i]->args()->sname())); - break; - case 11: - rv->Assign(9, bytestring_to_val((*args)[i]->args()->e_text()->encoding()->content())); - break; - case 12: - if ( error_code == KDC_ERR_PREAUTH_REQUIRED ) - rv->Assign(10, proc_padata((*args)[i]->args()->e_data()->padata(), NULL, true)); - break; - default: - break; - } - } - - return true; -} - RecordVal* proc_krb_kdc_req_arguments(KRB_KDC_REQ* msg, const BroAnalyzer bro_analyzer) { RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Request); @@ -162,6 +92,76 @@ RecordVal* proc_krb_kdc_req_arguments(KRB_KDC_REQ* msg, const BroAnalyzer bro_an return rv; } + +bool proc_error_arguments(RecordVal* rv, const std::vector* args, int64 error_code ) +{ + uint ctime_i = 0, stime_i = 0; + int64 ctime_usecs = 0, stime_usecs = 0; + + // We need to do a pass first, to see if we have microseconds for the timestamp values, which are optional + + for ( uint i = 0; i < args->size(); i++ ) + { + switch ( (*args)[i]->seq_meta()->index() ) + { + case 2: + ctime_i = i; + break; + case 3: + ctime_usecs = binary_to_int64((*args)[i]->args()->cusec()->encoding()->content()); + break; + case 4: + stime_i = i; + break; + case 5: + stime_usecs = binary_to_int64((*args)[i]->args()->susec()->encoding()->content()); + break; + default: + break; + } + } + + if ( ctime_i ) rv->Assign(2, GetTimeFromAsn1((*args)[ctime_i]->args()->ctime(), ctime_usecs)); + if ( stime_i ) rv->Assign(3, GetTimeFromAsn1((*args)[stime_i]->args()->stime(), stime_usecs)); + + for ( uint i = 0; i < args->size(); ++i ) + { + switch ( (*args)[i]->seq_meta()->index() ) + { + case 0: + rv->Assign(0, asn1_integer_to_val((*args)[i]->args()->pvno(), TYPE_COUNT)); + break; + case 1: + rv->Assign(1, asn1_integer_to_val((*args)[i]->args()->msg_type(), TYPE_COUNT)); + break; + // ctime/stime handled above + case 7: + rv->Assign(5, bytestring_to_val((*args)[i]->args()->crealm()->encoding()->content())); + break; + case 8: + rv->Assign(6, GetStringFromPrincipalName((*args)[i]->args()->cname())); + break; + case 9: + rv->Assign(7, bytestring_to_val((*args)[i]->args()->realm()->encoding()->content())); + break; + case 10: + rv->Assign(8, GetStringFromPrincipalName((*args)[i]->args()->sname())); + break; + case 11: + rv->Assign(9, bytestring_to_val((*args)[i]->args()->e_text()->encoding()->content())); + break; + case 12: + if ( error_code == KDC_ERR_PREAUTH_REQUIRED ) + rv->Assign(10, proc_padata((*args)[i]->args()->e_data()->padata(), NULL, true)); + break; + default: + break; + } + } + + return true; +} + %} refine connection KRB_Conn += { @@ -261,8 +261,59 @@ refine connection KRB_Conn += { function proc_krb_safe_msg(msg: KRB_SAFE_MSG): bool %{ bro_analyzer()->ProtocolConfirmation(); - // Not implemented - return true; + if ( krb_safe_msg ) + { + RecordVal* rv = new RecordVal(BifType::Record::KRB::SAFE_Msg); + + rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT)); + rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT)); + + uint timestamp_i = 0; + int64 timestamp_usecs = 0; + + // We need to do a pass first, to see if we have microseconds for the timestamp values, which are optional + + for ( uint i = 0; i < ${msg.safe_body.args}->size(); ++i ) + { + switch ( ${msg.safe_body.args[i].seq_meta.index} ) + { + case 1: + timestamp_i = i; + break; + case 2: + timestamp_usecs = binary_to_int64(${msg.safe_body.args[i].args.usec.encoding.content}); + break; + default: + break; + } + } + + if ( timestamp_i ) + rv->Assign(4, GetTimeFromAsn1(${msg.safe_body.args[timestamp_i].args.timestamp}, timestamp_usecs)); + + for ( uint i = 0; i < ${msg.safe_body.args}->size(); ++i ) + { + switch ( ${msg.safe_body.args[i].seq_meta.index} ) + { + case 0: + rv->Assign(3, bytestring_to_val(${msg.safe_body.args[i].args.user_data.encoding.content})); + break; + case 3: + rv->Assign(5, asn1_integer_to_val(${msg.safe_body.args[i].args.seq_number}, TYPE_COUNT)); + break; + case 4: + rv->Assign(6, proc_host_address(${msg.safe_body.args[i].args.sender_addr})); + break; + case 5: + rv->Assign(7, proc_host_address(${msg.safe_body.args[i].args.recp_addr})); + break; + default: + break; + } + } + BifEvent::generate_krb_safe_msg(bro_analyzer(), bro_analyzer()->Conn(), rv); + } + return true; %} function proc_krb_priv_msg(msg: KRB_PRIV_MSG): bool @@ -283,6 +334,7 @@ refine connection KRB_Conn += { BifEvent::generate_krb_cred(bro_analyzer(), bro_analyzer()->Conn(), proc_tickets(${msg.tickets})); } return true; + %} } diff --git a/src/analyzer/protocol/krb/krb-types.pac b/src/analyzer/protocol/krb/krb-types.pac index 8306d9a6f0..614081d189 100644 --- a/src/analyzer/protocol/krb/krb-types.pac +++ b/src/analyzer/protocol/krb/krb-types.pac @@ -4,7 +4,9 @@ Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname); VectorVal* proc_cipher_list(const Array* list); + VectorVal* proc_host_address_list(const KRB_Host_Addresses* list); +RecordVal* proc_host_address(const KRB_Host_Address* addr); VectorVal* proc_tickets(const KRB_Ticket_Sequence* list); RecordVal* proc_ticket(const KRB_Ticket* ticket); @@ -35,37 +37,41 @@ VectorVal* proc_host_address_list(const KRB_Host_Addresses* list) for ( uint i = 0; i < list->addresses()->size(); ++i ) { - RecordVal* addr = new RecordVal(BifType::Record::KRB::Host_Address); - KRB_Host_Address* element = (*list->addresses())[i]; - - switch ( binary_to_int64(element->addr_type()->encoding()->content()) ) - { - case 2: - addr->Assign(0, new AddrVal(IPAddr(IPv4, - (const uint32_t*) c_str(element->address()->data()->content()), - IPAddr::Network))); - break; - case 24: - addr->Assign(0, new AddrVal(IPAddr(IPv6, - (const uint32_t*) c_str(element->address()->data()->content()), - IPAddr::Network))); - break; - case 20: - addr->Assign(1, bytestring_to_val(element->address()->data()->content())); - break; - default: - RecordVal* unk = new RecordVal(BifType::Record::KRB::Type_Value); - unk->Assign(0, asn1_integer_to_val(element->addr_type(), TYPE_COUNT)); - unk->Assign(1, bytestring_to_val(element->address()->data()->content())); - addr->Assign(2, unk); - break; - } - addrs->Assign(addrs->Size(), addr); + addrs->Assign(addrs->Size(), proc_host_address((*list->addresses())[i])); } return addrs; } +RecordVal* proc_host_address(const KRB_Host_Address* addr) +{ + RecordVal* rv = new RecordVal(BifType::Record::KRB::Host_Address); + + switch ( binary_to_int64(addr->addr_type()->encoding()->content()) ) + { + case 2: + rv->Assign(0, new AddrVal(IPAddr(IPv4, + (const uint32_t*) c_str(addr->address()->data()->content()), + IPAddr::Network))); + break; + case 24: + rv->Assign(0, new AddrVal(IPAddr(IPv6, + (const uint32_t*) c_str(addr->address()->data()->content()), + IPAddr::Network))); + break; + case 20: + rv->Assign(1, bytestring_to_val(addr->address()->data()->content())); + break; + default: + RecordVal* unk = new RecordVal(BifType::Record::KRB::Type_Value); + unk->Assign(0, asn1_integer_to_val(addr->addr_type(), TYPE_COUNT)); + unk->Assign(1, bytestring_to_val(addr->address()->data()->content())); + rv->Assign(2, unk); + break; + } + + return rv; +} VectorVal* proc_tickets(const KRB_Ticket_Sequence* list) { diff --git a/src/analyzer/protocol/krb/types.bif b/src/analyzer/protocol/krb/types.bif index 54ac492b00..a16c18bf64 100644 --- a/src/analyzer/protocol/krb/types.bif +++ b/src/analyzer/protocol/krb/types.bif @@ -1,6 +1,7 @@ module KRB; type Error_Msg: record; +type SAFE_Msg: record; type KDC_Options: record; type AP_Options: record;