mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Add Kerberos support for PKINIT (x509 cert authentication)
This commit is contained in:
parent
3c3920bfbc
commit
b8376ca733
5 changed files with 313 additions and 42 deletions
|
@ -1,2 +1,3 @@
|
||||||
@load ./main
|
@load ./main
|
||||||
|
@load ./files
|
||||||
@load-sigs ./dpd.sig
|
@load-sigs ./dpd.sig
|
142
scripts/base/protocols/krb/files.bro
Normal file
142
scripts/base/protocols/krb/files.bro
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
@load ./main
|
||||||
|
@load base/utils/conn-ids
|
||||||
|
@load base/frameworks/files
|
||||||
|
@load base/files/x509
|
||||||
|
|
||||||
|
module KRB;
|
||||||
|
|
||||||
|
export {
|
||||||
|
redef record Info += {
|
||||||
|
# Client certificate
|
||||||
|
client_cert: Files::Info &optional;
|
||||||
|
# Subject of client certificate, if any
|
||||||
|
client_cert_subject:string &log &optional;
|
||||||
|
# File unique ID of client cert, if any
|
||||||
|
client_cert_fuid: string &log &optional;
|
||||||
|
|
||||||
|
# Server certificate
|
||||||
|
server_cert: Files::Info &optional;
|
||||||
|
# Subject of server certificate, if any
|
||||||
|
server_cert_subject:string &log &optional;
|
||||||
|
# File unique ID of server cert, if any
|
||||||
|
server_cert_fuid: string &log &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## Default file handle provider for KRB.
|
||||||
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
|
||||||
|
## Default file describer for KRB.
|
||||||
|
global describe_file: function(f: fa_file): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
|
{
|
||||||
|
# Unused. File handles are generated in the analyzer.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function describe_file(f: fa_file): string
|
||||||
|
{
|
||||||
|
if ( f$source != "KRB_TCP" && f$source != "KRB" )
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if ( ! f?$info || ! f$info?$x509 || ! f$info$x509?$certificate )
|
||||||
|
return "";
|
||||||
|
|
||||||
|
# It is difficult to reliably describe a certificate - especially since
|
||||||
|
# we do not know when this function is called (hence, if the data structures
|
||||||
|
# are already populated).
|
||||||
|
#
|
||||||
|
# Just return a bit of our connection information and hope that that is good enough.
|
||||||
|
for ( cid in f$conns )
|
||||||
|
{
|
||||||
|
if ( f$conns[cid]?$krb )
|
||||||
|
{
|
||||||
|
local c = f$conns[cid];
|
||||||
|
return cat(c$id$resp_h, ":", c$id$resp_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cat("Serial: ", f$info$x509$certificate$serial, " Subject: ",
|
||||||
|
f$info$x509$certificate$subject, " Issuer: ",
|
||||||
|
f$info$x509$certificate$issuer);
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
Files::register_protocol(Analyzer::ANALYZER_KRB_TCP,
|
||||||
|
[$get_file_handle = KRB::get_file_handle,
|
||||||
|
$describe = KRB::describe_file]);
|
||||||
|
|
||||||
|
Files::register_protocol(Analyzer::ANALYZER_KRB,
|
||||||
|
[$get_file_handle = KRB::get_file_handle,
|
||||||
|
$describe = KRB::describe_file]);
|
||||||
|
}
|
||||||
|
|
||||||
|
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||||
|
{
|
||||||
|
if ( f$source != "KRB_TCP" && f$source != "KRB" )
|
||||||
|
return;
|
||||||
|
|
||||||
|
local info: Info;
|
||||||
|
|
||||||
|
if ( ! c?$krb )
|
||||||
|
{
|
||||||
|
info$ts = network_time();
|
||||||
|
info$uid = c$uid;
|
||||||
|
info$id = c$id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
info = c$krb;
|
||||||
|
|
||||||
|
if ( is_orig )
|
||||||
|
{
|
||||||
|
info$client_cert = f$info;
|
||||||
|
info$client_cert_fuid = f$id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info$server_cert = f$info;
|
||||||
|
info$server_cert_fuid = f$id;
|
||||||
|
}
|
||||||
|
|
||||||
|
c$krb = info;
|
||||||
|
|
||||||
|
Files::add_analyzer(f, Files::ANALYZER_X509);
|
||||||
|
# always calculate hashes. They are not necessary for base scripts
|
||||||
|
# but very useful for identification, and required for policy scripts
|
||||||
|
Files::add_analyzer(f, Files::ANALYZER_MD5);
|
||||||
|
Files::add_analyzer(f, Files::ANALYZER_SHA1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fill_in_subjects(c: connection)
|
||||||
|
{
|
||||||
|
if ( !c?$krb )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( c$krb?$client_cert && c$krb$client_cert?$x509 && c$krb$client_cert$x509?$certificate )
|
||||||
|
c$krb$client_cert_subject = c$krb$client_cert$x509$certificate$subject;
|
||||||
|
|
||||||
|
if ( c$krb?$server_cert && c$krb$server_cert?$x509 && c$krb$server_cert$x509?$certificate )
|
||||||
|
c$krb$server_cert_subject = c$krb$server_cert$x509$certificate$subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_error(c: connection, msg: Error_Msg)
|
||||||
|
{
|
||||||
|
fill_in_subjects(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_as_rep(c: connection, msg: KDC_Reply)
|
||||||
|
{
|
||||||
|
fill_in_subjects(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_tgs_rep(c: connection, msg: KDC_Reply)
|
||||||
|
{
|
||||||
|
fill_in_subjects(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
event connection_state_remove(c: connection)
|
||||||
|
{
|
||||||
|
fill_in_subjects(c);
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ export {
|
||||||
} &redef;
|
} &redef;
|
||||||
|
|
||||||
## Event that can be handled to access the KRB record as it is sent on
|
## Event that can be handled to access the KRB record as it is sent on
|
||||||
## to the loggin framework.
|
## to the logging framework.
|
||||||
global log_krb: event(rec: Info);
|
global log_krb: event(rec: Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ event bro_init() &priority=5
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_KRB_TCP, tcp_ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_KRB_TCP, tcp_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
event krb_error(c: connection, msg: Error_Msg)
|
event krb_error(c: connection, msg: Error_Msg) &priority=5
|
||||||
{
|
{
|
||||||
local info: Info;
|
local info: Info;
|
||||||
|
|
||||||
|
@ -123,21 +123,30 @@ event krb_error(c: connection, msg: Error_Msg)
|
||||||
info$error_msg = error_msg[msg$error_code];
|
info$error_msg = error_msg[msg$error_code];
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::write(KRB::LOG, info);
|
|
||||||
info$logged = T;
|
|
||||||
|
|
||||||
c$krb = info;
|
c$krb = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
event krb_as_req(c: connection, msg: KDC_Request)
|
event krb_error(c: connection, msg: Error_Msg) &priority=-5
|
||||||
|
{
|
||||||
|
Log::write(KRB::LOG, c$krb);
|
||||||
|
c$krb$logged = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_as_req(c: connection, msg: KDC_Request) &priority=5
|
||||||
{
|
{
|
||||||
if ( c?$krb && c$krb$logged )
|
if ( c?$krb && c$krb$logged )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
local info: Info;
|
local info: Info;
|
||||||
info$ts = network_time();
|
|
||||||
info$uid = c$uid;
|
if ( !c?$krb )
|
||||||
info$id = c$id;
|
{
|
||||||
|
info$ts = network_time();
|
||||||
|
info$uid = c$uid;
|
||||||
|
info$id = c$id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
info = c$krb;
|
||||||
|
|
||||||
info$client = fmt("%s/%s", msg$client_name, msg$service_realm);
|
info$client = fmt("%s/%s", msg$client_name, msg$service_realm);
|
||||||
info$service = msg$service_name;
|
info$service = msg$service_name;
|
||||||
|
@ -174,7 +183,7 @@ event krb_as_req(c: connection, msg: KDC_Request)
|
||||||
c$krb = info;
|
c$krb = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
event krb_tgs_req(c: connection, msg: KDC_Request)
|
event krb_tgs_req(c: connection, msg: KDC_Request) &priority=5
|
||||||
{
|
{
|
||||||
if ( c?$krb && c$krb$logged )
|
if ( c?$krb && c$krb$logged )
|
||||||
return;
|
return;
|
||||||
|
@ -191,7 +200,40 @@ event krb_tgs_req(c: connection, msg: KDC_Request)
|
||||||
c$krb = info;
|
c$krb = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
event krb_as_rep(c: connection, msg: KDC_Reply)
|
event krb_as_rep(c: connection, msg: KDC_Reply) &priority=5
|
||||||
|
{
|
||||||
|
local info: Info;
|
||||||
|
|
||||||
|
if ( c?$krb && c$krb$logged )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( c?$krb )
|
||||||
|
info = c$krb;
|
||||||
|
|
||||||
|
if ( ! info?$ts )
|
||||||
|
{
|
||||||
|
info$ts = network_time();
|
||||||
|
info$uid = c$uid;
|
||||||
|
info$id = c$id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! info?$client )
|
||||||
|
info$client = fmt("%s/%s", msg$client_name, msg$client_realm);
|
||||||
|
|
||||||
|
info$service = msg$ticket$service_name;
|
||||||
|
info$result = "success";
|
||||||
|
|
||||||
|
c$krb = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_as_rep(c: connection, msg: KDC_Reply) &priority=-5
|
||||||
|
{
|
||||||
|
|
||||||
|
Log::write(KRB::LOG, c$krb);
|
||||||
|
c$krb$logged = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
event krb_tgs_rep(c: connection, msg: KDC_Reply) &priority=5
|
||||||
{
|
{
|
||||||
local info: Info;
|
local info: Info;
|
||||||
|
|
||||||
|
@ -214,42 +256,16 @@ event krb_as_rep(c: connection, msg: KDC_Reply)
|
||||||
info$service = msg$ticket$service_name;
|
info$service = msg$ticket$service_name;
|
||||||
info$result = "success";
|
info$result = "success";
|
||||||
|
|
||||||
Log::write(KRB::LOG, info);
|
|
||||||
info$logged = T;
|
|
||||||
|
|
||||||
c$krb = info;
|
c$krb = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
event krb_tgs_rep(c: connection, msg: KDC_Reply)
|
event krb_tgs_rep(c: connection, msg: KDC_Reply) &priority=-5
|
||||||
{
|
{
|
||||||
local info: Info;
|
Log::write(KRB::LOG, c$krb);
|
||||||
|
c$krb$logged = T;
|
||||||
if ( c?$krb && c$krb$logged )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( c?$krb )
|
|
||||||
info = c$krb;
|
|
||||||
|
|
||||||
if ( ! info?$ts )
|
|
||||||
{
|
|
||||||
info$ts = network_time();
|
|
||||||
info$uid = c$uid;
|
|
||||||
info$id = c$id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! info?$client )
|
|
||||||
info$client = fmt("%s/%s", msg$client_name, msg$client_realm);
|
|
||||||
|
|
||||||
info$service = msg$ticket$service_name;
|
|
||||||
info$result = "success";
|
|
||||||
|
|
||||||
Log::write(KRB::LOG, info);
|
|
||||||
info$logged = T;
|
|
||||||
|
|
||||||
c$krb = info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event connection_state_remove(c: connection)
|
event connection_state_remove(c: connection) &priority=-5
|
||||||
{
|
{
|
||||||
if ( c?$krb && ! c$krb$logged )
|
if ( c?$krb && ! c$krb$logged )
|
||||||
Log::write(KRB::LOG, c$krb);
|
Log::write(KRB::LOG, c$krb);
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
%extern{
|
||||||
|
#include "file_analysis/Manager.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
%header{
|
%header{
|
||||||
Val* GetTimeFromAsn1(const KRB_Time* atime);
|
Val* GetTimeFromAsn1(const KRB_Time* atime);
|
||||||
Val* GetTimeFromAsn1(StringVal* atime);
|
Val* GetTimeFromAsn1(StringVal* atime);
|
||||||
|
@ -132,6 +137,29 @@ refine connection KRB_Conn += {
|
||||||
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
|
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}));
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -292,6 +320,29 @@ refine connection KRB_Conn += {
|
||||||
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
|
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}));
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -506,4 +557,5 @@ refine typeattr KRB_CRED_MSG += &let {
|
||||||
|
|
||||||
#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);
|
||||||
#};
|
#};
|
||||||
|
|
||||||
|
|
|
@ -89,9 +89,69 @@ type KRB_PA_Data = record {
|
||||||
type KRB_PA_Data_Element(type: int64, length: uint64) = case type of {
|
type KRB_PA_Data_Element(type: int64, length: uint64) = case type of {
|
||||||
1 -> pa_tgs_req : KRB_AP_REQ;
|
1 -> pa_tgs_req : KRB_AP_REQ;
|
||||||
3 -> pa_pw_salt : ASN1OctetString;
|
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;
|
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 {
|
type KRB_REQ_Body = record {
|
||||||
seq_meta : ASN1EncodingMeta;
|
seq_meta : ASN1EncodingMeta;
|
||||||
args : KRB_REQ_Arg[];
|
args : KRB_REQ_Arg[];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue