WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx, struct wkssvc_PasswordBuffer *pwd_buf, DATA_BLOB *session_key, char **pwd) { uint8_t buffer[516]; struct MD5Context ctx; uint32_t pwd_len; DATA_BLOB confounded_session_key; int confounder_len = 8; uint8_t confounder[8]; *pwd = NULL; if (!pwd_buf) { return WERR_BAD_PASSWORD; } if (session_key->length != 16) { DEBUG(10,("invalid session key\n")); return WERR_BAD_PASSWORD; } confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16); memcpy(&confounder, &pwd_buf->data[0], confounder_len); memcpy(&buffer, &pwd_buf->data[8], 516); MD5Init(&ctx); MD5Update(&ctx, session_key->data, session_key->length); MD5Update(&ctx, confounder, confounder_len); MD5Final(confounded_session_key.data, &ctx); SamOEMhashBlob(buffer, 516, &confounded_session_key); if (!decode_pw_buffer(mem_ctx, buffer, pwd, &pwd_len, STR_UNICODE)) { data_blob_free(&confounded_session_key); return WERR_BAD_PASSWORD; } data_blob_free(&confounded_session_key); return WERR_OK; }
void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx, const char *pwd, DATA_BLOB *session_key, struct wkssvc_PasswordBuffer **pwd_buf) { uint8_t buffer[516]; struct MD5Context ctx; struct wkssvc_PasswordBuffer *my_pwd_buf = NULL; DATA_BLOB confounded_session_key; int confounder_len = 8; uint8_t confounder[8]; my_pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer); if (!my_pwd_buf) { return; } confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16); encode_pw_buffer(buffer, pwd, STR_UNICODE); generate_random_buffer((uint8_t *)confounder, confounder_len); MD5Init(&ctx); MD5Update(&ctx, session_key->data, session_key->length); MD5Update(&ctx, confounder, confounder_len); MD5Final(confounded_session_key.data, &ctx); SamOEMhashBlob(buffer, 516, &confounded_session_key); memcpy(&my_pwd_buf->data[0], confounder, confounder_len); memcpy(&my_pwd_buf->data[8], buffer, 516); data_blob_free(&confounded_session_key); *pwd_buf = my_pwd_buf; }
DATA_BLOB decrypt_drsuapi_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *session_key, bool rcrypt, uint32_t rid, const DATA_BLOB *buffer) { DATA_BLOB confounder; DATA_BLOB enc_buffer; struct MD5Context md5; uint8_t _enc_key[16]; DATA_BLOB enc_key; DATA_BLOB dec_buffer; uint32_t crc32_given; uint32_t crc32_calc; DATA_BLOB checked_buffer; DATA_BLOB plain_buffer; /* * the combination "c[3] s[1] e[1] d[0]..." * was successful!!!!!!!!!!!!!!!!!!!!!!!!!! */ /* * the first 16 bytes at the beginning are the confounder * followed by the 4 byte crc32 checksum */ if (buffer->length < 20) { 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, session_key->data, session_key->length); MD5Update(&md5, confounder.data, confounder.length); MD5Final(enc_key.data, &md5); /* * copy the encrypted buffer part and * decrypt it using the created encryption key using arcfour */ dec_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length); if (!dec_buffer.data) { return data_blob_const(NULL, 0); } SamOEMhashBlob(dec_buffer.data, dec_buffer.length, &enc_key); /* * the first 4 byte are the crc32 checksum * of the remaining bytes */ crc32_given = IVAL(dec_buffer.data, 0); crc32_calc = crc32_calc_buffer((const char *)dec_buffer.data + 4 , dec_buffer.length - 4); if (crc32_given != crc32_calc) { DEBUG(1,("CRC32: given[0x%08X] calc[0x%08X]\n", crc32_given, crc32_calc)); return data_blob_const(NULL, 0); } checked_buffer = data_blob_talloc(mem_ctx, dec_buffer.data + 4, dec_buffer.length - 4); if (!checked_buffer.data) { return data_blob_const(NULL, 0); } /* * 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 the sam_rid_crypt() function, as the value is constant, * so it doesn't depend on sessionkeys. */ if (rcrypt) { uint32_t i, num_hashes; if ((checked_buffer.length % 16) != 0) { return data_blob_const(NULL, 0); } plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length); if (!plain_buffer.data) { return data_blob_const(NULL, 0); } num_hashes = plain_buffer.length / 16; for (i = 0; i < num_hashes; i++) { uint32_t offset = i * 16; sam_pwd_hash(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0); } } else { plain_buffer = checked_buffer; } return plain_buffer; }
NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID *dom_sid, const char *clear_pw, enum netdom_domain_t dom_type ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND sam_pol, domain_pol, user_pol; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; char *acct_name; const char *const_acct_name; uint32 user_rid; uint32 num_rids, *name_types, *user_rids; uint32 flags = 0x3e8; uint32 acb_info = ACB_WSTRUST; uint32 acct_flags=0; uint32 fields_present; uchar pwbuf[532]; SAM_USERINFO_CTR ctr; SAM_USER_INFO_25 p25; const int infolevel = 25; struct MD5Context md5ctx; uchar md5buffer[16]; DATA_BLOB digested_session_key; uchar md4_trust_password[16]; /* Open the domain */ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) { DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n", nt_errstr(status) )); return status; } status = rpccli_samr_connect(pipe_hnd, mem_ctx, SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol); if ( !NT_STATUS_IS_OK(status) ) return status; status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol); if ( !NT_STATUS_IS_OK(status) ) return status; /* Create domain user */ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); strlower_m(acct_name); const_acct_name = acct_name; /* Don't try to set any acb_info flags other than ACB_WSTRUST */ acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE | SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC | SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR | SAMR_USER_SETATTR; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol, acct_name, acb_info, acct_flags, &user_pol, &user_rid); if ( !NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { d_fprintf(stderr, "Creation of workstation account failed\n"); /* If NT_STATUS_ACCESS_DENIED then we have a valid username/password combo but the user does not have administrator access. */ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_fprintf(stderr, "User specified does not have administrator privileges\n"); return status; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(status)) { rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); } status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx, &domain_pol, flags, 1, &const_acct_name, &num_rids, &user_rids, &name_types); if ( !NT_STATUS_IS_OK(status) ) return status; if ( name_types[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0])); return NT_STATUS_INVALID_WORKSTATION; } user_rid = user_rids[0]; /* Open handle on user */ status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol); if (!NT_STATUS_IS_OK(status)) { return status; } /* Create a random machine account password and generate the hash */ E_md4hash(clear_pw, md4_trust_password); encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE); generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer)); digested_session_key = data_blob_talloc(mem_ctx, 0, 16); MD5Init(&md5ctx); MD5Update(&md5ctx, md5buffer, sizeof(md5buffer)); MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length); MD5Final(digested_session_key.data, &md5ctx); SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key); memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer)); /* Fill in the additional account flags now */ acb_info |= ACB_PWNOEXP; if ( dom_type == ND_TYPE_AD ) { #if !defined(ENCTYPE_ARCFOUR_HMAC) acb_info |= ACB_USE_DES_KEY_ONLY; #endif ;; } /* Set password and account flags on machine account */ ZERO_STRUCT(ctr); ZERO_STRUCT(p25); fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS; init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf); ctr.switch_value = infolevel; ctr.info.id25 = &p25; status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, infolevel, &cli->user_session_key, &ctr); if ( !NT_STATUS_IS_OK(status) ) { d_fprintf( stderr, "Failed to set password for machine account (%s)\n", nt_errstr(status)); return status; } rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */ return status; }