diff --git a/src/analyzer/protocol/krb/krb-analyzer.pac b/src/analyzer/protocol/krb/krb-analyzer.pac index 71d6a48ed5..76bce5894c 100644 --- a/src/analyzer/protocol/krb/krb-analyzer.pac +++ b/src/analyzer/protocol/krb/krb-analyzer.pac @@ -1,94 +1,11 @@ -%extern{ -#include "file_analysis/Manager.h" -%} - - %header{ -Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs); -Val* GetTimeFromAsn1(StringVal* atime, int64 usecs); - -Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname); - -Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t); -Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t); - RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts); RecordVal* proc_krb_kdc_req_arguments(KRB_KDC_REQ* msg, const BroAnalyzer bro_analyzer); -VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error); - -VectorVal* proc_cipher_list(const Array* list); -VectorVal* proc_host_address_list(const KRB_Host_Addresses* list); -VectorVal* proc_tickets(const KRB_Ticket_Sequence* list); - bool proc_error_arguments(RecordVal* rv, const std::vector* args, int64 error_code); %} %code{ -Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs) - { - return GetTimeFromAsn1(bytestring_to_val(atime->time()), usecs); - } - -Val* GetTimeFromAsn1(StringVal* atime, int64 usecs) - { - time_t lResult = 0; - - char lBuffer[17]; - char* pBuffer = lBuffer; - - size_t lTimeLength = atime->Len(); - char * pString = (char *) atime->Bytes(); - - if ( lTimeLength != 15 && lTimeLength != 17 ) - return 0; - - if (lTimeLength == 17 ) - pString = pString + 2; - - memcpy(pBuffer, pString, 15); - *(pBuffer+15) = '\0'; - - tm lTime; - lTime.tm_sec = ((lBuffer[12] - '0') * 10) + (lBuffer[13] - '0'); - lTime.tm_min = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0'); - lTime.tm_hour = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0'); - lTime.tm_mday = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0'); - lTime.tm_mon = (((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0')) - 1; - lTime.tm_year = ((lBuffer[0] - '0') * 1000) + ((lBuffer[1] - '0') * 100) + ((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0') - 1900; - - lTime.tm_wday = 0; - lTime.tm_yday = 0; - lTime.tm_isdst = 0; - - lResult = timegm(&lTime); - - if ( !lResult ) - lResult = 0; - - return new Val(double(lResult + (usecs/100000)), TYPE_TIME); - } - -Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname) -{ - if ( pname->data()->size() == 1 ) - return bytestring_to_val(pname->data()[0][0]->encoding()->content()); - if ( pname->data()->size() == 2 ) - return new StringVal(fmt("%s/%s", (char *) pname->data()[0][0]->encoding()->content().begin(), (char *)pname->data()[0][1]->encoding()->content().begin())); - - return new StringVal("unknown"); -} - -Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t) -{ - return asn1_integer_to_val(i->encoding(), t); -} - -Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t) -{ - return new Val(binary_to_int64(i->content()), t); -} - RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts) { RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Options); @@ -110,159 +27,6 @@ RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts) return rv; } -VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error) -{ - VectorVal* vv = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType()); - for ( uint i = 0; i < data->padata_elems()->size(); ++i) - { - KRB_PA_Data* element = (*data->padata_elems())[i]; - int64 data_type = element->data_type(); - - if ( is_error && ( data_type == 16 || data_type == 17 ) ) - data_type = 0; - - switch( data_type ) - { - case 1: - // will be generated as separate event - break; - case 2: - // encrypted timestamp is unreadable - break; - case 3: - { - RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); - type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT)); - type_val->Assign(1, bytestring_to_val(element->pa_data_element()->pa_pw_salt()->encoding()->content())); - vv->Assign(vv->Size(), type_val); - break; - } - case 16: - { - const bytestring& cert = element->pa_data_element()->pa_pk_as_req()->cert(); - - ODesc common; - common.AddRaw("Analyzer::ANALYZER_KRB"); - common.Add(bro_analyzer->Conn()->StartTime()); - common.AddRaw("T", 1); - bro_analyzer->Conn()->IDString(&common); - - ODesc file_handle; - file_handle.Add(common.Description()); - file_handle.Add(0); - - string file_id = file_mgr->HashHandle(file_handle.Description()); - - file_mgr->DataIn(reinterpret_cast(cert.data()), - cert.length(), bro_analyzer->GetAnalyzerTag(), - bro_analyzer->Conn(), true, file_id); - file_mgr->EndOfFile(file_id); - - break; - } - case 17: - { - const bytestring& cert = element->pa_data_element()->pa_pk_as_rep()->cert(); - - ODesc common; - common.AddRaw("Analyzer::ANALYZER_KRB"); - common.Add(bro_analyzer->Conn()->StartTime()); - common.AddRaw("F", 1); - bro_analyzer->Conn()->IDString(&common); - - ODesc file_handle; - file_handle.Add(common.Description()); - file_handle.Add(1); - - string file_id = file_mgr->HashHandle(file_handle.Description()); - - file_mgr->DataIn(reinterpret_cast(cert.data()), - cert.length(), bro_analyzer->GetAnalyzerTag(), - bro_analyzer->Conn(), false, file_id); - file_mgr->EndOfFile(file_id); - - break; - } - default: - { - if ( ! is_error && element->pa_data_element()->unknown().length() ) - { - RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); - type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT)); - type_val->Assign(1, bytestring_to_val(element->pa_data_element()->unknown())); - vv->Assign(vv->Size(), type_val); - } - break; - } - } - } - return vv; -} - -VectorVal* proc_cipher_list(const Array* list) -{ - VectorVal* ciphers = new VectorVal(internal_type("index_vec")->AsVectorType()); - for ( uint i = 0; i < list->data()->size(); ++i ) - ciphers->Assign(ciphers->Size(), asn1_integer_to_val((*list->data())[i], TYPE_COUNT)); - return ciphers; -} - -VectorVal* proc_host_address_list(const KRB_Host_Addresses* list) -{ - VectorVal* addrs = new VectorVal(internal_type("KRB::Host_Address_Vector")->AsVectorType()); - - 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); - } - - return addrs; -} - - -VectorVal* proc_tickets(const KRB_Ticket_Sequence* list) -{ - VectorVal* tickets = new VectorVal(internal_type("KRB::Ticket_Vector")->AsVectorType()); - for ( uint i = 0; i < list->tickets()->size(); ++i ) - { - KRB_Ticket* element = (*list->tickets())[i]; - RecordVal* ticket = new RecordVal(BifType::Record::KRB::Ticket); - - ticket->Assign(0, asn1_integer_to_val(element->tkt_vno()->data(), TYPE_COUNT)); - ticket->Assign(1, bytestring_to_val(element->realm()->data()->content())); - ticket->Assign(2, GetStringFromPrincipalName(element->sname())); - ticket->Assign(3, asn1_integer_to_val(element->enc_part()->etype()->data(), TYPE_COUNT)); - tickets->Assign(tickets->Size(), ticket); - } - - return tickets; -} - 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; @@ -322,7 +86,7 @@ bool proc_error_arguments(RecordVal* rv, const std::vector* args rv->Assign(9, bytestring_to_val((*args)[i]->args()->e_text()->encoding()->content())); break; case 12: - if ( error_code == 25 ) + if ( error_code == KDC_ERR_PREAUTH_REQUIRED ) rv->Assign(10, proc_padata((*args)[i]->args()->e_data()->padata(), NULL, true)); break; default: @@ -537,39 +301,39 @@ refine typeattr KRB_AS_REQ += &let { refine typeattr KRB_TGS_REQ += &let { proc: bool = $context.connection.proc_krb_kdc_req(data); - }; +}; refine typeattr KRB_AS_REP += &let { proc: bool = $context.connection.proc_krb_kdc_rep(data); - }; +}; refine typeattr KRB_TGS_REP += &let { proc: bool = $context.connection.proc_krb_kdc_rep(data); - }; +}; refine typeattr KRB_AP_REQ += &let { proc: bool = $context.connection.proc_krb_ap_req(this); - }; +}; refine typeattr KRB_AP_REP += &let { proc: bool = $context.connection.proc_krb_ap_rep(this); - }; +}; refine typeattr KRB_ERROR_MSG += &let { proc: bool = $context.connection.proc_krb_error_msg(this); - }; +}; refine typeattr KRB_SAFE_MSG += &let { proc: bool = $context.connection.proc_krb_safe_msg(this); - }; +}; refine typeattr KRB_PRIV_MSG += &let { proc: bool = $context.connection.proc_krb_priv_msg(this); - }; +}; refine typeattr KRB_CRED_MSG += &let { proc: bool = $context.connection.proc_krb_cred_msg(this); - }; +}; #refine typeattr KRB_REQ_Arg_Data += &let { # proc: bool = $context.connection.debug_req_arg(this); diff --git a/src/analyzer/protocol/krb/krb-asn1.pac b/src/analyzer/protocol/krb/krb-asn1.pac index 5706c02384..c74f0c5af9 100644 --- a/src/analyzer/protocol/krb/krb-asn1.pac +++ b/src/analyzer/protocol/krb/krb-asn1.pac @@ -1,3 +1,67 @@ +%header{ +Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs); +Val* GetTimeFromAsn1(StringVal* atime, int64 usecs); + +Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t); +Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t); +%} + +%code{ +Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs) + { + return GetTimeFromAsn1(bytestring_to_val(atime->time()), usecs); + } + +Val* GetTimeFromAsn1(StringVal* atime, int64 usecs) + { + time_t lResult = 0; + + char lBuffer[17]; + char* pBuffer = lBuffer; + + size_t lTimeLength = atime->Len(); + char * pString = (char *) atime->Bytes(); + + if ( lTimeLength != 15 && lTimeLength != 17 ) + return 0; + + if (lTimeLength == 17 ) + pString = pString + 2; + + memcpy(pBuffer, pString, 15); + *(pBuffer+15) = '\0'; + + tm lTime; + lTime.tm_sec = ((lBuffer[12] - '0') * 10) + (lBuffer[13] - '0'); + lTime.tm_min = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0'); + lTime.tm_hour = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0'); + lTime.tm_mday = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0'); + lTime.tm_mon = (((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0')) - 1; + lTime.tm_year = ((lBuffer[0] - '0') * 1000) + ((lBuffer[1] - '0') * 100) + ((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0') - 1900; + + lTime.tm_wday = 0; + lTime.tm_yday = 0; + lTime.tm_isdst = 0; + + lResult = timegm(&lTime); + + if ( !lResult ) + lResult = 0; + + return new Val(double(lResult + (usecs/100000)), TYPE_TIME); + } + + Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t) + { + return asn1_integer_to_val(i->encoding(), t); + } + + Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t) + { + return new Val(binary_to_int64(i->content()), t); + } +%} + type ASN1Encoding = record { meta: ASN1EncodingMeta; content: bytestring &length = meta.length; @@ -10,8 +74,8 @@ type ASN1EncodingMeta = record { } &let { long_len: bool = (len & 0x80) > 0; length: uint64 = long_len ? binary_to_int64(more_len) : len; - has_index: bool = (tag >= 160); - index: uint8 = tag - 160; + has_index: bool = (tag >= ASN1_INDEX_TAG_OFFSET); + index: uint8 = tag - ASN1_INDEX_TAG_OFFSET; }; type ASN1OptionalEncodingMeta(is_present: bool, previous_metadata: ASN1EncodingMeta) = case is_present of { diff --git a/src/analyzer/protocol/krb/krb-defs.pac b/src/analyzer/protocol/krb/krb-defs.pac index fc801ccffa..e7e0f78159 100644 --- a/src/analyzer/protocol/krb/krb-defs.pac +++ b/src/analyzer/protocol/krb/krb-defs.pac @@ -1,3 +1,4 @@ +# Defined in RFC 4120 enum KRBMessageTypes { AS_REQ = 10, AS_REP = 11, @@ -11,3 +12,23 @@ enum KRBMessageTypes { KRB_ERROR = 30, }; +# Defined by IANA in Kerberos Parameters - Pre-authentication and Typed Data +enum KRBPADataTypes { + PA_TGS_REQ = 1, + PA_ENC_TIMESTAMP = 2, + PA_PW_SALT = 3, + PA_PW_AS_REQ = 16, + PA_PW_AS_REP = 17, +}; + +# Defined in RFC 4120 +enum KRBErrorCodes { + KDC_ERR_PREAUTH_REQUIRED = 25, +}; + +# Defined in ASN.1 +enum ASN1Consts { + ASN1_SEQUENCE_TAG = 48, + ASN1_APP_TAG_OFFSET = 96, + ASN1_INDEX_TAG_OFFSET = 160, +}; diff --git a/src/analyzer/protocol/krb/krb-padata.pac b/src/analyzer/protocol/krb/krb-padata.pac index bcf66ee208..df52c20053 100644 --- a/src/analyzer/protocol/krb/krb-padata.pac +++ b/src/analyzer/protocol/krb/krb-padata.pac @@ -1,24 +1,156 @@ # Kerberos pre-authentication data is a significant piece of the complexity, # so we're splitting this off +%extern{ +#include "file_analysis/Manager.h" +%} + +%header{ +VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error); +%} + +%code{ +VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error) +{ + VectorVal* vv = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType()); + + if ( ! data->data()->has_padata() ) + return vv; + + for ( uint i = 0; i < data->data()->padata_elems()->size(); ++i) + { + KRB_PA_Data* element = (*data->data()->padata_elems())[i]; + int64 data_type = element->data_type(); + + if ( is_error && ( data_type == PA_PW_AS_REQ || data_type == PA_PW_AS_REP ) ) + data_type = 0; + + switch( data_type ) + { + case PA_TGS_REQ: + // will be generated as separate event + break; + case PA_ENC_TIMESTAMP: + // encrypted timestamp is unreadable + break; + case PA_PW_SALT: + { + RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); + type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT)); + type_val->Assign(1, bytestring_to_val(element->pa_data_element()->pa_pw_salt()->encoding()->content())); + vv->Assign(vv->Size(), type_val); + break; + } + case PA_PW_AS_REQ: + { + const bytestring& cert = element->pa_data_element()->pa_pk_as_req()->cert(); + + ODesc common; + common.AddRaw("Analyzer::ANALYZER_KRB"); + common.Add(bro_analyzer->Conn()->StartTime()); + // Request means is_orig=T + common.AddRaw("T", 1); + bro_analyzer->Conn()->IDString(&common); + + ODesc file_handle; + file_handle.Add(common.Description()); + file_handle.Add(0); + + string file_id = file_mgr->HashHandle(file_handle.Description()); + + file_mgr->DataIn(reinterpret_cast(cert.data()), + cert.length(), bro_analyzer->GetAnalyzerTag(), + bro_analyzer->Conn(), true, file_id); + file_mgr->EndOfFile(file_id); + + break; + } + case PA_PW_AS_REP: + { + const bytestring& cert = element->pa_data_element()->pa_pk_as_rep()->cert(); + + ODesc common; + common.AddRaw("Analyzer::ANALYZER_KRB"); + common.Add(bro_analyzer->Conn()->StartTime()); + // Response means is_orig=F + common.AddRaw("F", 1); + bro_analyzer->Conn()->IDString(&common); + + ODesc file_handle; + file_handle.Add(common.Description()); + file_handle.Add(1); + + string file_id = file_mgr->HashHandle(file_handle.Description()); + + file_mgr->DataIn(reinterpret_cast(cert.data()), + cert.length(), bro_analyzer->GetAnalyzerTag(), + bro_analyzer->Conn(), false, file_id); + file_mgr->EndOfFile(file_id); + + break; + } + default: + { + if ( ! is_error && element->pa_data_element()->unknown().length() ) + { + RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); + type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT)); + type_val->Assign(1, bytestring_to_val(element->pa_data_element()->unknown())); + vv->Assign(vv->Size(), type_val); + } + break; + } + } + } + return vv; +} +%} + +# Basic structure: +# 1) In KDC_REQ/KDC_REP packets, the PA_Data is optional and needs a bit of "lookahead." +# KRB_PA_Data_Optional -> KRB_PA_Data_Optional_Contents -> KRB_PA_Data_Sequence +# +# 2) Once we get to the KRB_PA_Data_Sequence level: +# KRB_PA_Data_Sequence -> KRB_PA_Data_Container -> KRB_PA_Data -> KRB_PA_Data_Element + + +# Encapsulating header #1 for KDC_REQ/KDC_REP packets where the PADATA is optional. type KRB_PA_Data_Optional(pkt_type: uint8, desired_index: uint8) = record { first_meta : ASN1EncodingMeta; - padata : KRB_PA_Data_Field(has_padata, pkt_type, first_meta.length); + padata : KRB_PA_Data_Optional_Contents(has_padata, pkt_type, first_meta.length); next_meta : ASN1OptionalEncodingMeta(has_padata, first_meta); } &let { has_padata : bool = first_meta.index == desired_index; }; -type KRB_PA_Data_Field(is_present: bool, pkt_type: uint8, length: uint64) = case is_present of { +# Encapsulating header #2 for KDC_REQ/KDC_REP packets where the PADATA is optional. +# +# Note: Split off due to a BinPAC bug +type KRB_PA_Data_Optional_Contents(is_present: bool, pkt_type: uint8, length: uint64) = case is_present of { true -> padata: KRB_PA_Data_Sequence(pkt_type) &length=length; false -> none: empty; }; +# This is our main type type KRB_PA_Data_Sequence(pkt_type: uint8) = record { - seq_meta : ASN1EncodingMeta; - padata_elems: KRB_PA_Data(pkt_type)[]; + meta : ASN1EncodingMeta; + data : KRB_PA_Data_Container(pkt_type, meta.tag, meta.length); }; +# The data in KRB_PA_Data_Sequence is usually (and supposed to be) a sequence, which we'll parse, +# but is sometimes an octet string. We'll grab that but ignore it. +# +# Note: This is a separate type due to a BinPAC bug. +type KRB_PA_Data_Container(pkt_type: uint8, tag: uint8, length: uint64) = case tag of { + ASN1_SEQUENCE_TAG -> padata_elems : KRB_PA_Data(pkt_type)[]; + default -> unknown : bytestring &length=length; +} &let { + has_padata: bool = (tag == ASN1_SEQUENCE_TAG); +}; + +# The pre-auth data sequence. +# +# Note: Error packets don't have pre-auth data, they just advertise which mechanisms they support. type KRB_PA_Data(pkt_type: uint8) = record { seq_meta : ASN1EncodingMeta; pa_data_type : SequenceElement(true); @@ -31,21 +163,24 @@ type KRB_PA_Data(pkt_type: uint8) = record { data_type: int64 = binary_to_int64(pa_data_type.data.content); }; +# Each pre-auth element type KRB_PA_Data_Element(type: int64, length: uint64) = case type of { - 1 -> pa_tgs_req : KRB_AP_REQ; - 3 -> pa_pw_salt : ASN1OctetString; - 16 -> pa_pk_as_req : KRB_PA_PK_AS_Req &length=length; - 17 -> pa_pk_as_rep : KRB_PA_PK_AS_Rep &length=length; - default -> unknown : bytestring &length=length; + PA_TGS_REQ -> pa_tgs_req : KRB_AP_REQ; + PA_PW_SALT -> pa_pw_salt : ASN1OctetString; + PA_PW_AS_REQ -> pa_pk_as_req : KRB_PA_PK_AS_Req &length=length; + PA_PW_AS_REP -> pa_pk_as_rep : KRB_PA_PK_AS_Rep &length=length; + default -> unknown : bytestring &length=length; }; + +# The PKINIT certificate structure for a request type KRB_PA_PK_AS_Req = record { - string_meta : ASN1EncodingMeta; + string_meta : ASN1EncodingMeta; seq_meta1 : ASN1EncodingMeta; - elem_0_meta1: ASN1EncodingMeta; + elem_0_meta1 : ASN1EncodingMeta; seq_meta2 : ASN1EncodingMeta; - oid : ASN1Encoding; - elem_0_meta2: ASN1EncodingMeta; + oid : ASN1Encoding; + elem_0_meta2 : ASN1EncodingMeta; seq_meta3 : ASN1EncodingMeta; version : ASN1Encoding; digest_algs : ASN1Encoding; @@ -53,17 +188,18 @@ type KRB_PA_PK_AS_Req = record { cert_meta : ASN1EncodingMeta; cert : bytestring &length=cert_meta.length; # Ignore everything else - : bytestring &restofdata &transient; + : bytestring &restofdata &transient; }; +# The PKINIT certificate structure for a reply type KRB_PA_PK_AS_Rep = record { - string_meta : ASN1EncodingMeta; - elem_0_meta1: ASN1EncodingMeta; + string_meta : ASN1EncodingMeta; + elem_0_meta1 : ASN1EncodingMeta; seq_meta1 : ASN1EncodingMeta; - elem_0_meta2: ASN1EncodingMeta; + elem_0_meta2 : ASN1EncodingMeta; seq_meta2 : ASN1EncodingMeta; - oid : ASN1Encoding; - elem_0_meta3: ASN1EncodingMeta; + oid : ASN1Encoding; + elem_0_meta3 : ASN1EncodingMeta; seq_meta3 : ASN1EncodingMeta; version : ASN1Encoding; digest_algs : ASN1Encoding; @@ -71,6 +207,6 @@ type KRB_PA_PK_AS_Rep = record { cert_meta : ASN1EncodingMeta; cert : bytestring &length=cert_meta.length; # Ignore everything else - : bytestring &restofdata &transient; + : bytestring &restofdata &transient; }; diff --git a/src/analyzer/protocol/krb/krb-protocol.pac b/src/analyzer/protocol/krb/krb-protocol.pac index 1ec6e75cca..b64f9a72f6 100644 --- a/src/analyzer/protocol/krb/krb-protocol.pac +++ b/src/analyzer/protocol/krb/krb-protocol.pac @@ -18,7 +18,7 @@ type KRB_PDU_TCP = record { type KRB_PDU = record { app_meta : ASN1EncodingMeta; - msg_type : case (app_meta.tag - 96) of { + msg_type : case (app_meta.tag - ASN1_APP_TAG_OFFSET) of { AS_REQ -> as_req : KRB_AS_REQ; AS_REP -> as_rep : KRB_AS_REP; TGS_REQ -> tgs_req : KRB_TGS_REQ; @@ -188,7 +188,7 @@ type KRB_ERROR_Arg_Data(index: uint8, error_code: int64) = case index of { 12 -> e_data : KRB_ERROR_E_Data(error_code); }; -type KRB_ERROR_E_Data(error_code: uint64) = case ( error_code == 25 ) of { +type KRB_ERROR_E_Data(error_code: uint64) = case ( error_code == KDC_ERR_PREAUTH_REQUIRED ) of { true -> padata : KRB_PA_Data_Sequence(KRB_ERROR); false -> unknown : bytestring &restofdata; }; diff --git a/src/analyzer/protocol/krb/krb-types.pac b/src/analyzer/protocol/krb/krb-types.pac index 9ada8a137c..e8f4b75d9b 100644 --- a/src/analyzer/protocol/krb/krb-types.pac +++ b/src/analyzer/protocol/krb/krb-types.pac @@ -1,5 +1,89 @@ # Fundamental KRB types +%header{ +Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname); + +VectorVal* proc_cipher_list(const Array* list); +VectorVal* proc_host_address_list(const KRB_Host_Addresses* list); +VectorVal* proc_tickets(const KRB_Ticket_Sequence* list); +%} + +%code{ +Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname) +{ + if ( pname->data()->size() == 1 ) + return bytestring_to_val(pname->data()[0][0]->encoding()->content()); + if ( pname->data()->size() == 2 ) + return new StringVal(fmt("%s/%s", (char *) pname->data()[0][0]->encoding()->content().begin(), (char *)pname->data()[0][1]->encoding()->content().begin())); + + return new StringVal("unknown"); +} + +VectorVal* proc_cipher_list(const Array* list) +{ + VectorVal* ciphers = new VectorVal(internal_type("index_vec")->AsVectorType()); + for ( uint i = 0; i < list->data()->size(); ++i ) + ciphers->Assign(ciphers->Size(), asn1_integer_to_val((*list->data())[i], TYPE_COUNT)); + return ciphers; +} + +VectorVal* proc_host_address_list(const KRB_Host_Addresses* list) +{ + VectorVal* addrs = new VectorVal(internal_type("KRB::Host_Address_Vector")->AsVectorType()); + + 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); + } + + return addrs; +} + + +VectorVal* proc_tickets(const KRB_Ticket_Sequence* list) +{ + VectorVal* tickets = new VectorVal(internal_type("KRB::Ticket_Vector")->AsVectorType()); + for ( uint i = 0; i < list->tickets()->size(); ++i ) + { + KRB_Ticket* element = (*list->tickets())[i]; + RecordVal* ticket = new RecordVal(BifType::Record::KRB::Ticket); + + ticket->Assign(0, asn1_integer_to_val(element->tkt_vno()->data(), TYPE_COUNT)); + ticket->Assign(1, bytestring_to_val(element->realm()->data()->content())); + ticket->Assign(2, GetStringFromPrincipalName(element->sname())); + ticket->Assign(3, asn1_integer_to_val(element->enc_part()->etype()->data(), TYPE_COUNT)); + tickets->Assign(tickets->Size(), ticket); + } + + return tickets; +} +%} + type KRB_Principal_Name = record { seq_meta : ASN1EncodingMeta; name_meta : ASN1EncodingMeta;