From 2d3eea45312f3cb0121ea403eb5a809a4e6c062e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Feb 2007 19:40:54 +0000 Subject: r21245: combination "c[3] s[1] e[1] d[0]..." was successful!!!!!!!!!!!!!!!!!!!!!!!!!! we now support the session depended password attribute encryption used in DsGetNCChanges() the static encryption (something like sam_rid_crypt() is assumed for some attributes and the format of the attribute values isn't known yet, but some contain some unicode strings... metze (This used to be commit daee739ebba38e54fbdbd7e53d16fd30bc0dd54e) --- source4/torture/rpc/dssync.c | 341 ++++++++++--------------------------------- 1 file changed, 75 insertions(+), 266 deletions(-) (limited to 'source4/torture/rpc') diff --git a/source4/torture/rpc/dssync.c b/source4/torture/rpc/dssync.c index 9f171c4a00..79172e366c 100644 --- a/source4/torture/rpc/dssync.c +++ b/source4/torture/rpc/dssync.c @@ -42,9 +42,6 @@ struct DsSyncBindInfo { struct drsuapi_DsBindInfo28 our_bind_info28; struct drsuapi_DsBindInfo28 peer_bind_info28; struct policy_handle bind_handle; - DATA_BLOB dce_key; - DATA_BLOB gen_key; - struct samr_Password nthash; }; struct DsSyncLDAPInfo { @@ -181,11 +178,10 @@ static BOOL _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credent NTSTATUS status; BOOL ret = True; struct event_context *event = NULL; - const struct samr_Password *nthash; status = dcerpc_pipe_connect_b(ctx, &b->pipe, ctx->drsuapi_binding, - &dcerpc_table_drsuapi, + &dcerpc_table_drsuapi, credentials, event); if (!NT_STATUS_IS_OK(status)) { @@ -224,20 +220,6 @@ static BOOL _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credent } } - dcerpc_fetch_session_key(b->pipe, &b->dce_key); - gensec_session_key(b->pipe->conn->security_state.generic_state, &b->gen_key); - nthash = cli_credentials_get_nt_hash(credentials, NULL); - if (nthash) b->nthash = *nthash; - - if (lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) { - DEBUG(0,("DCERPC session key:\n")); - dump_data(0, b->dce_key.data, b->dce_key.length); - DEBUG(0,("GENSEC session key:\n")); - dump_data(0, b->gen_key.data, b->gen_key.length); - DEBUG(0,("CREDENTIALS nthash:\n")); - dump_data(0, b->nthash.hash, sizeof(b->nthash.hash)); - } - return ret; } @@ -318,263 +300,81 @@ static BOOL test_GetInfo(struct DsSyncTest *ctx) return ret; } -static void choose_confounder_v01(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - uint32_t confounder_len, - DATA_BLOB *confounder, - DATA_BLOB *enc_buffer) -{ - *confounder = data_blob_talloc(mem_ctx, buffer->data, confounder_len); - *enc_buffer = data_blob_talloc(mem_ctx, buffer->data+confounder_len, buffer->length - confounder_len); -} - -static void choose_confounder_v02(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - uint32_t confounder_len, - DATA_BLOB *confounder, - DATA_BLOB *enc_buffer) -{ - *confounder = data_blob_talloc(mem_ctx, buffer->data + buffer->length - confounder_len, confounder_len); - *enc_buffer = data_blob_talloc(mem_ctx, buffer->data, buffer->length - confounder_len); -} - -static const struct { - uint32_t len; - void (*fn)(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - uint32_t confounder_len, - DATA_BLOB *confounder, - DATA_BLOB *enc_buffer); -} choose_confounder_fns[] = { - { - .len = 4, - .fn = choose_confounder_v01, - }, - { - .len = 8, - .fn = choose_confounder_v01, - }, - { - .len = 12, - .fn = choose_confounder_v01, - }, - { - .len = 16, - .fn = choose_confounder_v01, - }, - { - .len = 4, - .fn = choose_confounder_v02, - }, - { - .len = 8, - .fn = choose_confounder_v02, - }, - { - .len = 12, - .fn = choose_confounder_v02, - }, - { - .len = 16, - .fn = choose_confounder_v02, - }, -}; - -static void choose_session_key_v01(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - DATA_BLOB *session_key) -{ - *session_key = data_blob_talloc(mem_ctx, b->dce_key.data, b->dce_key.length); -} - -static void choose_session_key_v02(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - DATA_BLOB *session_key) -{ - *session_key = data_blob_talloc(mem_ctx, b->gen_key.data, b->gen_key.length); -} - -static const struct { - void (*fn)(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - DATA_BLOB *session_key); -} choose_session_key_fns[] = { - { - .fn = choose_session_key_v01, - }, - { - .fn = choose_session_key_v02, - }, -}; - -static void create_enc_key_v01(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - const DATA_BLOB *confounder, - const DATA_BLOB *session_key, - DATA_BLOB *_enc_key) -{ - struct MD5Context md5; - DATA_BLOB enc_key; - - enc_key = data_blob_talloc(mem_ctx, NULL, 16); - MD5Init(&md5); - MD5Update(&md5, confounder->data, confounder->length); - MD5Update(&md5, session_key->data, session_key->length); - MD5Final(enc_key.data, &md5); - - *_enc_key = enc_key; -} - -static void create_enc_key_v02(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - const DATA_BLOB *confounder, - const DATA_BLOB *session_key, - DATA_BLOB *_enc_key) -{ - struct MD5Context md5; - DATA_BLOB enc_key; - - enc_key = data_blob_talloc(mem_ctx, NULL, 16); - MD5Init(&md5); - MD5Update(&md5, session_key->data, session_key->length); - MD5Update(&md5, confounder->data, confounder->length); - MD5Final(enc_key.data, &md5); - - *_enc_key = enc_key; -} - -static const struct { - void (*fn)(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - const DATA_BLOB *confounder, - const DATA_BLOB *session_key, - DATA_BLOB *_enc_key); -} create_enc_key_fns[] = { - { - .fn = create_enc_key_v01, - }, - { - .fn = create_enc_key_v02, - }, -}; - -static void do_decryption_v01(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - const DATA_BLOB *enc_key, - const DATA_BLOB *enc_buffer, - DATA_BLOB *_plain_buffer) -{ - DATA_BLOB plain_buffer; - - plain_buffer = data_blob_talloc(mem_ctx, enc_buffer->data, enc_buffer->length); - - arcfour_crypt_blob(plain_buffer.data, plain_buffer.length, enc_key); - - *_plain_buffer = plain_buffer; -} - -static const struct { - void (*fn)(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, - struct drsuapi_DsReplicaObjectIdentifier *id, - uint32_t rid, - const DATA_BLOB *buffer, - const DATA_BLOB *enc_key, - const DATA_BLOB *enc_buffer, - DATA_BLOB *plain_buffer); -} do_decryption_fns[] = { - { - .fn = do_decryption_v01, - }, -}; - static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx, - struct DsSyncBindInfo *b, + const DATA_BLOB *gensec_skey, struct drsuapi_DsReplicaObjectIdentifier *id, uint32_t rid, const DATA_BLOB *buffer) { - uint32_t conf_i; - uint32_t skey_i; - uint32_t ekey_i; - uint32_t crypt_i; - - - for (conf_i = 0; conf_i < ARRAY_SIZE(choose_confounder_fns); conf_i++) { - DATA_BLOB confounder; - DATA_BLOB enc_buffer; + DATA_BLOB confounder; + DATA_BLOB enc_buffer; - choose_confounder_fns[conf_i].fn(mem_ctx, b, id, rid, buffer, - choose_confounder_fns[conf_i].len, - &confounder, &enc_buffer); - - for (skey_i = 0; skey_i < ARRAY_SIZE(choose_session_key_fns); skey_i++) { - DATA_BLOB session_key; - - choose_session_key_fns[skey_i].fn(mem_ctx, b, id, rid, buffer, - &session_key); - - for (ekey_i = 0; ekey_i < ARRAY_SIZE(create_enc_key_fns); ekey_i++) { - DATA_BLOB enc_key; - - create_enc_key_fns[ekey_i].fn(mem_ctx, b, id, rid, buffer, - &confounder, &session_key, - &enc_key); + struct MD5Context md5; + uint8_t _enc_key[16]; + DATA_BLOB enc_key; - for (crypt_i = 0; crypt_i < ARRAY_SIZE(do_decryption_fns); crypt_i++) { - DATA_BLOB plain_buffer; + DATA_BLOB plain_buffer; - do_decryption_fns[crypt_i].fn(mem_ctx, b, id, rid, buffer, - &enc_key, &enc_buffer, - &plain_buffer); + /* + * the combination "c[3] s[1] e[1] d[0]..." + * was successful!!!!!!!!!!!!!!!!!!!!!!!!!! + */ - DEBUGADD(0,("c[%u] s[%u] e[%u] d[%u] len[%u]:\n", - conf_i, skey_i, ekey_i, crypt_i, - plain_buffer.length)); - dump_data(0, confounder.data, confounder.length); - dump_data(0, session_key.data, session_key.length); - dump_data(0, enc_key.data, enc_key.length); - dump_data(0, enc_buffer.data, enc_buffer.length); - dump_data(0, plain_buffer.data, plain_buffer.length); - } - } - } + /* the first 16 bytes at the beginning are the confounder */ + if (buffer->length <= 16) { + return data_blob_const(NULL, 0); } + confounder = data_blob_const(buffer->data, 16); + enc_buffer = data_blob_const(buffer->data + 16, buffer->length - 16); + + /* + * build the encryption key md5 over the session key followed + * by the confounder + * + * here the gensec session key is used and + * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key! + */ + enc_key = data_blob_const(_enc_key, sizeof(_enc_key)); + MD5Init(&md5); + MD5Update(&md5, gensec_skey->data, gensec_skey->length); + MD5Update(&md5, confounder.data, confounder.length); + MD5Final(enc_key.data, &md5); - return data_blob(NULL, 0); + /* + * 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) { + return data_blob_const(NULL, 0); + } + arcfour_crypt_blob(plain_buffer.data, plain_buffer.length, &enc_key); + + /* + * some attributes seem to be in a usable form after this decryption + * (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing, + * trustAuthIncoming, initialAuthOutgoing, initialAuthIncoming) + * At least supplementalCredentials contains plaintext + * like "Primary:Kerberos" (in unicode form) + * + * 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); + */ + + return plain_buffer; } static void test_analyse_objects(struct DsSyncTest *ctx, + const DATA_BLOB *gensec_skey, struct drsuapi_DsReplicaObjectListItemEx *cur) { if (!lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) { @@ -648,7 +448,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, &ctx->new_dc.drsuapi, + plain_data = decrypt_blob(ctx, gensec_skey, cur->object.identifier, rid, enc_data); if (!dn_printed) { @@ -657,9 +457,10 @@ static void test_analyse_objects(struct DsSyncTest *ctx, } DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n", name, (long)enc_data->length, (long)plain_data.length)); - dump_data(0, enc_data->data, enc_data->length); if (plain_data.length) { dump_data(0, plain_data.data, plain_data.length); + } else { + dump_data(0, enc_data->data, enc_data->length); } } } @@ -679,6 +480,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx) int32_t out_level = 0; struct GUID null_guid; struct dom_sid null_sid; + DATA_BLOB gensec_skey; struct { int32_t level; } array[] = { @@ -701,6 +503,13 @@ static BOOL test_FetchData(struct DsSyncTest *ctx) highest_usn = lp_parm_int(-1, "dssync", "highest_usn", 0); + status = gensec_session_key(ctx->new_dc.drsuapi.pipe->conn->security_state.generic_state, + &gensec_skey); + if (!NT_STATUS_IS_OK(status)) { + printf("failed to get gensec session key: %s\n", nt_errstr(status)); + return False; + } + for (i=0; i < ARRAY_SIZE(array); i++) { printf("testing DsGetNCChanges level %d\n", array[i].level); @@ -821,7 +630,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx) (long long)ctr1->new_highwatermark.tmp_highest_usn, (long long)ctr1->new_highwatermark.highest_usn)); - test_analyse_objects(ctx, ctr1->first_object); + test_analyse_objects(ctx, &gensec_skey, ctr1->first_object); if (ctr1->new_highwatermark.tmp_highest_usn > ctr1->new_highwatermark.highest_usn) { r.in.req.req5.highwatermark = ctr1->new_highwatermark; @@ -844,7 +653,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx) (long long)ctr6->new_highwatermark.tmp_highest_usn, (long long)ctr6->new_highwatermark.highest_usn)); - test_analyse_objects(ctx, ctr6->first_object); + test_analyse_objects(ctx, &gensec_skey, ctr6->first_object); if (ctr6->new_highwatermark.tmp_highest_usn > ctr6->new_highwatermark.highest_usn) { r.in.req.req8.highwatermark = ctr6->new_highwatermark; -- cgit