From d9aab840a75ededc286b8e9894e5af7ce6298bbc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Sep 2017 12:06:10 +0200 Subject: packet-kerberos: try to verify the PAC checksums and display the used keys This makes it much easier to analyze how PAC signing is supposed to work with trusted domains. Change-Id: I9993e5d92b7efee5aa91cd0e2005787f7d384444 Signed-off-by: Stefan Metzmacher Reviewed-on: https://code.wireshark.org/review/35704 Petri-Dish: Anders Broman Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- .../asn1/kerberos/packet-kerberos-template.c | 116 ++++++++++++++++++ epan/dissectors/packet-kerberos.c | 130 +++++++++++++++++++-- 2 files changed, 239 insertions(+), 7 deletions(-) (limited to 'epan') diff --git a/epan/dissectors/asn1/kerberos/packet-kerberos-template.c b/epan/dissectors/asn1/kerberos/packet-kerberos-template.c index 4c22cd27d8..55f70c73e0 100644 --- a/epan/dissectors/asn1/kerberos/packet-kerberos-template.c +++ b/epan/dissectors/asn1/kerberos/packet-kerberos-template.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "packet-kerberos.h" #include "packet-netbios.h" #include "packet-tcp.h" @@ -295,6 +296,22 @@ static void used_encryption_key(proto_tree *tree, packet_info *pinfo, ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF); } +#ifdef HAVE_MIT_KERBEROS +static void used_signing_key(proto_tree *tree, packet_info *pinfo, + enc_key_t *ek, tvbuff_t *tvb, + krb5_cksumtype checksum, + const char *reason) +{ + proto_tree_add_expert_format(tree, pinfo, &ei_kerberos_decrypted_keytype, + tvb, 0, 0, + "%s checksum %d keytype %d in frame %u " + "using %s (%02x%02x%02x%02x...)", + reason, checksum, ek->keytype, pinfo->fd->num, ek->key_origin, + ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF, + ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF); +} +#endif /* HAVE_MIT_KERBEROS */ + #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */ #if defined(HAVE_MIT_KERBEROS) @@ -443,6 +460,101 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo, } USES_APPLE_RST +extern krb5_error_code +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *); + +static void +verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) +{ + krb5_error_code ret; + enc_key_t *ek = NULL;; + krb5_data checksum_data = {0,0,NULL}; + krb5_cksumtype server_checksum = 0; + krb5_cksumtype kdc_checksum = 0; + int length = tvb_captured_length(pactvb); + const guint8 *pacbuffer = NULL; + krb5_pac pac; + + /* don't do anything if we are not attempting to decrypt data */ + if(!krb_decrypt || length < 1){ + return; + } + + /* make sure we have all the data we need */ + if (tvb_captured_length(pactvb) < tvb_reported_length(pactvb)) { + return; + } + + pacbuffer = tvb_get_ptr(pactvb, 0, length); + + ret = krb5_pac_parse(krb5_ctx, pacbuffer, length, &pac); + if (ret != 0) { + proto_tree_add_expert_format(tree, actx->pinfo, &ei_kerberos_decrypted_keytype, + pactvb, 0, 0, + "Failed to parse PAC buffer %d in frame %u", + ret, actx->pinfo->fd->num); + return; + } + + ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_SERVER_CHECKSUM, + &checksum_data); + if (ret == 0) { + server_checksum = pletoh32(checksum_data.data); + krb5_free_data_contents(krb5_ctx, &checksum_data); + }; + ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_PRIVSVR_CHECKSUM, + &checksum_data); + if (ret == 0) { + kdc_checksum = pletoh32(checksum_data.data); + krb5_free_data_contents(krb5_ctx, &checksum_data); + }; + + read_keytab_file_from_preferences(); + + for(ek=enc_key_list;ek;ek=ek->next){ + krb5_keyblock keyblock; + krb5_cksumtype checksumtype = 0; + + if (server_checksum == 0 && kdc_checksum == 0) { + break; + } + + ret = krb5int_c_mandatory_cksumtype(krb5_ctx, ek->keytype, + &checksumtype); + if (ret != 0) { + continue; + } + + keyblock.magic = KV5M_KEYBLOCK; + keyblock.enctype = ek->keytype; + keyblock.length = ek->keylength; + keyblock.contents = (guint8 *)ek->keyvalue; + + if (checksumtype == server_checksum) { + ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL, + &keyblock, NULL); + if (ret == 0) { + used_signing_key(tree, actx->pinfo, ek, pactvb, + server_checksum, "Verified Server"); + server_checksum = 0; + } + } + + if (checksumtype == kdc_checksum) { + ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL, + NULL, &keyblock); + if (ret == 0) { + used_signing_key(tree, actx->pinfo, ek, pactvb, + kdc_checksum, "Verified KDC"); + kdc_checksum = 0; + } + } + + } + + krb5_pac_free(krb5_ctx, pac); +} + #elif defined(HAVE_HEIMDAL_KERBEROS) static krb5_context krb5_ctx; @@ -1897,6 +2009,10 @@ dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, guint32 version; guint32 i; +#ifdef HAVE_MIT_KERBEROS + verify_krb5_pac(tree, actx, tvb); +#endif + /* first in the PAC structure comes the number of entries */ entries=tvb_get_letohl(tvb, offset); proto_tree_add_uint(tree, hf_krb_w2k_pac_entries, tvb, offset, 4, entries); diff --git a/epan/dissectors/packet-kerberos.c b/epan/dissectors/packet-kerberos.c index c712aa83ca..2107f8b0a5 100644 --- a/epan/dissectors/packet-kerberos.c +++ b/epan/dissectors/packet-kerberos.c @@ -62,6 +62,7 @@ #include #include #include +#include #include "packet-kerberos.h" #include "packet-netbios.h" #include "packet-tcp.h" @@ -387,7 +388,7 @@ static int hf_kerberos_PAC_OPTIONS_FLAGS_forward_to_full_dc = -1; static int hf_kerberos_PAC_OPTIONS_FLAGS_resource_based_constrained_delegation = -1; /*--- End of included file: packet-kerberos-hf.c ---*/ -#line 173 "./asn1/kerberos/packet-kerberos-template.c" +#line 174 "./asn1/kerberos/packet-kerberos-template.c" /* Initialize the subtree pointers */ static gint ett_kerberos = -1; @@ -475,7 +476,7 @@ static gint ett_kerberos_PA_FX_FAST_REPLY = -1; static gint ett_kerberos_KrbFastArmoredRep = -1; /*--- End of included file: packet-kerberos-ett.c ---*/ -#line 187 "./asn1/kerberos/packet-kerberos-template.c" +#line 188 "./asn1/kerberos/packet-kerberos-template.c" static expert_field ei_kerberos_decrypted_keytype = EI_INIT; static expert_field ei_kerberos_address = EI_INIT; @@ -503,7 +504,7 @@ static gboolean gbl_do_col_info; #define KERBEROS_ADDR_TYPE_IPV6 24 /*--- End of included file: packet-kerberos-val.h ---*/ -#line 199 "./asn1/kerberos/packet-kerberos-template.c" +#line 200 "./asn1/kerberos/packet-kerberos-template.c" static void call_kerberos_callbacks(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int tag, kerberos_callbacks *cb) @@ -598,11 +599,27 @@ static void used_encryption_key(proto_tree *tree, packet_info *pinfo, cryptotvb, 0, 0, "Decrypted keytype %d usage %d in frame %u " "using %s (%02x%02x%02x%02x...)", - ek->keytype, pinfo->fd->num, usage, ek->key_origin, + ek->keytype, usage, pinfo->fd->num, ek->key_origin, ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF, ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF); } +#ifdef HAVE_MIT_KERBEROS +static void used_signing_key(proto_tree *tree, packet_info *pinfo, + enc_key_t *ek, tvbuff_t *tvb, + krb5_cksumtype checksum, + const char *reason) +{ + proto_tree_add_expert_format(tree, pinfo, &ei_kerberos_decrypted_keytype, + tvb, 0, 0, + "%s checksum %d keytype %d in frame %u " + "using %s (%02x%02x%02x%02x...)", + reason, checksum, ek->keytype, pinfo->fd->num, ek->key_origin, + ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF, + ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF); +} +#endif /* HAVE_MIT_KERBEROS */ + #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */ #if defined(HAVE_MIT_KERBEROS) @@ -751,6 +768,101 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo, } USES_APPLE_RST +extern krb5_error_code +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *); + +static void +verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) +{ + krb5_error_code ret; + enc_key_t *ek = NULL;; + krb5_data checksum_data = {0,0,NULL}; + krb5_cksumtype server_checksum = 0; + krb5_cksumtype kdc_checksum = 0; + int length = tvb_captured_length(pactvb); + const guint8 *pacbuffer = NULL; + krb5_pac pac; + + /* don't do anything if we are not attempting to decrypt data */ + if(!krb_decrypt || length < 1){ + return; + } + + /* make sure we have all the data we need */ + if (tvb_captured_length(pactvb) < tvb_reported_length(pactvb)) { + return; + } + + pacbuffer = tvb_get_ptr(pactvb, 0, length); + + ret = krb5_pac_parse(krb5_ctx, pacbuffer, length, &pac); + if (ret != 0) { + proto_tree_add_expert_format(tree, actx->pinfo, &ei_kerberos_decrypted_keytype, + pactvb, 0, 0, + "Failed to parse PAC buffer %d in frame %u", + ret, actx->pinfo->fd->num); + return; + } + + ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_SERVER_CHECKSUM, + &checksum_data); + if (ret == 0) { + server_checksum = pletoh32(checksum_data.data); + krb5_free_data_contents(krb5_ctx, &checksum_data); + }; + ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_PRIVSVR_CHECKSUM, + &checksum_data); + if (ret == 0) { + kdc_checksum = pletoh32(checksum_data.data); + krb5_free_data_contents(krb5_ctx, &checksum_data); + }; + + read_keytab_file_from_preferences(); + + for(ek=enc_key_list;ek;ek=ek->next){ + krb5_keyblock keyblock; + krb5_cksumtype checksumtype = 0; + + if (server_checksum == 0 && kdc_checksum == 0) { + break; + } + + ret = krb5int_c_mandatory_cksumtype(krb5_ctx, ek->keytype, + &checksumtype); + if (ret != 0) { + continue; + } + + keyblock.magic = KV5M_KEYBLOCK; + keyblock.enctype = ek->keytype; + keyblock.length = ek->keylength; + keyblock.contents = (guint8 *)ek->keyvalue; + + if (checksumtype == server_checksum) { + ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL, + &keyblock, NULL); + if (ret == 0) { + used_signing_key(tree, actx->pinfo, ek, pactvb, + server_checksum, "Verified Server"); + server_checksum = 0; + } + } + + if (checksumtype == kdc_checksum) { + ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL, + NULL, &keyblock); + if (ret == 0) { + used_signing_key(tree, actx->pinfo, ek, pactvb, + kdc_checksum, "Verified KDC"); + kdc_checksum = 0; + } + } + + } + + krb5_pac_free(krb5_ctx, pac); +} + #elif defined(HAVE_HEIMDAL_KERBEROS) static krb5_context krb5_ctx; @@ -2205,6 +2317,10 @@ dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, guint32 version; guint32 i; +#ifdef HAVE_MIT_KERBEROS + verify_krb5_pac(tree, actx, tvb); +#endif + /* first in the PAC structure comes the number of entries */ entries=tvb_get_letohl(tvb, offset); proto_tree_add_uint(tree, hf_krb_w2k_pac_entries, tvb, offset, 4, entries); @@ -4657,7 +4773,7 @@ dissect_kerberos_EncryptedChallenge(gboolean implicit_tag _U_, tvbuff_t *tvb _U_ /*--- End of included file: packet-kerberos-fn.c ---*/ -#line 1918 "./asn1/kerberos/packet-kerberos-template.c" +#line 2034 "./asn1/kerberos/packet-kerberos-template.c" /* Make wrappers around exported functions for now */ int @@ -5865,7 +5981,7 @@ void proto_register_kerberos(void) { NULL, HFILL }}, /*--- End of included file: packet-kerberos-hfarr.c ---*/ -#line 2305 "./asn1/kerberos/packet-kerberos-template.c" +#line 2421 "./asn1/kerberos/packet-kerberos-template.c" }; /* List of subtrees */ @@ -5955,7 +6071,7 @@ void proto_register_kerberos(void) { &ett_kerberos_KrbFastArmoredRep, /*--- End of included file: packet-kerberos-ettarr.c ---*/ -#line 2321 "./asn1/kerberos/packet-kerberos-template.c" +#line 2437 "./asn1/kerberos/packet-kerberos-template.c" }; static ei_register_info ei[] = { -- cgit v1.2.3