From 85d987632d97c39afecae757aa35abeef411af05 Mon Sep 17 00:00:00 2001 From: Alex Seigler Date: Fri, 20 Sep 2024 17:15:09 -0400 Subject: [PATCH 1/3] Implement searching password hashes using split database --- .../Misc/TestPasswordQualityCommand.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs index e457a94..50b968f 100644 --- a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs +++ b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs @@ -94,6 +94,14 @@ public string WeakPasswordHashesSortedFile get; set; } + + [Parameter] + [ValidateNotNullOrEmpty] + public string WeakPasswordHashesSortedFilePath + { + get; + set; + } #endregion Parameters #region Fields @@ -115,10 +123,11 @@ protected override void BeginProcessing() // Test the optional file path in advance to throw an early error. this.ResolveFilePath(this.WeakPasswordHashesFile); this.ResolveFilePath(this.WeakPasswordsFile); + this.ResolveDirectoryPath(this.WeakPasswordHashesSortedFilePath); // Open the sorted weak password hashes file, as we will be searching it on-the-fly. string sortedHashesFile = this.ResolveFilePath(this.WeakPasswordHashesSortedFile); - if(sortedHashesFile != null) + if (sortedHashesFile != null) { this.sortedHashFileSearcher = new SortedFileSearcher(sortedHashesFile); } @@ -294,10 +303,24 @@ private bool ShouldTestWeakPasswordsInMemory private void LookupAccountNTHashInSortedFile() { + string hash = this.Account.NTHash.ToHex(true); + // If there is a file path present, the hashes are in seperate sorted files + if (this.WeakPasswordHashesSortedFilePath != null) + { + // The files in the path should be named with the first 5 chararacters of the hash and the extension txt, like ABDD0.txt + string sortedHashesFile = this.ResolveFilePath(this.WeakPasswordHashesSortedFilePath + hash.Substring(0, 5) + ".txt"); + if (sortedHashesFile != null) + { + // Assuming all went well, we should be able to set up to search this much smaller file for the hashes + this.sortedHashFileSearcher = new SortedFileSearcher(sortedHashesFile); + hash = hash.Substring(5); + } + } + if (this.sortedHashFileSearcher != null) { // Check the password on the fly in the sorted file using binary search - bool found = this.sortedHashFileSearcher.FindString(this.Account.NTHash.ToHex()); + bool found = this.sortedHashFileSearcher.FindString(hash); if (found) { this.result.WeakPassword.UnionWith(new string[] { this.Account.LogonName }); From 7ba2626ab743c916f5abd38a7c8cee7f11a046ef Mon Sep 17 00:00:00 2001 From: Alex Seigler Date: Mon, 23 Sep 2024 11:33:10 -0400 Subject: [PATCH 2/3] Update TestPasswordQualityCommand.cs Update comment --- .../Commands/Misc/TestPasswordQualityCommand.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs index 50b968f..3a0a30e 100644 --- a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs +++ b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs @@ -313,6 +313,8 @@ private void LookupAccountNTHashInSortedFile() { // Assuming all went well, we should be able to set up to search this much smaller file for the hashes this.sortedHashFileSearcher = new SortedFileSearcher(sortedHashesFile); + + // In the split database the hashes are stored in the sorted files starting with the 6th character (since the filename is the first 5 hash = hash.Substring(5); } } From dee85e4f0ea3a443ea702316b143b51e308aff1c Mon Sep 17 00:00:00 2001 From: Alex Seigler Date: Mon, 23 Sep 2024 16:49:36 -0400 Subject: [PATCH 3/3] Add parameter sets for WeakPasswordHashesSortedFile/WeakPasswordHashesSortedFilePath, update documentation --- .../PowerShell/Test-PasswordQuality.md | 33 ++++++++++++++++--- .../Misc/TestPasswordQualityCommand.cs | 8 +++-- .../en-US/DSInternals.PowerShell.dll-Help.xml | 26 +++++++++++---- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Documentation/PowerShell/Test-PasswordQuality.md b/Documentation/PowerShell/Test-PasswordQuality.md index 0c2dab8..d7b11c9 100644 --- a/Documentation/PowerShell/Test-PasswordQuality.md +++ b/Documentation/PowerShell/Test-PasswordQuality.md @@ -12,12 +12,20 @@ Performs AD audit, including checks for weak, duplicate, default and empty passw ## SYNTAX +### Using monolithic password hashes sorted file (HIBP v8 and earlier) ``` Test-PasswordQuality [-Account] [-SkipDuplicatePasswordTest] [-IncludeDisabledAccounts] [-WeakPasswords ] [-WeakPasswordsFile ] [-WeakPasswordHashesFile ] [-WeakPasswordHashesSortedFile ] [] ``` +### Using multiple password hashes sorted files (HIBP after v8) +``` +Test-PasswordQuality [-Account] [-SkipDuplicatePasswordTest] [-IncludeDisabledAccounts] + [-WeakPasswords ] [-WeakPasswordsFile ] [-WeakPasswordHashesFile ] + [-WeakPasswordHashesSortedFilePath ] [] +``` + ## DESCRIPTION The Test-PasswordQuality cmdlet is a simple tool for Active Directory password auditing. It can detect weak, duplicate, default, non-expiring or empty passwords and find accounts that are violating security best practices. The cmdlet accepts output of the Get-ADDBAccount and Get-ADReplAccount cmdlets, so both offline (ntds.dit) and online (DCSync) password analysis can be done. @@ -31,7 +39,7 @@ Although the cmdlet output is formatted in a human readable fashion, it is still ### Example 1 ```powershell PS C:\> Get-ADDBAccount -All -DatabasePath ntds.dit -BootKey acdba64a3929261b04e5270c3ef973cf | - Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + Test-PasswordQuality -WeakPasswordHashesSortedFilePath P:\pwnedpasswords_ntlm <# Sample Output: Active Directory Password Quality Report @@ -102,7 +110,7 @@ Performs an offline credential hygiene audit of AD database against HIBP. ```powershell PS C:\> $results = Get-ADReplAccount -All -Server LON-DC1 | Test-PasswordQuality -WeakPasswords 'Pa$$w0rd','April2019' ` - -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v8.txt ``` Performs an online credential hygiene audit of AD against HIBP + a custom wordlist. @@ -120,7 +128,7 @@ Performs a dictionary attack against a set of accounts. The Test-PasswordQuality ```powershell PS C:\> Get-ADDBAccount -All -DatabasePath ntds.dit -BootKey $key | where DistinguishedName -like '*OU=Employees,DC=contoso,DC=com' | - Test-PasswordQuality -IncludeDisabledAccounts -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + Test-PasswordQuality -IncludeDisabledAccounts -WeakPasswordHashesSortedFilePath P:\pwnedpasswords_ntlm ``` Performs an offline credential hygiene audit of a selected OU from AD database against HIBP. @@ -209,11 +217,26 @@ Accept wildcard characters: False ``` ### -WeakPasswordHashesSortedFile -Path to a file that contains NT hashes of weak passwords, one hash in HEX format per line. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned. +Path to a file that contains NT hashes of weak passwords, one hash in HEX format per line. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned, v8 and earlier. ```yaml Type: String -Parameter Sets: (All) +Parameter Sets: SingleFile +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WeakPasswordHashesSortedFilePath +Path to a directory of files named as the first five characters of an NT hash (00000.txt - FFFFF.txt), each of which contain NT hashes of weak passwords, one hash in HEX format per line, starting with the 6th character in the hash. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned after v8. + +```yaml +Type: String +Parameter Sets: MultiFile Aliases: Required: False diff --git a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs index 3a0a30e..799f2f2 100644 --- a/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs +++ b/Src/DSInternals.PowerShell/Commands/Misc/TestPasswordQualityCommand.cs @@ -15,6 +15,10 @@ public class TestPasswordQualityCommand : PSCmdletEx, IDisposable { #region Constants + protected const string ParamSetSingleSortedFile = "SingleFile"; + + protected const string ParamSetMultipuleSortedFile = "MultiFile"; + /// /// Expected number of users being processed. /// @@ -87,7 +91,7 @@ public string WeakPasswordHashesFile set; } - [Parameter] + [Parameter(ParameterSetName = ParamSetSingleSortedFile)] [ValidateNotNullOrEmpty] public string WeakPasswordHashesSortedFile { @@ -95,7 +99,7 @@ public string WeakPasswordHashesSortedFile set; } - [Parameter] + [Parameter(ParameterSetName = ParamSetMultipuleSortedFile)] [ValidateNotNullOrEmpty] public string WeakPasswordHashesSortedFilePath { diff --git a/Src/DSInternals.PowerShell/en-US/DSInternals.PowerShell.dll-Help.xml b/Src/DSInternals.PowerShell/en-US/DSInternals.PowerShell.dll-Help.xml index 96d3616..fce083e 100644 --- a/Src/DSInternals.PowerShell/en-US/DSInternals.PowerShell.dll-Help.xml +++ b/Src/DSInternals.PowerShell/en-US/DSInternals.PowerShell.dll-Help.xml @@ -3606,7 +3606,7 @@ Credential Roaming PS C:\> $results = Get-ADDBAccount -DatabasePath '.\Active Directory\ntds.dit' ` -BootKey acdba64a3929261b04e5270c3ef973cf ` -All | - Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v8.txt Performs an offline credential hygiene audit of AD database against HIBP. @@ -5572,7 +5572,7 @@ Credential Roaming -------------------------- Example 3 -------------------------- PS C:\> $results = Get-ADReplAccount -All -Server 'lon-dc1.contoso.com' | - Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v8.txt Performs an online credential hygiene audit of AD against HIBP. @@ -10947,7 +10947,19 @@ PS C:\> Set-AzureADUserEx -UserPrincipalName 'john@contoso.com' -KeyCredentia WeakPasswordHashesSortedFile - Path to a file that contains NT hashes of weak passwords, one hash in HEX format per line. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned. + Path to a file that contains NT hashes of weak passwords, one hash in HEX format per line. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned, v8 and earlier. + + String + + String + + + None + + + WeakPasswordHashesSortedFilePath + + Path to a directory of files named as the first five characters of an NT hash (00000.txt - FFFFF.txt), each of which contain NT hashes of weak passwords, one hash in HEX format per line, starting with the 6th character in the hash. The hashes must be sorted alphabetically, because a binary search is performed. This parameter is typically used with a list of leaked password hashes from HaveIBeenPwned after v8. String @@ -11097,8 +11109,8 @@ PS C:\> Set-AzureADUserEx -UserPrincipalName 'john@contoso.com' -KeyCredentia -------------------------- Example 1 -------------------------- PS C:\> Get-ADDBAccount -All -DatabasePath ntds.dit -BootKey acdba64a3929261b04e5270c3ef973cf | - Test-PasswordQuality -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt -<# Sample Output: + Test-PasswordQuality -WeakPasswordHashesSortedFilePath P:\pwnedpasswords_ntlm + <# Sample Output: Active Directory Password Quality Report ---------------------------------------- @@ -11168,7 +11180,7 @@ These accounts that require smart card authentication have a password: -------------------------- Example 2 -------------------------- PS C:\> $results = Get-ADReplAccount -All -Server LON-DC1 | Test-PasswordQuality -WeakPasswords 'Pa$$w0rd','April2019' ` - -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v5.txt + -WeakPasswordHashesSortedFile pwned-passwords-ntlm-ordered-by-hash-v8.txt Performs an online credential hygiene audit of AD against HIBP + a custom wordlist. @@ -11653,4 +11665,4 @@ These groups of accounts have the same passwords: - \ No newline at end of file +