From 7eb369db9b771de5ec3a11d077fc8ca94ce673bf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 28 Jan 2022 14:02:34 +0100 Subject: [PATCH] nthashes --- epan/dissectors/pidl/drsuapi/drsuapi.cnf | 145 +++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 8 deletions(-) diff --git a/epan/dissectors/pidl/drsuapi/drsuapi.cnf b/epan/dissectors/pidl/drsuapi/drsuapi.cnf index bf8c591a43..14a25ea67e 100644 --- a/epan/dissectors/pidl/drsuapi/drsuapi.cnf +++ b/epan/dissectors/pidl/drsuapi/drsuapi.cnf @@ -756,6 +756,65 @@ drsuapi_dissect_supplementalCredentials(tvbuff_t *tvb _U_, packet_info *pinfo _U hf_drsuapi_sch_supplementalCredentials, 0); } +static int +drsuapi_dissect_unicodePwd(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *parent_tree _U_, dcerpc_info* parent_di _U_) +{ + int offset = 0; + dcerpc_ptr_stack *ptr = parent_di->ptr_stack; + guint32 rid = 0; + int keytype = 23; + int keylength = 16; + tvbuff_t *keytvb = tvb_new_subset_length(tvb, offset, keylength); + guint8 keyvalue[KRB_MAX_KEY_LENGTH] = {0,}; + char origin[128] = {0, }; + + if (ptr != NULL && ptr->parent != NULL) { + rid = ptr->parent->private_data.val64; + } + + tvb_memcpy(keytvb, keyvalue, 0, MIN(keylength, KRB_MAX_KEY_LENGTH)); + snprintf(origin, sizeof(origin)-1, "RID=%u drsuapi.unicodePwd", rid); + + kerberos_inject_longterm_key(pinfo, parent_tree, NULL, keytvb, + keytype, keylength, keyvalue, + origin); + offset += 16; + + return offset; +} + +static int +drsuapi_dissect_ntPwdHistory(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *parent_tree _U_, dcerpc_info* parent_di _U_) +{ + dcerpc_ptr_stack *ptr = parent_di->ptr_stack; + guint32 rid = 0; + guint num_hashes = tvb_reported_length(tvb)/16; + guint idx; + int offset = 0; + + if (ptr != NULL && ptr->parent != NULL) { + rid = ptr->parent->private_data.val64; + } + + for (idx = 0; idx < num_hashes; idx++) { + int keytype = 23; + int keylength = 16; + tvbuff_t *keytvb = tvb_new_subset_length(tvb, offset, keylength); + guint8 keyvalue[KRB_MAX_KEY_LENGTH] = {0,}; + char origin[128] = {0, }; + + tvb_memcpy(keytvb, keyvalue, 0, MIN(keylength, KRB_MAX_KEY_LENGTH)); + snprintf(origin, sizeof(origin)-1, "RID=%u drsuapi.ntPwdHistory[%u]", rid, idx); + + kerberos_inject_longterm_key(pinfo, parent_tree, NULL, keytvb, + keytype, keylength, keyvalue, + origin); + offset += 16; + } + + return offset; +} + typedef int (*attr_dissector_fn_t)(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *parent_tree _U_, dcerpc_info* parent_di _U_); static int @@ -775,9 +834,13 @@ drsuapi_dissect_element_DsAttributeValue_blob_(tvbuff_t *tvb _U_, int offset _U_ gcry_error_t err; guint8 *buf = NULL; int buf_len; - tvbuff_t *plain_tvb = NULL; + guint8 *payload_buf = NULL; + int payload_len = 0; + tvbuff_t *payload_tvb = NULL; gboolean rid_crypt = FALSE; + const char *attr_name = NULL; attr_dissector_fn_t attr_dissector_fn = NULL; + char source_name[64] = { 0,}; offset = dissect_ndr_datablob(tvb, offset, pinfo, tree, di, drep, hf_drsuapi_drsuapi_DsAttributeValue_blob, 0); if (ptr == NULL) { @@ -792,20 +855,44 @@ drsuapi_dissect_element_DsAttributeValue_blob_(tvbuff_t *tvb _U_, int offset _U_ switch (attid) { case DRSUAPI_ATTID_dBCSPwd: + attr_name = "dBCSPwd"; + rid_crypt = TRUE; + break; case DRSUAPI_ATTID_unicodePwd: + attr_name = "unicodePwd"; + attr_dissector_fn = drsuapi_dissect_unicodePwd; + rid_crypt = TRUE; + break; case DRSUAPI_ATTID_ntPwdHistory: + attr_name = "ntPwdHistory"; + attr_dissector_fn = drsuapi_dissect_ntPwdHistory; + rid_crypt = TRUE; + break; case DRSUAPI_ATTID_lmPwdHistory: + attr_name = "lmPwdHistory"; rid_crypt = TRUE; break; case DRSUAPI_ATTID_supplementalCredentials: + attr_name = "supplementalCredentials"; attr_dissector_fn = drsuapi_dissect_supplementalCredentials; break; case DRSUAPI_ATTID_priorValue: + attr_name = "priorValue"; + break; case DRSUAPI_ATTID_currentValue: + attr_name = "currentValue"; + break; case DRSUAPI_ATTID_trustAuthOutgoing: + attr_name = "trustAuthOutgoing"; + break; case DRSUAPI_ATTID_trustAuthIncoming: + attr_name = "trustAuthIncoming"; + break; case DRSUAPI_ATTID_initialAuthOutgoing: + attr_name = "initialAuthOutgoing"; + break; case DRSUAPI_ATTID_initialAuthIncoming: + attr_name = "initialAuthIncoming"; break; default: return offset; @@ -821,9 +908,9 @@ drsuapi_dissect_element_DsAttributeValue_blob_(tvbuff_t *tvb _U_, int offset _U_ if (0) { proto_tree_add_text_internal(tree, tvb, start_offset, length, - "METZE rid_crypt:%s RID:%d ATTID:0x%08X length=%d session_key=%s", + "METZE rid_crypt:%s RID:%d ATTID:0x%08X ATTR[%s] length=%d session_key=%s", rid_crypt ? "YES" : "NO", - rid, attid, + rid, attid, attr_name, length, di->auth_session_key != NULL ? di->auth_session_key->id_str : "NO"); @@ -875,19 +962,61 @@ if (0) { } gcry_cipher_close(rc4_handle); - if (rid_crypt) { - return offset; + payload_buf = buf + 4; + payload_len = buf_len - 4; + + if (rid_crypt && rid != 0) { + guint8 rk[14]; + guint8 ri = 0; + guint8 *hb = payload_buf; + guint32 hl = payload_len; + guint32 hi; + + /* + * We have a payload contains one or more + * NT Hashes (16 bytes each). + */ + if ((hl % 16) != 0) { + return offset; + } + + /* + * We build a 112 bit key based on the RID + * + * With that we need to decrypt each NT Hash (16 byte) + * + * DES is based on 8 byte blocks, which mean + * we can use the first 7 bytes (56Bit) of the key to + * decrypt the first 8 bytes of the NT Hash and + * the last 7 bytes (also 56Bit) of the key to + * decrypt the 2nd 8 bytes of the NT Hash. + */ + + rk[0] = rk[4] = rk[8] = rk[12] = (guint8)(rid & 0xFF); + rk[1] = rk[5] = rk[9] = rk[13] = (guint8)((rid >> 8) & 0xFF); + rk[2] = rk[6] = rk[10] = (guint8)((rid >> 16) & 0xFF); + rk[3] = rk[7] = rk[11] = (guint8)((rid >> 24) & 0xFF); + + /* loop in 8 byte steps and toggle the key index between 0 and 7 */ + for (hi=0, ri = 0; hi < hl; hi += 8, ri = ri == 0 ? 7 : 0) { + guint8 *h64 = &hb[hi]; + guint8 *rk56 = &rk[ri]; + + crypt_des_ecb(h64, h64, rk56); + } } - plain_tvb = tvb_new_child_real_data(tvb, buf + 4, buf_len - 4, buf_len - 4); + payload_tvb = tvb_new_child_real_data(tvb, payload_buf, payload_len, payload_len); - add_new_data_source(pinfo, plain_tvb, "DRSUAPI Decrypted Attribute Value"); + snprintf(source_name, sizeof(source_name)-1, "DRSUAPI Decrypted %s RID=%u", attr_name, rid); + add_new_data_source(pinfo, payload_tvb, source_name); + proto_tree_add_text_internal(tree, payload_tvb, 0, payload_len, source_name); if (attr_dissector_fn == NULL) { return offset; } - attr_dissector_fn(plain_tvb, pinfo, tree, di); + attr_dissector_fn(payload_tvb, pinfo, tree, di); return offset; } -- 2.11.4.GIT