MichaelGrafnetter / DSInternals

Directory Services Internals (DSInternals) PowerShell Module and Framework
https://www.dsinternals.com
MIT License
1.62k stars 250 forks source link

Version DSInternals version : 4.4.0: System.FormatException: CRC check failed. #136

Open ThalesVinayak opened 2 years ago

ThalesVinayak commented 2 years ago

Hi ,

We wanted to share information about the exception faced with DSInternals.Replication.DirectoryReplicationClient.GetAccount. we are getting below mentioned exception while using the DSInternals.Replication.DirectoryReplicationClient.GetAccount method. All the users in AD are populated with the passwords, whenever we try to use this GetAccount method to get passwordhash, it throws an the exception for random users. For example, on an average if we have 200 users to get password hash, GetAccount throws an exception for at least 2-3 users.

We have recently upgraded our application from version 2.21.0.0 to 4.4.0.0. While using version 2.21.0.0, there is no such exception thrown by the GetAccount method.

System.FormatException: CRC check failed. at DSInternals.Common.Validator.AssertCrcMatches(Byte[] buffer, UInt32 expectedCrc) at DSInternals.Replication.ReplicationSecretDecryptor.DecryptSecret(Byte[] blob) at DSInternals.Common.Data.DSAccount.LoadHashes(DirectoryObject dsObject, DirectorySecretDecryptor pek) at DSInternals.Replication.DirectoryReplicationClient.GetAccount(String distinguishedName) at ADUserAdapter.ActiveDirectory.ActiveDirectoryService.GetPasswordHash(String userDistinguishedName) at ADUserAdapter.ActiveDirectory.ActiveDirectoryService.GetPasswordHash(String userDistinguishedName)

Kindly suggest

MichaelGrafnetter commented 2 years ago

Hello @ThalesVinayak , are you please able to replicate the bug in a test environment? From what Windows Server version are you replicating the data?

ThalesVinayak commented 2 years ago

@MichaelGrafnetter thanks for the reply. yes, bug is reproducible in test environment as well. server used is WIN2012R2. Issue was not reproducible with 10-20 users in AD. I tried with around 200 users and I always faced this exception for at least 2-3 users. In every syncing iteration there are random users for which the exception is faced and password hash is calculated as null In every subsequent sync, the users failed in previous attempt work fine and another random 2-3 fail. Please let me know if you need more information about the issue. tagging @andrei-galkin

ThalesVinayak commented 2 years ago

Hi @MichaelGrafnetter I have further investigated the issue that we are facing. After debugging the code for DSinternals, I came to know that the blob which is getting read under LoadHashes method is different from actual value:

dsObject.ReadAttribute(CommonDirectoryAttributes.NTHash, out encryptedNtHash);

this encryptedNthash value blob gets changed for random users and when this blob is passed to DecryptSecret method of ReplicationSecretDecryptor class. validation fails while doing the CRC check as actual value is not equal to the expected value of CRC.

this.NTHash = pek.DecryptHash(encryptedNtHash, this.Sid.GetRid()); >>>> byte[] partiallyDecryptedHash = this.DecryptSecret(blob); >>> public override byte[] DecryptSecret(byte[] blob)

below is success and fail case for same user:

failure case:

2021-12-31:12:09:28 AM [7] WARN ClientLauncher - ReplicationSecretDecryptor: decrypted secret:gäHÝÝ¡l|Äíàñ ýí expected crc:3918247760 actual:385695902.

success case for the same user:

2021-12-31:12:11:30 AM [13] WARN ClientLauncher - ReplicationSecretDecryptor: decrypted secret:i¯ƒü„ :_ùÀ&ñw½hQ expected crc:762667822 actual:762667822.

ThalesVinayak commented 2 years ago

@MichaelGrafnetter issue is reproducible on windows server 2019 standard as well. @andrei-galkin

ThalesVinayak commented 2 years ago

@MichaelGrafnetter we further investigated the issue, we reverted back to all the previous version of DSInternals and identified that issue started to happen when DSinternal was upgraded from 4.1 to 4.2(multi-domain/forest support to Test-PasswordQuality) and below is the commit which has brought in the issue

https://github.com/MichaelGrafnetter/DSInternals/commit/4bd98076879cdb91c77383a8d37630ad031e708e

Particularly the issue is with the file https://github.com/MichaelGrafnetter/DSInternals/commit/4bd98076879cdb91c77383a8d37630ad031e708e#diff-8897063dea57c61fae8eefd70f5fdb014df6025a3b263b8e44e07ff65b1a6a2a Under the method DSAccount GetAccount(string distinguishedName), the NetBIOSDomainName value is passed to instantiate DSAccount. I tried passing hard coded valid value for NetBIOSDomainName instead of calculating it and no such exception was thrown. so the issue seems to be happening while evaluating NetBIOSDomainName using the method this.LoadDomainInfo(). Please see if this is the root cause. FYI @andrei-galkin

MichaelGrafnetter commented 2 years ago

Thanks @ThalesVinayak , I will look into it.

ThalesVinayak commented 2 years ago

Hi @MichaelGrafnetter, we are able to resolve the issue by using below line in our code.

replicationClient.Dispose(); replicationClient = null;

I think we can close this issue. Thank you

MichaelGrafnetter commented 2 years ago

Hello @ThalesVinayak , I still was not able to replicate this issue. I received a similar report yesterday and it seems to be caused by a non-US version of Windows Server DC. Could you please share what language version you have on the affected DC? Another suspicion of mine is some out-of-band session key change.

ThalesVinayak commented 2 years ago

Hello @MichaelGrafnetter, the language version is 0409/en-US/English - United States.

In our case, we were not disposing replication client created and as a result related DRS connections were not getting disposed off as well. After reaching a threshold they were creating the issue around evaluating NetBiosDomainName(evaluated via lazy loading).