Kerberos analyzer updates:

- Split up the (quite length) krb-protocol.pac into krb-protocol, krb-defs, krb-types and krb-padata
  - Add some supporting types to get rid of awkward and difficult to read case true/false statements
  - Clean up the conversion code in krb-analyzer.pac
This commit is contained in:
Vlad Grigorescu 2015-01-29 14:15:40 -05:00
parent 1f41c0470c
commit 2d11fafd5e
6 changed files with 565 additions and 591 deletions

View file

@ -4,8 +4,8 @@
%header{ %header{
Val* GetTimeFromAsn1(const KRB_Time* atime); Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs);
Val* GetTimeFromAsn1(StringVal* atime); Val* GetTimeFromAsn1(StringVal* atime, int64 usecs);
Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname); Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname);
@ -13,15 +13,24 @@ Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t);
Val* asn1_integer_to_val(const ASN1Integer* 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_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<KRB_ERROR_Arg*>* args, int64 error_code);
%} %}
%code{ %code{
Val* GetTimeFromAsn1(const KRB_Time* atime) Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs)
{ {
return GetTimeFromAsn1(bytestring_to_val(atime->time())); return GetTimeFromAsn1(bytestring_to_val(atime->time()), usecs);
} }
Val* GetTimeFromAsn1(StringVal* atime) Val* GetTimeFromAsn1(StringVal* atime, int64 usecs)
{ {
time_t lResult = 0; time_t lResult = 0;
@ -57,7 +66,7 @@ Val* GetTimeFromAsn1(StringVal* atime)
if ( !lResult ) if ( !lResult )
lResult = 0; lResult = 0;
return new Val(double(lResult), TYPE_TIME); return new Val(double(lResult + (usecs/100000)), TYPE_TIME);
} }
Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname) Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname)
@ -101,6 +110,294 @@ RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts)
return rv; 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<const u_char*>(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<const u_char*>(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<KRB_ERROR_Arg*>* 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 == 25 )
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);
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));
if ( msg->padata()->has_padata() )
rv->Assign(2, proc_padata(msg->padata()->padata()->padata(), bro_analyzer, false));
for ( uint i = 0; i < msg->body_args()->size(); ++i )
{
KRB_REQ_Arg* element = (*msg->body_args())[i];
switch ( element->seq_meta()->index() )
{
case 0:
rv->Assign(3, proc_krb_kdc_options(element->data()->options()));
break;
case 1:
rv->Assign(4, GetStringFromPrincipalName(element->data()->principal()));
break;
case 2:
rv->Assign(5, bytestring_to_val(element->data()->realm()->encoding()->content()));
break;
case 3:
rv->Assign(6, GetStringFromPrincipalName(element->data()->sname()));
break;
case 4:
rv->Assign(7, GetTimeFromAsn1(element->data()->from(), 0));
break;
case 5:
rv->Assign(8, GetTimeFromAsn1(element->data()->till(), 0));
break;
case 6:
rv->Assign(9, GetTimeFromAsn1(element->data()->rtime(), 0));
break;
case 7:
rv->Assign(10, asn1_integer_to_val(element->data()->nonce(), TYPE_COUNT));
break;
case 8:
if ( element->data()->etype()->data()->size() )
rv->Assign(11, proc_cipher_list(element->data()->etype()));
break;
case 9:
if ( element->data()->addrs()->addresses()->size() )
rv->Assign(12, proc_host_address_list(element->data()->addrs()));
break;
case 10:
// TODO
break;
case 11:
if ( element->data()->addl_tkts()->tickets()->size() )
rv->Assign(13, proc_tickets(element->data()->addl_tkts()));
break;
default:
break;
}
}
return rv;
}
%} %}
refine connection KRB_Conn += { refine connection KRB_Conn += {
@ -114,166 +411,7 @@ refine connection KRB_Conn += {
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 12 ) && ! krb_tgs_req ) if ( ( binary_to_int64(${msg.msg_type.data.content}) == 12 ) && ! krb_tgs_req )
return false; return false;
RecordVal* rv = proc_krb_kdc_req_arguments(${msg}, bro_analyzer());
RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Request);
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));
if ( ${msg.has_padata} )
{
VectorVal* padata = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType());
for ( uint i = 0; i < ${msg.padata.padata_elems}->size(); ++i)
{
switch( ${msg.padata.padata_elems[i].data_type} )
{
case 1:
// will be generated as separate event
break;
case 3:
{
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.pa_pw_salt.encoding.content}));
padata->Assign(padata->Size(), type_val);
break;
}
case 16:
{
const bytestring& cert = ${msg.padata.padata_elems[i].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<const u_char*>(cert.data()),
cert.length(), bro_analyzer()->GetAnalyzerTag(),
bro_analyzer()->Conn(), true, file_id);
file_mgr->EndOfFile(file_id);
break;
}
default:
{
if ( ${msg.padata.padata_elems[i].pa_data_element.unknown}.length() )
{
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.unknown}));
padata->Assign(padata->Size(), type_val);
}
break;
}
}
}
rv->Assign(2, padata);
}
for ( uint i = 0; i < ${msg.body.args}->size(); ++i )
{
switch ( ${msg.body.args[i].seq_meta.index} )
{
case 0:
rv->Assign(3, proc_krb_kdc_options(${msg.body.args[i].data.options}));
break;
case 1:
rv->Assign(4, GetStringFromPrincipalName(${msg.body.args[i].data.principal}));
break;
case 2:
rv->Assign(5, bytestring_to_val(${msg.body.args[i].data.realm.encoding.content}));
break;
case 3:
rv->Assign(6, GetStringFromPrincipalName(${msg.body.args[i].data.sname}));
break;
case 4:
rv->Assign(7, GetTimeFromAsn1(${msg.body.args[i].data.from}));
break;
case 5:
rv->Assign(8, GetTimeFromAsn1(${msg.body.args[i].data.till}));
break;
case 6:
rv->Assign(9, GetTimeFromAsn1(${msg.body.args[i].data.rtime}));
break;
case 7:
rv->Assign(10, asn1_integer_to_val(${msg.body.args[i].data.nonce}, TYPE_COUNT));
break;
case 8:
if ( ${msg.body.args[i].data.etype.data}->size() )
{
VectorVal* ciphers = new VectorVal(internal_type("index_vec")->AsVectorType());
for ( uint j = 0; j < ${msg.body.args[i].data.etype.data}->size(); ++j )
ciphers->Assign(ciphers->Size(), asn1_integer_to_val(${msg.body.args[i].data.etype.data[j]}, TYPE_COUNT));
rv->Assign(11, ciphers);
}
break;
case 9:
if ( ${msg.body.args[i].data.addrs.addresses}->size() )
{
VectorVal* addrs = new VectorVal(internal_type("KRB::Host_Address_Vector")->AsVectorType());
for ( uint j = 0; j < ${msg.body.args[i].data.addrs.addresses}->size(); ++j )
{
RecordVal* addr = new RecordVal(BifType::Record::KRB::Host_Address);
switch ( binary_to_int64(${msg.body.args[i].data.addrs.addresses[j].addr_type.encoding.content}) )
{
case 2:
addr->Assign(0, new AddrVal(IPAddr(IPv4, (const uint32_t*) c_str(${msg.body.args[i].data.addrs.addresses[j].address.data.content}), IPAddr::Network)));
break;
case 24:
addr->Assign(0, new AddrVal(IPAddr(IPv6, (const uint32_t*) c_str(${msg.body.args[i].data.addrs.addresses[j].address.data.content}), IPAddr::Network)));
break;
case 20:
addr->Assign(1, bytestring_to_val(${msg.body.args[i].data.addrs.addresses[j].address.data.content}));
break;
default:
RecordVal* unk = new RecordVal(BifType::Record::KRB::Type_Value);
unk->Assign(0, asn1_integer_to_val(${msg.body.args[i].data.addrs.addresses[j].addr_type}, TYPE_COUNT));
unk->Assign(1, bytestring_to_val(${msg.body.args[i].data.addrs.addresses[j].address.data.content}));
addr->Assign(2, unk);
break;
}
addrs->Assign(addrs->Size(), addr);
}
rv->Assign(12, addrs);
}
break;
case 10:
// TODO
break;
case 11:
if ( ${msg.body.args[i].data.addl_tkts.tickets}->size() )
{
VectorVal* tickets = new VectorVal(internal_type("KRB::Ticket_Vector")->AsVectorType());
for ( uint j = 0; j < ${msg.body.args[i].data.addl_tkts.tickets}->size(); ++j )
{
RecordVal* ticket = new RecordVal(BifType::Record::KRB::Ticket);
ticket->Assign(0, asn1_integer_to_val(${msg.body.args[i].data.addl_tkts.tickets[j].tkt_vno.data}, TYPE_COUNT));
ticket->Assign(1, bytestring_to_val(${msg.body.args[i].data.addl_tkts.tickets[j].realm.data.content}));
ticket->Assign(2, GetStringFromPrincipalName(${msg.body.args[i].data.addl_tkts.tickets[j].sname}));
ticket->Assign(3, asn1_integer_to_val(${msg.body.args[i].data.addl_tkts.tickets[j].enc_part.etype.data}, TYPE_COUNT));
tickets->Assign(tickets->Size(), ticket);
}
rv->Assign(13, tickets);
}
break;
default:
break;
}
}
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 10 ) ) if ( ( binary_to_int64(${msg.msg_type.data.content}) == 10 ) )
BifEvent::generate_krb_as_req(bro_analyzer(), bro_analyzer()->Conn(), rv); BifEvent::generate_krb_as_req(bro_analyzer(), bro_analyzer()->Conn(), rv);
@ -300,63 +438,8 @@ refine connection KRB_Conn += {
rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT)); 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)); rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT));
if ( ${msg.has_padata} ) if ( ${msg.padata.has_padata} )
{ rv->Assign(2, proc_padata(${msg.padata.padata.padata}, bro_analyzer(), false));
VectorVal* padata = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType());
for ( uint i = 0; i < ${msg.padata.padata_elems}->size(); ++i)
{
switch( ${msg.padata.padata_elems[i].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(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.pa_pw_salt.encoding.content}));
padata->Assign(padata->Size(), type_val);
break;
}
case 17:
{
const bytestring& cert = ${msg.padata.padata_elems[i].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<const u_char*>(cert.data()),
cert.length(), bro_analyzer()->GetAnalyzerTag(),
bro_analyzer()->Conn(), false, file_id);
file_mgr->EndOfFile(file_id);
break;
}
default:
{
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.unknown}));
padata->Assign(padata->Size(), type_val);
break;
}
}
}
rv->Assign(2, padata);
}
rv->Assign(3, bytestring_to_val(${msg.client_realm.encoding.content})); rv->Assign(3, bytestring_to_val(${msg.client_realm.encoding.content}));
rv->Assign(4, GetStringFromPrincipalName(${msg.client_name})); rv->Assign(4, GetStringFromPrincipalName(${msg.client_name}));
@ -399,78 +482,9 @@ refine connection KRB_Conn += {
if ( krb_error ) if ( krb_error )
{ {
RecordVal* rv = new RecordVal(BifType::Record::KRB::Error_Msg); RecordVal* rv = new RecordVal(BifType::Record::KRB::Error_Msg);
rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT)); proc_error_arguments(rv, ${msg.args1}, 0);
rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT)); rv->Assign(4, asn1_integer_to_val(${msg.error_code}, TYPE_COUNT));
if ( ${msg.has_ctime} ) proc_error_arguments(rv, ${msg.args2}, binary_to_int64(${msg.error_code.encoding.content}));
rv->Assign(2, GetTimeFromAsn1(bytestring_to_val(${msg.ctime})));
// TODO: if ( ${msg.has_cusec} )
rv->Assign(3, GetTimeFromAsn1(bytestring_to_val(${msg.stime})));
// TODO: ${msg.susec}
rv->Assign(4, asn1_integer_to_val(${msg.error_code.data}, TYPE_COUNT));
for ( uint i = 0; i < ${msg.args}->size(); i++ )
{
switch ( ${msg.args[i].seq_meta.index} )
{
case 7:
rv->Assign(5, bytestring_to_val(${msg.args[i].args.crealm.encoding.content}));
break;
case 8:
rv->Assign(6, GetStringFromPrincipalName(${msg.args[i].args.cname}));
break;
case 9:
rv->Assign(7, bytestring_to_val(${msg.args[i].args.realm.encoding.content}));
break;
case 10:
rv->Assign(8, GetStringFromPrincipalName(${msg.args[i].args.sname}));
break;
case 11:
rv->Assign(9, bytestring_to_val(${msg.args[i].args.e_text.encoding.content}));
break;
case 12:
// if ( ${msg.error_code.data.content}[0] == 25 )
// {
// VectorVal* padata = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType());
// for ( uint j = 0; j < ${msg.args[i].args.e_data.padata.padata_elems}->size(); ++j)
// {
// switch( ${msg.args[i].args.e_data.padata.padata_elems[j].data_type} )
// {
// case 1:
// // will be generated as separate event
// break;
// case 3:
// {
// RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
// type_val->Assign(0, new Val(${msg.args[i].args.e_data.padata.padata_elems[j].data_type}, TYPE_COUNT));
// type_val->Assign(1, bytestring_to_val(${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.pa_pw_salt.encoding.content}));
// padata->Assign(padata->Size(), type_val);
// break;
// }
// default:
// {
// if ( ${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.unknown}.length() )
// {
// RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
// type_val->Assign(0, new Val(${msg.args[i].args.e_data.padata.padata_elems[j].data_type}, TYPE_COUNT));
// type_val->Assign(1, bytestring_to_val(${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.unknown}));
// padata->Assign(padata->Size(), type_val);
// }
// break;
// }
// }
// }
// rv->Assign(10, padata);
// }
break;
default:
break;
}
}
BifEvent::generate_krb_error(bro_analyzer(), bro_analyzer()->Conn(), rv); BifEvent::generate_krb_error(bro_analyzer(), bro_analyzer()->Conn(), rv);
} }
return true; return true;
@ -505,7 +519,13 @@ refine connection KRB_Conn += {
function debug_asn1_encoding_meta(msg: ASN1EncodingMeta): bool function debug_asn1_encoding_meta(msg: ASN1EncodingMeta): bool
%{ %{
printf("ASN1 Element tag=%x, length=%d\n", ${msg.tag}, ${msg.length}); printf("DeBuG ASN1 Element tag=%x, length=%d\n", ${msg.tag}, ${msg.length});
return true;
%}
function debug_krb_error_arg(msg: KRB_ERROR_Arg): bool
%{
printf("DeBuG KRB Error index=%d\n", ${msg.seq_meta.index});
return true; return true;
%} %}
} }
@ -555,7 +575,10 @@ refine typeattr KRB_CRED_MSG += &let {
# proc: bool = $context.connection.debug_req_arg(this); # proc: bool = $context.connection.debug_req_arg(this);
#}; #};
#refine typeattr ASN1EncodingMeta += &let { refine typeattr ASN1EncodingMeta += &let {
# proc: bool = $context.connection.debug_asn1_encoding_meta(this); proc: bool = $context.connection.debug_asn1_encoding_meta(this);
#}; };
refine typeattr KRB_ERROR_Arg += &let {
proc: bool = $context.connection.debug_krb_error_arg(this);
};

View file

@ -14,6 +14,13 @@ type ASN1EncodingMeta = record {
index: uint8 = tag - 160; index: uint8 = tag - 160;
}; };
type ASN1OptionalEncodingMeta(is_present: bool, previous_metadata: ASN1EncodingMeta) = case is_present of {
true -> data: ASN1EncodingMeta;
false -> none: empty;
} &let {
length: uint64 = is_present ? data.length : previous_metadata.length;
};
type ASN1Integer = record { type ASN1Integer = record {
encoding: ASN1Encoding; encoding: ASN1Encoding;
}; };

View file

@ -0,0 +1,13 @@
enum KRBMessageTypes {
AS_REQ = 10,
AS_REP = 11,
TGS_REQ = 12,
TGS_REP = 13,
AP_REQ = 14,
AP_REP = 15,
KRB_SAFE = 20,
KRB_PRIV = 21,
KRB_CRED = 22,
KRB_ERROR = 30,
};

View file

@ -0,0 +1,76 @@
# Kerberos pre-authentication data is a significant piece of the complexity,
# so we're splitting this off
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);
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 {
true -> padata: KRB_PA_Data_Sequence(pkt_type) &length=length;
false -> none: empty;
};
type KRB_PA_Data_Sequence(pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
padata_elems: KRB_PA_Data(pkt_type)[];
};
type KRB_PA_Data(pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
pa_data_type : SequenceElement(true);
pa_data_elem_meta : ASN1EncodingMeta;
have_data : case pkt_type of {
KRB_ERROR -> pa_data_placeholder: bytestring &length=pa_data_elem_meta.length;
default -> pa_data_element : KRB_PA_Data_Element(data_type, pa_data_elem_meta.length);
} &requires(data_type);
} &let {
data_type: int64 = binary_to_int64(pa_data_type.data.content);
};
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;
};
type KRB_PA_PK_AS_Req = record {
string_meta : ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta1: ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta2: ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};
type KRB_PA_PK_AS_Rep = record {
string_meta : ASN1EncodingMeta;
elem_0_meta1: ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta2: ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta3: ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};

View file

@ -1,20 +1,18 @@
# ASN1 parsing
%include krb-asn1.pac %include krb-asn1.pac
enum KRBMessageTypes { # Constants
AS_REQ = 10, %include krb-defs.pac
AS_REP = 11,
TGS_REQ = 12,
TGS_REP = 13,
AP_REQ = 14,
AP_REP = 15,
KRB_SAFE = 20,
KRB_PRIV = 21,
KRB_CRED = 22,
KRB_ERROR = 30,
};
# Basic types
%include krb-types.pac
# Preauth data parsing
%include krb-padata.pac
# KRB over TCP is the same as over UDP, but prefixed with a uint32 denoting the size
type KRB_PDU_TCP = record { type KRB_PDU_TCP = record {
size: uint32; size : uint32;
pdu : KRB_PDU; pdu : KRB_PDU;
} &length=size+4 &byteorder=bigendian; } &length=size+4 &byteorder=bigendian;
@ -31,7 +29,6 @@ type KRB_PDU = record {
KRB_PRIV -> krb_priv : KRB_PRIV_MSG; KRB_PRIV -> krb_priv : KRB_PRIV_MSG;
KRB_CRED -> krb_cred : KRB_CRED_MSG; KRB_CRED -> krb_cred : KRB_CRED_MSG;
KRB_ERROR -> krb_error: KRB_ERROR_MSG; KRB_ERROR -> krb_error: KRB_ERROR_MSG;
default -> unknown : bytestring &restofdata;
}; };
} &byteorder=bigendian; } &byteorder=bigendian;
@ -51,113 +48,15 @@ type KRB_TGS_REP = record {
data: KRB_KDC_REP(TGS_REP); data: KRB_KDC_REP(TGS_REP);
}; };
### KDC_REQ ### A Kerberos ticket-granting-service or authentication-service request
type KRB_KDC_REQ(pkt_type: uint8) = record { type KRB_KDC_REQ(pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta; seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true); pvno : SequenceElement(true);
msg_type : SequenceElement(true); msg_type : SequenceElement(true);
padata_meta: ASN1EncodingMeta; padata : KRB_PA_Data_Optional(pkt_type, 3);
tmp1 : case has_padata of { body_meta : ASN1EncodingMeta;
true -> padata : KRB_PA_Data_Sequence(pkt_type) &length=padata_meta.length; body_args : KRB_REQ_Arg[];
false -> n1 : empty;
};
tmp2 : case has_padata of {
true -> meta2 : ASN1EncodingMeta;
false -> n2 : empty;
};
body : KRB_REQ_Body &length=body_length;
} &let {
has_padata : bool = padata_meta.index == 3;
body_length: uint64 = has_padata ? meta2.length : padata_meta.length;
};
type KRB_PA_Data_Sequence(pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
padata_elems: KRB_PA_Data(pkt_type)[];
};
type KRB_PA_Data(pkttype: uint8) = record {
seq_meta : ASN1EncodingMeta;
pa_data_type : SequenceElement(true);
pa_data_elem_meta : ASN1EncodingMeta;
have_data : case ( pkttype == 30 ) of {
true -> pa_data_placeholder: bytestring &length=pa_data_elem_meta.length;
false -> pa_data_element : KRB_PA_Data_Element(binary_to_int64(pa_data_type.data.content), pa_data_elem_meta.length);
};
} &let {
data_type: int64 = binary_to_int64(pa_data_type.data.content);
};
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;
};
# Octet string metadata
# -- Sequence metadata
# ---- [0] metadata
# ------ Sequence metadata
# -------- OID
# ---------- [0] metadata
# ------------ Sequence metadata
# -------------- version
# -------------- digestAlgorithms
# -------------- signedData
# -------------- certificates
type KRB_PA_PK_AS_Req = record {
string_meta : ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta1: ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta2: ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};
# Octet string metadata
# -- [0] metadata
# ---- Sequence metadata
# ------ [0] metadata
# -------- Sequence metadata
# ---------- OID
# ------------ [0] metadata
# -------------- Sequence metadata
# ---------------- version
# ---------------- digestAlgorithms
# ---------------- signedData
# ---------------- certificates
type KRB_PA_PK_AS_Rep = record {
string_meta : ASN1EncodingMeta;
elem_0_meta1: ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta2: ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta3: ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};
type KRB_REQ_Body = record {
seq_meta : ASN1EncodingMeta;
args : KRB_REQ_Arg[];
}; };
type KRB_REQ_Arg = record { type KRB_REQ_Arg = record {
@ -210,95 +109,18 @@ type KRB_KDC_Options = record {
validate : bool = (flags & 0x1) > 0; validate : bool = (flags & 0x1) > 0;
}; };
type KRB_Principal_Name = record {
seq_meta : ASN1EncodingMeta;
name_meta : ASN1EncodingMeta;
name_type : ASN1Integer;
seq_meta_1: ASN1EncodingMeta;
seq_meta_2: ASN1EncodingMeta;
data : ASN1OctetString[];
};
type KRB_Time = record {
meta: ASN1EncodingMeta;
time: bytestring &restofdata;
};
type KRB_Host_Addresses = record {
seq_meta : ASN1EncodingMeta;
addresses: KRB_Host_Address[];
};
type KRB_Host_Address = record {
addr_type_meta : SequenceElement(false);
addr_type : ASN1Integer;
address : SequenceElement(true);
};
type KRB_Ticket(in_sequence: bool) = record {
have_seq : case in_sequence of {
true -> meta: ASN1EncodingMeta;
false -> none: empty;
};
app_meta : ASN1EncodingMeta;
seq_meta : ASN1EncodingMeta;
tkt_vno : SequenceElement(true);
realm : SequenceElement(true);
sname_meta: ASN1EncodingMeta;
sname : KRB_Principal_Name &length=sname_meta.length;
enc_part : KRB_Encrypted_Data;
};
type KRB_Ticket_Sequence = record {
seq_meta : ASN1EncodingMeta;
tickets : KRB_Ticket(true)[] &length=seq_meta.length;
};
type KRB_Encrypted_Data_in_Seq = record {
index_meta : ASN1EncodingMeta;
data : KRB_Encrypted_Data &length=index_meta.length;
};
type KRB_Encrypted_Data = record {
seq_meta : ASN1EncodingMeta;
etype : SequenceElement(true);
kvno_meta : ASN1EncodingMeta;
case_kvno : case have_kvno of {
true -> kvno : ASN1Integer;
false -> none : empty;
};
grab_next_meta : case have_kvno of {
true -> next_meta: ASN1EncodingMeta;
false -> none_meta: empty;
};
ciphertext : bytestring &length=have_kvno ? next_meta.length : kvno_meta.length;
} &let {
have_kvno : bool = kvno_meta.index == 1;
};
### KDC_REP ### KDC_REP
type KRB_KDC_REP(pkt_type: uint8) = record { type KRB_KDC_REP(pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta; seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true); pvno : SequenceElement(true);
msg_type : SequenceElement(true); msg_type : SequenceElement(true);
padata_meta : ASN1EncodingMeta; padata : KRB_PA_Data_Optional(pkt_type, 2);
tmp1 : case has_padata of { client_realm: ASN1OctetString &length=padata.next_meta.length;
true -> padata : KRB_PA_Data_Sequence(pkt_type) &length=padata_meta.length;
false -> n1 : empty;
};
tmp2 : case has_padata of {
true -> meta2 : ASN1EncodingMeta;
false -> n2 : empty;
};
client_realm: ASN1OctetString &length=realm_length;
cname_meta : ASN1EncodingMeta; cname_meta : ASN1EncodingMeta;
client_name : KRB_Principal_Name &length=cname_meta.length; client_name : KRB_Principal_Name &length=cname_meta.length;
ticket : KRB_Ticket(true); ticket : KRB_Ticket(true);
enc_part : KRB_Encrypted_Data_in_Seq; enc_part : KRB_Encrypted_Data_in_Seq;
} &let {
has_padata : bool = padata_meta.index == 2;
realm_length: uint64 = has_padata ? meta2.length : padata_meta.length;
}; };
### AP_REQ ### AP_REQ
@ -335,56 +157,29 @@ type KRB_AP_REP = record {
### KRB_ERROR ### KRB_ERROR
# pvno [0] INTEGER (5),
# msg-type [1] INTEGER (30),
# ctime [2] KerberosTime OPTIONAL,
# cusec [3] Microseconds OPTIONAL,
# stime [4] KerberosTime,
# susec [5] Microseconds,
# error-code [6] Int32,
# crealm [7] Realm OPTIONAL,
# cname [8] PrincipalName OPTIONAL,
# realm [9] Realm -- service realm --,
# sname [10] PrincipalName -- service name --,
# e-text [11] KerberosString OPTIONAL,
type KRB_ERROR_MSG = record { type KRB_ERROR_MSG = record {
seq_meta : ASN1EncodingMeta; seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true); args1 : KRB_ERROR_Arg(0)[] &until ($element.process_in_parent);
msg_type : SequenceElement(true); error_code : ASN1Integer;
ctime_meta : ASN1EncodingMeta; args2 : KRB_ERROR_Arg(binary_to_int64(error_code.encoding.content))[];
tmp1 : case has_ctime of {
true -> ctime : bytestring &length=ctime_meta.length;
false -> n1 : empty;
};
tmp2 : case has_ctime of {
true -> cusec_meta : ASN1EncodingMeta;
false -> n2 : empty;
};
tmp3 : case has_cusec of {
true -> cusec : ASN1Integer;
false -> n3 : empty;
};
tmp4 : case has_cusec of {
true -> stime_meta : ASN1EncodingMeta;
false -> n4 : empty;
};
stime : bytestring &length=stime_length;
susec : SequenceElement(true);
error_code : SequenceElement(true);
args : KRB_ERROR_Arg(binary_to_int64(error_code.data.content))[];
} &let {
has_ctime: bool = ctime_meta.index == 2;
has_cusec: bool = has_ctime ? cusec_meta.index == 3 : ctime_meta.index == 3;
stime_length: uint64 = has_ctime ? (has_cusec ? stime_meta.length : cusec_meta.length) : (has_cusec ? stime_meta.length : ctime_meta.length);
}; };
type KRB_ERROR_Arg(error_code: uint64) = record { type KRB_ERROR_Arg(error_code: int64) = record {
seq_meta: ASN1EncodingMeta; seq_meta: ASN1EncodingMeta;
args : KRB_ERROR_Arg_Data(seq_meta.index, error_code) &length=seq_meta.length; args : KRB_ERROR_Arg_Data(seq_meta.index, error_code) &length=arg_length;
} &let {
process_in_parent: bool = seq_meta.index == 6;
arg_length : uint64 = ( process_in_parent ? 0 : seq_meta.length);
}; };
type KRB_ERROR_Arg_Data(index: uint8, error_code: uint64) = case index of { type KRB_ERROR_Arg_Data(index: uint8, error_code: int64) = case index of {
0 -> pvno : ASN1Integer;
1 -> msg_type : ASN1Integer;
2 -> ctime : KRB_Time;
3 -> cusec : ASN1Integer;
4 -> stime : KRB_Time;
5 -> susec : ASN1Integer;
6 -> err_code : empty;
7 -> crealm : ASN1OctetString; 7 -> crealm : ASN1OctetString;
8 -> cname : KRB_Principal_Name; 8 -> cname : KRB_Principal_Name;
9 -> realm : ASN1OctetString; 9 -> realm : ASN1OctetString;
@ -394,16 +189,8 @@ type KRB_ERROR_Arg_Data(index: uint8, error_code: uint64) = case index of {
}; };
type KRB_ERROR_E_Data(error_code: uint64) = case ( error_code == 25 ) of { type KRB_ERROR_E_Data(error_code: uint64) = case ( error_code == 25 ) of {
true -> padata : KRB_ERROR_PA_Data;
false -> unknown : bytestring &restofdata;
};
type KRB_ERROR_PA_Data = record {
meta : ASN1EncodingMeta;
have_padata : case ( meta.tag == 30 ) of {
true -> padata : KRB_PA_Data_Sequence(KRB_ERROR); true -> padata : KRB_PA_Data_Sequence(KRB_ERROR);
false -> unknown : bytestring &restofdata; false -> unknown : bytestring &restofdata;
};
}; };
### KRB_SAFE ### KRB_SAFE
@ -434,11 +221,6 @@ type KRB_SAFE_Arg_Data(index: uint8) = case index of {
5 -> recp_addr : KRB_Host_Address; 5 -> recp_addr : KRB_Host_Address;
}; };
type KRB_Checksum = record {
checksum_type: SequenceElement(true);
checksum : SequenceElement(true);
};
### KRB_PRIV ### KRB_PRIV
type KRB_PRIV_MSG = record { type KRB_PRIV_MSG = record {

View file

@ -0,0 +1,73 @@
# Fundamental KRB types
type KRB_Principal_Name = record {
seq_meta : ASN1EncodingMeta;
name_meta : ASN1EncodingMeta;
name_type : ASN1Integer;
seq_meta_1: ASN1EncodingMeta;
seq_meta_2: ASN1EncodingMeta;
data : ASN1OctetString[];
};
type KRB_Time = record {
meta: ASN1EncodingMeta;
time: bytestring &restofdata;
};
type KRB_Host_Addresses = record {
seq_meta : ASN1EncodingMeta;
addresses: KRB_Host_Address[];
};
type KRB_Host_Address = record {
addr_type_meta : SequenceElement(false);
addr_type : ASN1Integer;
address : SequenceElement(true);
};
type KRB_Ticket(in_sequence: bool) = record {
have_seq : case in_sequence of {
true -> meta: ASN1EncodingMeta;
false -> none: empty;
};
app_meta : ASN1EncodingMeta;
seq_meta : ASN1EncodingMeta;
tkt_vno : SequenceElement(true);
realm : SequenceElement(true);
sname_meta: ASN1EncodingMeta;
sname : KRB_Principal_Name &length=sname_meta.length;
enc_part : KRB_Encrypted_Data;
};
type KRB_Ticket_Sequence = record {
seq_meta : ASN1EncodingMeta;
tickets : KRB_Ticket(true)[] &length=seq_meta.length;
};
type KRB_Encrypted_Data_in_Seq = record {
index_meta : ASN1EncodingMeta;
data : KRB_Encrypted_Data &length=index_meta.length;
};
type KRB_Encrypted_Data = record {
seq_meta : ASN1EncodingMeta;
etype : SequenceElement(true);
kvno_meta : ASN1EncodingMeta;
case_kvno : case have_kvno of {
true -> kvno : ASN1Integer;
false -> none : empty;
};
grab_next_meta : case have_kvno of {
true -> next_meta: ASN1EncodingMeta;
false -> none_meta: empty;
};
ciphertext : bytestring &length=have_kvno ? next_meta.length : kvno_meta.length;
} &let {
have_kvno : bool = kvno_meta.index == 1;
};
type KRB_Checksum = record {
checksum_type: SequenceElement(true);
checksum : SequenceElement(true);
};