summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2007-02-09 17:35:32 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:44:56 -0500
commit714052a68c9f64bbfebb01fc50868bf96f3b5ada (patch)
tree79b5323895e3aae01283d1a768d5418d0a275dcf
parentb619e959c9c8d5a17e882d8b8316a97ec860245b (diff)
downloadsamba-714052a68c9f64bbfebb01fc50868bf96f3b5ada.tar.gz
samba-714052a68c9f64bbfebb01fc50868bf96f3b5ada.tar.bz2
samba-714052a68c9f64bbfebb01fc50868bf96f3b5ada.zip
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)
-rw-r--r--source4/torture/rpc/dssync.c86
1 files changed, 74 insertions, 12 deletions
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)) {