UPN retrieval added

This commit is contained in:
2024-08-12 11:34:09 +02:00
parent 2269660984
commit 51b518613f
3 changed files with 116 additions and 24 deletions

8
CHANGELOG.md Normal file
View File

@@ -0,0 +1,8 @@
# Changelog
## Extract-NTHashes.ps1
### version 1.1.0
**Added:**
- UPN retrieval (this will prolong the time needed to run the script significantly)
- Better error handling

View File

@@ -14,9 +14,9 @@
# KHDB Settings # KHDB Settings
############### ###############
storageAccountName = '' storageAccountName =
containerName = '' containerName =
sasToken = '?' sasToken =
# Application Settings # Application Settings
###################### ######################

View File

@@ -8,7 +8,7 @@
################################################## ##################################################
## Project: Elysium ## ## Project: Elysium ##
## File: Test-WeakADPasswords.ps1 ## ## File: Test-WeakADPasswords.ps1 ##
## Version: 1.0.1 ## ## Version: 1.1.0 ##
## Support: support@cqre.net ## ## Support: support@cqre.net ##
################################################## ##################################################
@@ -17,9 +17,12 @@
Weak AD password finder component of Elysium tool. Weak AD password finder component of Elysium tool.
.DESCRIPTION .DESCRIPTION
This script will test the passwords of selected domain (defined in ElysiumSettings.txt) using DSInternals' Test-PasswordQuality cmdlet. It writes its output to a report file which is meant to be shared with the internal security team. This script will test the passwords of selected domain (defined in ElysiumSettings.txt) using DSInternals' Test-PasswordQuality cmdlet. It writes its output to a report file which is meant to be shared with the internal security team. The report now includes UPNs for each account mentioned.
#> #>
# Enable verbose output
$VerbosePreference = "Continue"
# Current timestamp for both report generation and header # Current timestamp for both report generation and header
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
@@ -33,7 +36,7 @@ Report Generated: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
$footer = "`r`n==== End of Report ====" $footer = "`r`n==== End of Report ===="
# Import settings # Import settings
Write-Host "Loading settings..." Write-Verbose "Loading settings..."
$ElysiumSettings = @{} $ElysiumSettings = @{}
$settingsPath = "ElysiumSettings.txt" $settingsPath = "ElysiumSettings.txt"
@@ -44,6 +47,7 @@ if (-not (Test-Path $settingsPath)) {
} }
# Load settings from file # Load settings from file
try {
Get-Content $settingsPath | ForEach-Object { Get-Content $settingsPath | ForEach-Object {
if (-not [string]::IsNullOrWhiteSpace($_) -and -not $_.StartsWith("#")) { if (-not [string]::IsNullOrWhiteSpace($_) -and -not $_.StartsWith("#")) {
$keyValue = $_ -split '=', 2 $keyValue = $_ -split '=', 2
@@ -52,6 +56,11 @@ Get-Content $settingsPath | ForEach-Object {
} }
} }
} }
Write-Verbose "Settings loaded successfully."
} catch {
Write-Error ("An error occurred while loading settings: {0}" -f $_.Exception.Message)
exit
}
# Define the function to extract domain details from settings # Define the function to extract domain details from settings
function Get-DomainDetailsFromSettings { function Get-DomainDetailsFromSettings {
@@ -80,6 +89,7 @@ function Get-DomainDetailsFromSettings {
# Continue with script logic... # Continue with script logic...
$domainDetails = Get-DomainDetailsFromSettings -Settings $ElysiumSettings $domainDetails = Get-DomainDetailsFromSettings -Settings $ElysiumSettings
Write-Verbose ("Domain details extracted: {0}" -f ($domainDetails | ConvertTo-Json))
# Required modules # Required modules
$requiredModules = @("DSInternals", "ActiveDirectory") $requiredModules = @("DSInternals", "ActiveDirectory")
@@ -87,10 +97,23 @@ $requiredModules = @("DSInternals", "ActiveDirectory")
# Check each required module and import # Check each required module and import
foreach ($module in $requiredModules) { foreach ($module in $requiredModules) {
if (-not (Get-Module -ListAvailable -Name $module)) { if (-not (Get-Module -ListAvailable -Name $module)) {
Write-Verbose "Required module '$module' is not installed."
$response = Read-Host "Would you like to install it? (Y/N)"
if ($response -eq 'Y') {
try {
Install-Module -Name $module -Force -ErrorAction Stop
Write-Verbose "Module '$module' installed successfully."
} catch {
Write-Error ("Failed to install module '{0}': {1}" -f $module, $_.Exception.Message)
exit
}
} else {
Write-Error "Required module '$module' is not installed. Please install it to proceed." Write-Error "Required module '$module' is not installed. Please install it to proceed."
exit exit
} }
}
Import-Module $module Import-Module $module
Write-Verbose "Module '$module' imported."
} }
# Verify the existence of the Weak Password Hashes file # Verify the existence of the Weak Password Hashes file
@@ -99,11 +122,37 @@ if (-not (Test-Path $WeakHashesSortedFilePath)) {
Write-Error "Weak password hashes file not found at '$WeakHashesSortedFilePath'." Write-Error "Weak password hashes file not found at '$WeakHashesSortedFilePath'."
exit exit
} }
Write-Verbose "Weak password hashes file found at '$WeakHashesSortedFilePath'."
# Ensure the report directory exists # Ensure the report directory exists
$reportPathBase = $ElysiumSettings["ReportPathBase"] $reportPathBase = $ElysiumSettings["ReportPathBase"]
if (-not (Test-Path -Path $reportPathBase)) { if (-not (Test-Path -Path $reportPathBase)) {
New-Item -Path $reportPathBase -ItemType Directory try {
New-Item -Path $reportPathBase -ItemType Directory -ErrorAction Stop
Write-Verbose "Report directory created at '$reportPathBase'."
} catch {
Write-Error ("Failed to create report directory: {0}" -f $_.Exception.Message)
exit
}
}
# Function to get UPN for a given SAM account name
function Get-UserUPN {
param (
[string]$SamAccountName,
[string]$Domain,
[System.Management.Automation.PSCredential]$Credential
)
Write-Verbose "Attempting to get UPN for $SamAccountName in domain $Domain"
try {
$user = Get-ADUser -Identity $SamAccountName -Properties UserPrincipalName -Server $Domain -Credential $Credential
Write-Verbose "UPN found: $($user.UserPrincipalName)"
return $user.UserPrincipalName
} catch {
Write-Verbose ("Failed to get UPN for {0}: {1}" -f $SamAccountName, $_.Exception.Message)
return "UPN not found"
}
} }
# Function to test for weak AD passwords # Function to test for weak AD passwords
@@ -117,29 +166,64 @@ function Test-WeakADPasswords {
Write-Host "Select a domain to test:" Write-Host "Select a domain to test:"
$DomainDetails.GetEnumerator() | ForEach-Object { Write-Host "$($_.Key): $($_.Value.Name)" } $DomainDetails.GetEnumerator() | ForEach-Object { Write-Host "$($_.Key): $($_.Value.Name)" }
$selection = Read-Host "Enter the number of the domain" $selection = Read-Host "Enter the number of the domain"
$selectedDomain = $DomainDetails[$selection]
if (-not $selectedDomain) { if (-not ($DomainDetails.ContainsKey($selection))) {
Write-Error "Invalid selection." Write-Error "Invalid selection."
return return
} }
$selectedDomain = $DomainDetails[$selection]
Write-Verbose "Selected domain: $($selectedDomain.Name)"
# Prompt for DA credentials # Prompt for DA credentials
$credential = Get-Credential -Message "Enter AD credentials with replication rights for $($selectedDomain.Name)" $credential = Get-Credential -Message "Enter AD credentials with replication rights for $($selectedDomain.Name)"
# Performing the test # Performing the test
Write-Host "Testing password quality for $($selectedDomain.Name)..." Write-Verbose "Testing password quality for $($selectedDomain.Name)..."
try {
$testResults = Get-ADReplAccount -All -Server $selectedDomain["DC"] -Credential $credential | $testResults = Get-ADReplAccount -All -Server $selectedDomain["DC"] -Credential $credential |
Test-PasswordQuality -WeakPasswordHashesFile $FilePath Test-PasswordQuality -WeakPasswordHashesFile $FilePath
Write-Verbose "Password quality test completed."
} catch {
Write-Error ("An error occurred while testing passwords: {0}" -f $_.Exception.Message)
return
}
# Report generation with dynamic content # Report generation with dynamic content and UPNs
$reportPath = Join-Path -Path $reportPathBase -ChildPath "$($selectedDomain.Name)_WeakPasswordReport_$timestamp.txt" $reportPath = Join-Path -Path $reportPathBase -ChildPath "$($selectedDomain.Name)_WeakPasswordReport_$timestamp.txt"
Write-Verbose "Generating report at $reportPath"
$reportContent = @($header, ($testResults | Out-String).Trim(), $footer) -join "`r`n" $reportContent = @($header, ($testResults | Out-String).Trim(), $footer) -join "`r`n"
$reportContent | Out-File -FilePath $reportPath
$lines = $reportContent -split "`r`n"
$newReportContent = @()
foreach ($line in $lines) {
$newReportContent += $line
if ($line -match "$($selectedDomain.Name)\\(.+)") {
$samAccountName = $matches[1]
Write-Verbose "Looking up UPN for $samAccountName"
$upn = Get-UserUPN -SamAccountName $samAccountName -Domain $selectedDomain.DC -Credential $credential
$newReportContent += " UPN: $upn"
}
}
$updatedReportContent = $newReportContent -join "`r`n"
try {
$updatedReportContent | Out-File -FilePath $reportPath -ErrorAction Stop
Write-Host "Report saved to $reportPath" Write-Host "Report saved to $reportPath"
} catch {
Write-Error ("Failed to save report: {0}" -f $_.Exception.Message)
}
} }
# Main script logic # Main script logic
try {
Write-Verbose "Starting main script execution..."
Test-WeakADPasswords -DomainDetails $domainDetails -FilePath $WeakHashesSortedFilePath Test-WeakADPasswords -DomainDetails $domainDetails -FilePath $WeakHashesSortedFilePath
} catch {
Write-Error ("An error occurred during script execution: {0}" -f $_.Exception.Message)
}
Write-Host "Script execution completed." Write-Host "Script execution completed."