From 714052a68c9f64bbfebb01fc50868bf96f3b5ada Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Feb 2007 17:35:32 +0000 Subject: r21261: add support for getting to the plain nthash (and I assume others too) I wonder what the first 4 bytes are, but the last 16 bytes of the 20 bytes are the rid crypted hash. The lmhash and the history fields are not verified yet. But I get the administrators nthash in plain. metze (This used to be commit 7726d4a0272b29a4eade26c9ae3d929df50897da) --- source4/torture/rpc/dssync.c | 86 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 12 deletions(-) (limited to 'source4/torture/rpc') diff --git a/source4/torture/rpc/dssync.c b/source4/torture/rpc/dssync.c index 79172e366c..063b37c617 100644 --- a/source4/torture/rpc/dssync.c +++ b/source4/torture/rpc/dssync.c @@ -300,8 +300,39 @@ static BOOL test_GetInfo(struct DsSyncTest *ctx) return ret; } +static void sam_rid_crypt_len(uint_t rid, uint32_t len, const uint8_t *in, uint8_t *out, int forw) +{ + uint8_t s[14]; + uint8_t in_pad[8], out_pad[8]; + uint32_t b_off, s_off = 0; + + s[0] = s[4] = s[8] = s[12] = (uint8_t)(rid & 0xFF); + s[1] = s[5] = s[9] = s[13] = (uint8_t)((rid >> 8) & 0xFF); + s[2] = s[6] = s[10] = (uint8_t)((rid >> 16) & 0xFF); + s[3] = s[7] = s[11] = (uint8_t)((rid >> 24) & 0xFF); + + for (b_off=0; b_off < len; b_off += 8) { + uint32_t left = len - b_off; + if (left >= 8) { + des_crypt56(out + b_off, in + b_off, s + s_off, forw); + } else { + ZERO_STRUCT(in_pad); + memcpy(in_pad, in + b_off, left); + des_crypt56(out_pad, in + b_off, s + s_off, forw); + memcpy(out + b_off, out_pad, left); + ZERO_STRUCT(out_pad); + } + if (s_off == 0) { + s_off = 7; + } else { + s_off--; + } + } +} + static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *gensec_skey, + bool rcrypt, struct drsuapi_DsReplicaObjectIdentifier *id, uint32_t rid, const DATA_BLOB *buffer) @@ -313,6 +344,7 @@ static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx, uint8_t _enc_key[16]; DATA_BLOB enc_key; + DATA_BLOB dec_buffer; DATA_BLOB plain_buffer; /* @@ -344,11 +376,11 @@ static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx, * copy the encrypted buffer part and * decrypt it using the created encryption key using arcfour */ - plain_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length); - if (!plain_buffer.data) { + dec_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length); + if (!dec_buffer.data) { return data_blob_const(NULL, 0); } - arcfour_crypt_blob(plain_buffer.data, plain_buffer.length, &enc_key); + arcfour_crypt_blob(dec_buffer.data, dec_buffer.length, &enc_key); /* * some attributes seem to be in a usable form after this decryption @@ -360,15 +392,32 @@ static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx, * some attributes seem to have some additional encryption * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory * - * it's assumed it's something like this sam_rid_crypt() - * function, as the value is constant, so it doesn't depend - * on sessionkeys. But for the unicodePwd attribute which contains - * the nthash be have 20 bytes at this point, but the ntnash only - * is 16 bytes long, so using the current sam_rid_crypt() function - * doesn't work. - * - * sam_rid_crypt(rid, crypt_nt_hash.hash, plain_nt_hash.hash, 0); + * it's the sam_rid_crypt() function, as the value is constant, + * so it doesn't depend on sessionkeys. But for the unicodePwd attribute + * which contains the nthash has 20 bytes at this point. + * + * the first 4 byte are unknown yet, but the last 16 byte are the + * rid crypted hash. */ + if (rcrypt) { + plain_buffer = data_blob_talloc(mem_ctx, dec_buffer.data, dec_buffer.length); + if (!plain_buffer.data) { + return data_blob_const(NULL, 0); + } + if (plain_buffer.length < 20) { + return data_blob_const(NULL, 0); + } + /* + * TODO: check if that's correct for the history fields, + * which can be larger than 16 bytes (but in 16 byte steps) + * maybe we need to call the 16 byte sam_rid_crypt() function + * for each hash, but here we assume the rid des key is shifted + * by one for each 8 byte block. + */ + sam_rid_crypt_len(rid, dec_buffer.length - 4, dec_buffer.data + 4, plain_buffer.data + 4, 0); + } else { + plain_buffer = dec_buffer; + } return plain_buffer; } @@ -398,6 +447,7 @@ static void test_analyse_objects(struct DsSyncTest *ctx, for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) { const char *name = NULL; + bool rcrypt = false; DATA_BLOB *enc_data = NULL; DATA_BLOB plain_data; struct drsuapi_DsReplicaAttribute *attr; @@ -406,15 +456,19 @@ static void test_analyse_objects(struct DsSyncTest *ctx, switch (attr->attid) { case DRSUAPI_ATTRIBUTE_dBCSPwd: name = "dBCSPwd"; + rcrypt = true; break; case DRSUAPI_ATTRIBUTE_unicodePwd: name = "unicodePwd"; + rcrypt = true; break; case DRSUAPI_ATTRIBUTE_ntPwdHistory: name = "ntPwdHistory"; + rcrypt = true; break; case DRSUAPI_ATTRIBUTE_lmPwdHistory: name = "lmPwdHistory"; + rcrypt = true; break; case DRSUAPI_ATTRIBUTE_supplementalCredentials: name = "supplementalCredentials"; @@ -448,7 +502,7 @@ static void test_analyse_objects(struct DsSyncTest *ctx, enc_data = attr->value_ctr.values[0].blob; ZERO_STRUCT(plain_data); - plain_data = decrypt_blob(ctx, gensec_skey, + plain_data = decrypt_blob(ctx, gensec_skey, rcrypt, cur->object.identifier, rid, enc_data); if (!dn_printed) { @@ -503,6 +557,14 @@ static BOOL test_FetchData(struct DsSyncTest *ctx) highest_usn = lp_parm_int(-1, "dssync", "highest_usn", 0); + if (lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) { + const struct samr_Password *nthash; + nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx); + if (nthash) { + DEBUG(0,("CREDENTIALS nthash:\n")); + dump_data(0, nthash->hash, sizeof(nthash->hash)); + } + } status = gensec_session_key(ctx->new_dc.drsuapi.pipe->conn->security_state.generic_state, &gensec_skey); if (!NT_STATUS_IS_OK(status)) { -- cgit