GSSAPI analyzer now forwards authentication blobs more correctly (and other fixes).

Previously, the GSSAPI analyzer blindly forwarded authentication
blobs to the NTLM analyzer (which it instantiated too early). Now
it waits to instantiate sub analyzers until a blob of a particular
type has been seen.  It also makes the distinction between krb and
ntlm and forwards to the correct analyzer.

This required some fixes to the KRB analyzer because KRB over GSSAPI
looks slightly different than raw KRB.

The KRB analyzer also now includes support for the PA_ENCTYPE_INFO2
pre-auth data type.
This commit is contained in:
Seth Hall 2016-08-09 10:27:21 -04:00
parent 4a3dfe69b1
commit cbde25f1b8
5 changed files with 69 additions and 11 deletions

View file

@ -2,10 +2,12 @@
refine connection GSSAPI_Conn += { refine connection GSSAPI_Conn += {
%member{ %member{
analyzer::Analyzer *ntlm; analyzer::Analyzer *ntlm;
analyzer::Analyzer *krb5;
%} %}
%init{ %init{
ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer->Conn()); ntlm=0;
krb5=0;
%} %}
%cleanup{ %cleanup{
@ -13,13 +15,44 @@ refine connection GSSAPI_Conn += {
{ {
ntlm->Done(); ntlm->Done();
delete ntlm; delete ntlm;
ntlm=0;
}
if ( krb5 )
{
krb5->Done();
delete krb5;
krb5=0;
} }
%} %}
function forward_ntlm(data: bytestring, is_orig: bool): bool function forward_blob(val: GSSAPI_NEG_TOKEN_MECH_TOKEN, is_orig: bool): bool
%{ %{
if ( ${val.mech_token}.length() >= 7 &&
memcmp("NTLMSSP", ${val.mech_token}.begin(), 7) == 0 )
{
// ntlmssp
if ( ! ntlm )
ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer()->Conn());
if ( ntlm ) if ( ntlm )
ntlm->DeliverStream(${data}.length(), ${data}.begin(), is_orig); ntlm->DeliverStream(${val.mech_token}.length(), ${val.mech_token}.begin(), is_orig);
}
else if ( ${val.mech_token}.length() == 9 &&
(memcmp("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", ${val.mech_token}.begin(), ${val.mech_token}.length()) == 0 ||
memcmp("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", ${val.mech_token}.begin(), ${val.mech_token}.length()) == 0 ) )
{
// krb5 && ms-krb5
if ( ! krb5 )
krb5 = analyzer_mgr->InstantiateAnalyzer("KRB", bro_analyzer()->Conn());
// 0x0100 is a special marker
if ( krb5 && memcmp("\x01\x00", ${val.mech_token}.begin(), 2) == 0 )
{
krb5->DeliverPacket(${val.mech_token}.length()-2, ${val.mech_token}.begin()+2, is_orig, 0, 0, 0);
}
}
return true; return true;
%} %}
@ -37,7 +70,7 @@ refine connection GSSAPI_Conn += {
} }
refine typeattr GSSAPI_NEG_TOKEN_MECH_TOKEN += &let { refine typeattr GSSAPI_NEG_TOKEN_MECH_TOKEN += &let {
fwd: bool = $context.connection.forward_ntlm(mech_token, is_orig); fwd: bool = $context.connection.forward_blob(this, is_orig);
}; };
refine typeattr GSSAPI_NEG_TOKEN_RESP_Arg += &let { refine typeattr GSSAPI_NEG_TOKEN_RESP_Arg += &let {

View file

@ -53,3 +53,4 @@ type GSSAPI_NEG_TOKEN_MECH_TOKEN(is_orig: bool) = record {
meta : ASN1EncodingMeta; meta : ASN1EncodingMeta;
mech_token : bytestring &length=meta.length; mech_token : bytestring &length=meta.length;
}; };

View file

@ -19,6 +19,7 @@ enum KRBPADataTypes {
PA_PW_SALT = 3, PA_PW_SALT = 3,
PA_PW_AS_REQ = 16, PA_PW_AS_REQ = 16,
PA_PW_AS_REP = 17, PA_PW_AS_REP = 17,
PA_ENCTYPE_INFO2 = 19,
}; };
# Defined in RFC 4120 # Defined in RFC 4120

View file

@ -41,6 +41,14 @@ VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_a
vv->Assign(vv->Size(), type_val); vv->Assign(vv->Size(), type_val);
break; break;
} }
case PA_ENCTYPE_INFO2:
{
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()->pf_enctype_info2()->salt()));
vv->Assign(vv->Size(), type_val);
break;
}
case PA_PW_AS_REQ: case PA_PW_AS_REQ:
{ {
const bytestring& cert = element->pa_data_element()->pa_pk_as_req()->cert(); const bytestring& cert = element->pa_data_element()->pa_pk_as_req()->cert();
@ -91,11 +99,11 @@ VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_a
} }
default: default:
{ {
if ( ! is_error && element->pa_data_element()->unknown().length() ) if ( ! is_error && element->pa_data_element()->unknown()->meta()->length() > 0 )
{ {
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT)); type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(element->pa_data_element()->unknown())); type_val->Assign(1, bytestring_to_val(element->pa_data_element()->unknown()->content()));
vv->Assign(vv->Size(), type_val); vv->Assign(vv->Size(), type_val);
} }
break; break;
@ -165,13 +173,21 @@ type KRB_PA_Data(is_orig: bool, pkt_type: uint8) = record {
# Each pre-auth element # Each pre-auth element
type KRB_PA_Data_Element(is_orig: bool, type: int64, length: uint64) = case type of { type KRB_PA_Data_Element(is_orig: bool, type: int64, length: uint64) = case type of {
PA_TGS_REQ -> pa_tgs_req : KRB_AP_REQ(is_orig); PA_TGS_REQ -> pa_tgs_req : KRB_PA_AP_REQ_wrapper(is_orig);
PA_PW_SALT -> pa_pw_salt : ASN1OctetString; 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_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; PA_PW_AS_REP -> pa_pk_as_rep : KRB_PA_PK_AS_Rep &length=length;
default -> unknown : bytestring &length=length; PA_ENCTYPE_INFO2 -> pf_enctype_info2 : KRB_PA_ENCTYPE_INFO2 &length=length;
default -> unknown : ASN1Encoding &length=length;
}; };
type KRB_PA_AP_REQ_wrapper(is_orig: bool) = record {
# Not sure what these two field are, but they need to be
# here for pre-auth ap-req messages.
some_meta1 : ASN1EncodingMeta;
some_meta2 : ASN1EncodingMeta;
req : KRB_AP_REQ(is_orig);
};
# The PKINIT certificate structure for a request # The PKINIT certificate structure for a request
type KRB_PA_PK_AS_Req = record { type KRB_PA_PK_AS_Req = record {
@ -210,3 +226,12 @@ type KRB_PA_PK_AS_Rep = record {
: bytestring &restofdata &transient; : bytestring &restofdata &transient;
}; };
type KRB_PA_ENCTYPE_INFO2 = record {
some_meta1 : ASN1EncodingMeta;
some_meta2 : ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
etype : ASN1Encoding;
seq_meta2 : ASN1EncodingMeta;
string_meta : ASN1EncodingMeta;
salt : bytestring &length=string_meta.length;
};

View file

@ -126,8 +126,6 @@ type KRB_KDC_REP(is_orig: bool, pkt_type: uint8) = record {
### AP_REQ ### AP_REQ
type KRB_AP_REQ(is_orig: bool) = record { type KRB_AP_REQ(is_orig: bool) = record {
string_meta : ASN1EncodingMeta;
app_meta : ASN1EncodingMeta;
seq_meta : ASN1EncodingMeta; seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true); pvno : SequenceElement(true);
msg_type : SequenceElement(true); msg_type : SequenceElement(true);