diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-11-13 03:57:54 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:05:46 -0500 |
commit | 1158268287f07310e79e9d470971dc021a334f9e (patch) | |
tree | c8b79f8075c451ef5129c0e38e781a98d6b5026a | |
parent | 62979b84cb52465e6264ecb31fb3ff4db72313e4 (diff) | |
download | samba-1158268287f07310e79e9d470971dc021a334f9e.tar.gz samba-1158268287f07310e79e9d470971dc021a334f9e.tar.bz2 samba-1158268287f07310e79e9d470971dc021a334f9e.zip |
r3716: Improvements in the RPC-SAMSYNC tests:
We now (for the first time) start to parse the 'user sensitive info'
field, which reveals the user's NT and LM passwords from Win2k3.
Using this, the 'validate samsync against netlogon' portion of the
tests works for accounts.
Trusted domains and secrets are now retreived, but like users,
require further cross-validation work.
Andrew Bartlett
(This used to be commit c1d3794cad8b001661b48ecb05df5c38a69be92c)
-rw-r--r-- | source4/librpc/idl/netlogon.idl | 42 | ||||
-rw-r--r-- | source4/torture/rpc/samsync.c | 169 |
2 files changed, 195 insertions, 16 deletions
diff --git a/source4/librpc/idl/netlogon.idl b/source4/librpc/idl/netlogon.idl index f55049d30e..37c6949fad 100644 --- a/source4/librpc/idl/netlogon.idl +++ b/source4/librpc/idl/netlogon.idl @@ -303,8 +303,32 @@ interface netlogon } netr_DELTA_DELETE_USER; typedef struct { + uint16 length; + [value(r->length)] uint16 size; + uint32 flags; + samr_Password pwd; + } netr_USER_KEY16; + + typedef struct { + netr_USER_KEY16 lmpassword; + netr_USER_KEY16 ntpassword; + + } netr_USER_KEYS2; + + typedef struct { + netr_USER_KEYS2 keys2; + } netr_USER_KEY_UNION; + + typedef [public] struct { + uint32 version; + netr_USER_KEY_UNION keys; + } netr_USER_KEYS; + + typedef struct { bool8 SensitiveDataFlag; uint32 DataLength; + + /* netr_USER_KEYS encrypted with the session key */ [size_is(DataLength)] uint8 *SensitiveData; } netr_USER_PRIVATE_INFO; @@ -349,7 +373,7 @@ interface netlogon } netr_DELTA_USER; typedef struct { - netr_String DomainName; + netr_String domain_name; netr_String OEMInfo; NTTIME forcedlogoff; uint16 min_password_len; @@ -465,7 +489,7 @@ interface netlogon } netr_DELTA_POLICY; typedef struct { - netr_String DomainName; + netr_String domain_name; uint32 num_controllers; [size_is(num_controllers)] netr_String *controller_names; uint32 SecurityInformation; @@ -478,7 +502,7 @@ interface netlogon uint32 unknown6; uint32 unknown7; uint32 unknown8; - } netr_DELTA_TRUSTED_DOMAINS; + } netr_DELTA_TRUSTED_DOMAIN; typedef struct { uint16 unknown; @@ -548,7 +572,7 @@ interface netlogon NETR_DELTA_RENAME_ALIAS = 11, NETR_DELTA_ALIAS_MEMBER = 12, NETR_DELTA_POLICY = 13, - NETR_DELTA_TRUSTED_DOMAINS = 14, + NETR_DELTA_TRUSTED_DOMAIN = 14, NETR_DELTA_DELETE_TRUST = 15, NETR_DELTA_ACCOUNTS = 16, NETR_DELTA_DELETE_ACCOUNT = 17, @@ -573,12 +597,12 @@ interface netlogon [case(NETR_DELTA_RENAME_ALIAS)] netr_DELTA_RENAME *rename_alias; [case(NETR_DELTA_ALIAS_MEMBER)] netr_DELTA_ALIAS_MEMBER *alias_member; [case(NETR_DELTA_POLICY)] netr_DELTA_POLICY *policy; - [case(NETR_DELTA_TRUSTED_DOMAINS)] netr_DELTA_TRUSTED_DOMAINS *trusted_domains; - [case(NETR_DELTA_DELETE_TRUST)] netr_DELTA_DELETE_TRUST delete_trust; + [case(NETR_DELTA_TRUSTED_DOMAIN)] netr_DELTA_TRUSTED_DOMAIN *trusted_domain; + [case(NETR_DELTA_DELETE_TRUST)] netr_DELTA_DELETE_TRUST delete_trust; [case(NETR_DELTA_ACCOUNTS)] netr_DELTA_ACCOUNTS *accounts; - [case(NETR_DELTA_DELETE_ACCOUNT)] netr_DELTA_DELETE_ACCOUNT delete_account; + [case(NETR_DELTA_DELETE_ACCOUNT)] netr_DELTA_DELETE_ACCOUNT delete_account; [case(NETR_DELTA_SECRET)] netr_DELTA_SECRET *secret; - [case(NETR_DELTA_DELETE_SECRET)] netr_DELTA_DELETE_SECRET delete_secret; + [case(NETR_DELTA_DELETE_SECRET)] netr_DELTA_DELETE_SECRET delete_secret; [case(NETR_DELTA_DELETE_GROUP2)] netr_DELTA_DELETE_USER *delete_group; [case(NETR_DELTA_DELETE_USER2)] netr_DELTA_DELETE_USER *delete_user; [case(NETR_DELTA_MODIFY_COUNT)] uint64 *modified_count; @@ -598,7 +622,7 @@ interface netlogon [case(NETR_DELTA_RENAME_ALIAS)] uint32 rid; [case(NETR_DELTA_ALIAS_MEMBER)] uint32 rid; [case(NETR_DELTA_POLICY)] dom_sid2 *sid; - [case(NETR_DELTA_TRUSTED_DOMAINS)] dom_sid2 *sid; + [case(NETR_DELTA_TRUSTED_DOMAIN)] dom_sid2 *sid; [case(NETR_DELTA_DELETE_TRUST)] dom_sid2 *sid; [case(NETR_DELTA_ACCOUNTS)] dom_sid2 *sid; [case(NETR_DELTA_DELETE_ACCOUNT)] dom_sid2 *sid; diff --git a/source4/torture/rpc/samsync.c b/source4/torture/rpc/samsync.c index 8bb6ec2ec6..aaab3ef988 100644 --- a/source4/torture/rpc/samsync.c +++ b/source4/torture/rpc/samsync.c @@ -25,6 +25,8 @@ #include "includes.h" #include "librpc/gen_ndr/ndr_netlogon.h" #include "auth/auth.h" +#include "dlinklist.h" +#include "lib/crypto/crypto.h" #define TEST_MACHINE_NAME "samsynctest" @@ -55,12 +57,18 @@ static NTSTATUS test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ninfo.nt.length = 24; ninfo.nt.data = talloc(mem_ctx, 24); SMBOWFencrypt(nt_hash->hash, ninfo.challenge, ninfo.nt.data); + } else { + ninfo.nt.length = 0; + ninfo.nt.data = NULL; } if (lm_hash) { ninfo.lm.length = 24; ninfo.lm.data = talloc(mem_ctx, 24); SMBOWFencrypt(lm_hash->hash, ninfo.challenge, ninfo.lm.data); + } else { + ninfo.lm.length = 0; + ninfo.lm.data = NULL; } r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); @@ -81,7 +89,9 @@ static NTSTATUS test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("Credential chaining failed\n"); } - *info3 = r.out.validation.sam3; + if (info3) { + *info3 = r.out.validation.sam3; + } return status; } @@ -89,6 +99,20 @@ static NTSTATUS test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct samsync_state { uint64_t seq_num; char *domain_name; + struct samsync_secret *secrets; + struct samsync_trusted_domain *trusted_domains; +}; + +struct samsync_secret { + struct samsync_secret *prev, *next; + DATA_BLOB secret; + char *name; +}; + +struct samsync_trusted_domain { + struct samsync_trusted_domain *prev, *next; + struct dom_sid *sid; + char *name; }; static struct samsync_state *samsync_state; @@ -103,7 +127,7 @@ static BOOL samsync_handle_domain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, domain->sequence_num; samsync_state[database_id].domain_name = - talloc_reference(samsync_state, domain->DomainName.string); + talloc_reference(samsync_state, domain->domain_name.string); printf("\tsequence_nums[%d/%s]=%llu\n", database_id, samsync_state[database_id].domain_name, @@ -120,6 +144,8 @@ static BOOL samsync_handle_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct netr_SamInfo3 *info3; struct samr_Password lm_hash; struct samr_Password nt_hash; + struct samr_Password *lm_hash_p = NULL; + struct samr_Password *nt_hash_p = NULL; const char *domain = samsync_state[database_id].domain_name ? samsync_state[database_id].domain_name : lp_workgroup(); @@ -130,22 +156,53 @@ static BOOL samsync_handle_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, if (user->lmpassword_present) { sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0); + lm_hash_p = &lm_hash; } if (user->ntpassword_present) { sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0); + nt_hash_p = &nt_hash; } - if (!user->lmpassword_present && !user->lmpassword_present) { + if (user->user_private_info.SensitiveData) { + DATA_BLOB data; + struct netr_USER_KEYS keys; + data.data = user->user_private_info.SensitiveData; + data.length = user->user_private_info.DataLength; + creds_arcfour_crypt(creds, data.data, data.length); +#if 0 + printf("Sensitive Data for %s:\n", username); + dump_data(0, data.data, data.length); +#endif + nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS); + if (!NT_STATUS_IS_OK(nt_status)) { + return False; + } + if (keys.keys.keys2.lmpassword.length == 16) { + sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0); + dump_data(0, keys.keys.keys2.lmpassword.pwd.hash, + sizeof(keys.keys.keys2.lmpassword.pwd.hash)); + + lm_hash_p = &lm_hash; + } + if (keys.keys.keys2.ntpassword.length == 16) { + sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0); + dump_data(0, keys.keys.keys2.ntpassword.pwd.hash, + sizeof(keys.keys.keys2.ntpassword.pwd.hash)); + nt_hash_p = &nt_hash; + } + + } + if (!lm_hash_p && !nt_hash_p) { printf("NO password set for %s\n", user->account_name.string); return True; } - + nt_status = test_SamLogon(p, mem_ctx, creds, domain, username, - user->lmpassword_present ? &lm_hash : NULL, - user->ntpassword_present ? &nt_hash : NULL, + lm_hash_p, + nt_hash_p, &info3); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) { @@ -178,7 +235,7 @@ static BOOL samsync_handle_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, user->acct_flags, info3->base.acct_flags); return False; } - if (strcmp(user->full_name.string, info3->base.full_name.string) != 0) { + if (strcmp_safe(user->full_name.string, info3->base.full_name.string) != 0) { printf("Full name mismatch: %s != %s\n", user->full_name.string, info3->base.full_name.string); return False; @@ -192,6 +249,44 @@ static BOOL samsync_handle_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return False; } +static BOOL samsync_handle_secret(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + struct creds_CredentialState *creds, + int database_id, struct netr_DELTA_ENUM *delta) +{ + struct netr_DELTA_SECRET *secret = delta->delta_union.secret; + const char *name = delta->delta_id_union.name; + struct samsync_secret *new = talloc_p(samsync_state, struct samsync_secret); + + creds_arcfour_crypt(creds, secret->current_cipher.cipher_data, + secret->current_cipher.maxlen); + + creds_arcfour_crypt(creds, secret->old_cipher.cipher_data, + secret->old_cipher.maxlen); + + new->name = talloc_reference(new, name); + new->secret = data_blob_talloc(new, secret->current_cipher.cipher_data, secret->current_cipher.maxlen); + + DLIST_ADD(samsync_state[database_id].secrets, new); + + return True; +} + +static BOOL samsync_handle_trusted_domain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + struct creds_CredentialState *creds, + int database_id, struct netr_DELTA_ENUM *delta) +{ + struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain; + struct dom_sid *dom_sid = delta->delta_id_union.sid; + + struct samsync_trusted_domain *new = talloc_p(samsync_state, struct samsync_trusted_domain); + new->name = talloc_reference(new, trusted_domain->domain_name.string); + new->sid = talloc_reference(new, dom_sid); + + DLIST_ADD(samsync_state[database_id].trusted_domains, new); + + return True; +} + /* we remember the sequence numbers so we can easily do a DatabaseDelta */ static uint64_t sequence_nums[3]; @@ -206,6 +301,8 @@ static BOOL test_DatabaseSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const uint32_t database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; int i, d; BOOL ret = True; + struct samsync_trusted_domain *t; + struct samsync_secret *s; samsync_state = talloc_zero_array_p(mem_ctx, struct samsync_state, 3); @@ -247,9 +344,67 @@ static BOOL test_DatabaseSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ret &= samsync_handle_user(p, mem_ctx, creds, r.in.database_id, &r.out.delta_enum_array->delta_enum[d]); break; + case NETR_DELTA_TRUSTED_DOMAIN: + ret &= samsync_handle_trusted_domain(p, mem_ctx, creds, + r.in.database_id, &r.out.delta_enum_array->delta_enum[d]); + break; + case NETR_DELTA_SECRET: + ret &= samsync_handle_secret(p, mem_ctx, creds, + r.in.database_id, &r.out.delta_enum_array->delta_enum[d]); + break; } } } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)); + + for (t=samsync_state[r.in.database_id].trusted_domains; t; t=t->next) { + const char *domain = samsync_state[r.in.database_id].domain_name + ? samsync_state[r.in.database_id].domain_name + : lp_workgroup(); + char *username = talloc_asprintf(mem_ctx, "%s$", domain); + char *secret_name = talloc_asprintf(mem_ctx, "G$$%s", t->name); + for (s=samsync_state[r.in.database_id].secrets; s; s=s->next) { + printf("Checking secret %s against %s\n", + s->name, secret_name); + if (StrCaseCmp(s->name, secret_name) == 0) { + NTSTATUS nt_status; + struct samr_Password nt_hash; + mdfour(nt_hash.hash, s->secret.data, s->secret.length); + + printf("Checking password for %s\\%s\n", t->name, username); + nt_status = test_SamLogon(p, mem_ctx, creds, + t->name, + username, + NULL, + &nt_hash, + NULL); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) { + printf("Could not verify trust password to %s: %s\n", + t->name, nt_errstr(nt_status)); + ret = False; + } + + /* break it */ + nt_hash.hash[0]++; + nt_status = test_SamLogon(p, mem_ctx, creds, + t->name, + username, + NULL, + &nt_hash, + NULL); + + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { + printf("Verifiction of trust password to %s: should have failed (wrong password), instead: %s\n", + t->name, nt_errstr(nt_status)); + ret = False; + ret = False; + } + + break; + } + } + talloc_free(secret_name); + talloc_free(username); + } } return ret; |