Improve weak password test credential diagnostics and docs
This commit is contained in:
10
README.md
10
README.md
@@ -46,7 +46,7 @@ Every run also emits a cleaned, DSInternals-friendly `khdb-clean.txt` beside the
|
|||||||
When `-ForcePlainText` is specified the script automatically keeps a checkpoint (default: `<output>/khdb.checkpoint.json`) and resumes from it on the next run so massive inputs don’t restart from scratch. Use `-CheckpointPath` to relocate that file or `-NoCheckpoint` to disable the behavior entirely.
|
When `-ForcePlainText` is specified the script automatically keeps a checkpoint (default: `<output>/khdb.checkpoint.json`) and resumes from it on the next run so massive inputs don’t restart from scratch. Use `-CheckpointPath` to relocate that file or `-NoCheckpoint` to disable the behavior entirely.
|
||||||
### Test Weak AD passwords
|
### Test Weak AD passwords
|
||||||
Run script Elysium.ps1 as an administrator and choose option 2 (Test Weak AD Passwords).
|
Run script Elysium.ps1 as an administrator and choose option 2 (Test Weak AD Passwords).
|
||||||
The script will list domains in the same order as they appear in `ElysiumSettings.txt` and, after you pick one, prompt for the corresponding domain administrator password (the username is taken from the settings file).
|
The script lists domains in the same order as they appear in `ElysiumSettings.txt`. After you pick one, it prompts for credentials and validates them against the selected domain controller before running the password-quality test.
|
||||||
The tool connects to the selected Domain Controller and compares accounts against KHDB (respecting the optional `CheckOnlyEnabledUsers` flag if configured). A timestamped text report is saved under `Reports`, and accounts with dictionary hits are also exported to a dedicated UPN-only text file to support follow-up automation.
|
The tool connects to the selected Domain Controller and compares accounts against KHDB (respecting the optional `CheckOnlyEnabledUsers` flag if configured). A timestamped text report is saved under `Reports`, and accounts with dictionary hits are also exported to a dedicated UPN-only text file to support follow-up automation.
|
||||||
The KHDB file is consumed via binary search as a sorted hash list (plain text lines like `HASH:count`); ensure the file you place at `khdb.txt` keeps that ordering and omits stray blank lines.
|
The KHDB file is consumed via binary search as a sorted hash list (plain text lines like `HASH:count`); ensure the file you place at `khdb.txt` keeps that ordering and omits stray blank lines.
|
||||||
|
|
||||||
@@ -58,6 +58,14 @@ The DSInternals cmdlets (`Get-ADReplAccount`/`Test-PasswordQuality`) pull replic
|
|||||||
|
|
||||||
To delegate, enable Advanced Features in ADUC, right-click the domain, choose *Delegate Control…*, pick the service account, select *Create a custom task*, apply to *This object and all descendant objects*, and tick the three replication permissions above. Keep this account disabled and only activate it for scheduled tests.
|
To delegate, enable Advanced Features in ADUC, right-click the domain, choose *Delegate Control…*, pick the service account, select *Create a custom task*, apply to *This object and all descendant objects*, and tick the three replication permissions above. Keep this account disabled and only activate it for scheduled tests.
|
||||||
|
|
||||||
|
#### Common errors
|
||||||
|
- `The server has rejected the client credentials.` or `Credentials ... were rejected`:
|
||||||
|
The supplied username/password is invalid for the selected domain controller, or the session is not running in the expected domain context. Re-run and provide valid domain credentials.
|
||||||
|
- `Get-ADReplAccount: Access is denied`:
|
||||||
|
Credentials are valid, but the account does not have the three replication permissions listed above.
|
||||||
|
- `Only FIPS certified cryptographic algorithms are enabled in .NET`:
|
||||||
|
This warning comes from DSInternals under FIPS-enforced environments. Hash-quality operations that rely on MD5 may be limited.
|
||||||
|
|
||||||
#### Optional usage beacon
|
#### Optional usage beacon
|
||||||
If you want to know the script was executed without collecting telemetry, set a pre-signed URL (for example, an S3 `PUT` URL) in `UsageBeaconUrl` inside `ElysiumSettings.txt`. When present, the weak-password script issues a single request as soon as it loads the settings. Only the script name, its version, a UTC timestamp, and the optional `UsageBeaconInstanceId` value are sent, and network failures never block the run. Choose the HTTP verb via `UsageBeaconMethod` (`GET`, `POST`, or `PUT`) and adjust the timeout with `UsageBeaconTimeoutSeconds` if your storage endpoint needs more time.
|
If you want to know the script was executed without collecting telemetry, set a pre-signed URL (for example, an S3 `PUT` URL) in `UsageBeaconUrl` inside `ElysiumSettings.txt`. When present, the weak-password script issues a single request as soon as it loads the settings. Only the script name, its version, a UTC timestamp, and the optional `UsageBeaconInstanceId` value are sent, and network failures never block the run. Choose the HTTP verb via `UsageBeaconMethod` (`GET`, `POST`, or `PUT`) and adjust the timeout with `UsageBeaconTimeoutSeconds` if your storage endpoint needs more time.
|
||||||
|
|
||||||
|
|||||||
@@ -402,12 +402,42 @@ function Get-UserUPN {
|
|||||||
|
|
||||||
# (removed stray top-level loop; UPN enrichment happens during report generation below)
|
# (removed stray top-level loop; UPN enrichment happens during report generation below)
|
||||||
|
|
||||||
|
function Get-ValidatedADCredential {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory)][string]$DomainName,
|
||||||
|
[Parameter(Mandatory)][string]$Server,
|
||||||
|
[int]$MaxAttempts = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {
|
||||||
|
$credential = Get-Credential -Message "Enter AD credentials with replication rights for $DomainName (attempt $attempt/$MaxAttempts)"
|
||||||
|
if ($null -eq $credential) {
|
||||||
|
throw "Credential prompt was cancelled."
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Get-ADDomain -Server $Server -Credential $credential -ErrorAction Stop | Out-Null
|
||||||
|
Write-Verbose ("Credential pre-check succeeded for '{0}' against '{1}'." -f $credential.UserName, $Server)
|
||||||
|
return $credential
|
||||||
|
} catch {
|
||||||
|
$message = $_.Exception.Message
|
||||||
|
if ($message -match 'rejected the client credentials|unknown user name|bad password|logon failure') {
|
||||||
|
Write-Warning ("Credentials were rejected for '{0}' (attempt {1}/{2})." -f $credential.UserName, $attempt, $MaxAttempts)
|
||||||
|
if ($attempt -lt $MaxAttempts) { continue }
|
||||||
|
throw "Credentials were rejected by domain controller '$Server' after $MaxAttempts attempts."
|
||||||
|
}
|
||||||
|
throw "Credential pre-check failed against '$Server': $message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Function to test for weak AD passwords
|
# Function to test for weak AD passwords
|
||||||
function Test-WeakADPasswords {
|
function Test-WeakADPasswords {
|
||||||
param (
|
param (
|
||||||
[hashtable]$DomainDetails,
|
[hashtable]$DomainDetails,
|
||||||
[string]$FilePath,
|
[string]$FilePath,
|
||||||
[bool]$CheckOnlyEnabledUsers = $false
|
[bool]$CheckOnlyEnabledUsers = $false,
|
||||||
|
[System.Management.Automation.PSCredential]$Credential
|
||||||
)
|
)
|
||||||
|
|
||||||
# User selects a domain
|
# User selects a domain
|
||||||
@@ -423,8 +453,17 @@ function Test-WeakADPasswords {
|
|||||||
$selectedDomain = $DomainDetails[$selection]
|
$selectedDomain = $DomainDetails[$selection]
|
||||||
Write-Verbose "Selected domain: $($selectedDomain.Name)"
|
Write-Verbose "Selected domain: $($selectedDomain.Name)"
|
||||||
|
|
||||||
# Prompt for DA credentials
|
if ([string]::IsNullOrWhiteSpace($selectedDomain["DC"])) {
|
||||||
$credential = Get-Credential -Message "Enter AD credentials with replication rights for $($selectedDomain.Name)"
|
Write-Error ("Domain '{0}' does not have a configured DC in ElysiumSettings.txt." -f $selectedDomain.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($null -eq $Credential) {
|
||||||
|
$credential = Get-ValidatedADCredential -DomainName $selectedDomain.Name -Server $selectedDomain["DC"]
|
||||||
|
} else {
|
||||||
|
$credential = $Credential
|
||||||
|
Write-Verbose ("Using credential supplied by caller: {0}" -f $credential.UserName)
|
||||||
|
}
|
||||||
|
|
||||||
# Performing the test
|
# Performing the test
|
||||||
Write-Verbose "Testing password quality for $($selectedDomain.Name)..."
|
Write-Verbose "Testing password quality for $($selectedDomain.Name)..."
|
||||||
@@ -440,7 +479,16 @@ function Test-WeakADPasswords {
|
|||||||
$testResults = $accounts | Test-PasswordQuality -WeakPasswordHashesSortedFile $FilePath
|
$testResults = $accounts | Test-PasswordQuality -WeakPasswordHashesSortedFile $FilePath
|
||||||
Write-Verbose "Password quality test completed."
|
Write-Verbose "Password quality test completed."
|
||||||
} catch {
|
} catch {
|
||||||
Write-Error ("An error occurred while testing passwords: {0}" -f $_.Exception.Message)
|
$message = $_.Exception.Message
|
||||||
|
if ($message -match 'Access is denied') {
|
||||||
|
Write-Error ("Access denied while reading replication data from '{0}' using '{1}'. Ensure this account has Replicating Directory Changes, Replicating Directory Changes All, and Replicating Directory Changes In Filtered Set on the domain." -f $selectedDomain["DC"], $credential.UserName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($message -match 'rejected the client credentials|unknown user name|bad password|logon failure') {
|
||||||
|
Write-Error ("Credentials for '{0}' were rejected by '{1}'. Re-run and provide valid domain credentials." -f $credential.UserName, $selectedDomain["DC"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Write-Error ("An error occurred while testing passwords: {0}" -f $message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user