New updates

This commit is contained in:
2025-10-10 15:09:33 +02:00
parent 76c9fcfb61
commit aa54c751c3
7 changed files with 436 additions and 207 deletions

View File

@@ -7,7 +7,7 @@
##################################################
## Project: Elysium ##
## File: Update-KHDB.ps1 ##
## Version: 1.0.1 ##
## Version: 1.1.0 ##
## Support: support@cqre.net ##
##################################################
@@ -16,83 +16,183 @@
Known hashes database update script for the Elysium AD password testing tool.
.DESCRIPTION
This script downloads khdb.txt.zip from the designated Azure Storage account, decompresses it, and overwrites the current version.
This script downloads khdb.txt.zip from the designated Azure Storage account, validates and decompresses it, and atomically updates the current version with backup and logging.
#>
# Initialize an empty hashtable to store settings
$ElysiumSettings = @{}
# safer defaults
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
# Read the settings file
$settingsPath = "ElysiumSettings.txt"
Get-Content $settingsPath | ForEach-Object {
if ($_ -notmatch '^#' -and $_.Trim()) {
$keyValue = $_.Split('=', 2)
$key = $keyValue[0].Trim()
$value = $keyValue[1].Trim().Trim("'")
$ElysiumSettings[$key] = $value
# ensure TLS 1.2
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
# Resolve paths
$scriptRoot = $PSScriptRoot
function Start-UpdateTranscript {
param(
[string]$BasePath
)
try {
$logsDir = Join-Path -Path $BasePath -ChildPath 'Reports/logs'
if (-not (Test-Path $logsDir)) { New-Item -Path $logsDir -ItemType Directory -Force | Out-Null }
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
$logPath = Join-Path -Path $logsDir -ChildPath "update-khdb-$ts.log"
Start-Transcript -Path $logPath -Force | Out-Null
} catch {
Write-Warning "Could not start transcript: $($_.Exception.Message)"
}
}
# Verify that all required settings have been loaded
if (-not $ElysiumSettings.ContainsKey("storageAccountName") -or
-not $ElysiumSettings.ContainsKey("containerName") -or
-not $ElysiumSettings.ContainsKey("sasToken")) {
Write-Error "Missing required settings. Please check your settings file."
return
function Stop-UpdateTranscript {
try { Stop-Transcript | Out-Null } catch {}
}
# Construct the full URL for accessing the Azure Blob Storage
$storageAccountName = $ElysiumSettings["storageAccountName"]
$containerName = $ElysiumSettings["containerName"]
$sasToken = $ElysiumSettings["sasToken"]
$AzureBlobStorageUrl = "https://$storageAccountName.blob.core.windows.net/$containerName/khdb.txt.zip$sasToken"
# Load necessary .NET assembly for HTTP operations
Add-Type -AssemblyName System.Net.Http
function Update-KHDB {
Write-Host "Downloading KHDB..."
# Initialize the client for downloading the file
$httpClient = New-Object System.Net.Http.HttpClient
try {
# Start the asynchronous request to download the file
$response = $httpClient.GetAsync($AzureBlobStorageUrl, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).Result
if ($response.IsSuccessStatusCode) {
$totalBytes = $response.Content.Headers.ContentLength
$totalRead = 0
$read = 0
$buffer = New-Object byte[] 8192
$stream = $response.Content.ReadAsStreamAsync().Result
$fileStream = [System.IO.File]::Create("khdb.txt.zip")
# Read the stream in chunks and update the progress bar
while (($read = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
$fileStream.Write($buffer, 0, $read)
$totalRead += $read
$percentage = ($totalRead * 100) / $totalBytes
Write-Progress -Activity "Downloading khdb.txt.zip" -Status "$([Math]::Round($percentage, 2))% Complete:" -PercentComplete $percentage
}
$fileStream.Close()
Write-Host "KHDB.zip downloaded successfully."
} else {
Write-Error "Failed to download khdb.txt.zip: $($response.StatusCode)"
function Read-ElysiumSettings {
$settings = @{}
$settingsPath = Join-Path -Path $scriptRoot -ChildPath 'ElysiumSettings.txt'
if (-not (Test-Path $settingsPath)) { throw "Settings file not found at $settingsPath" }
Get-Content $settingsPath | ForEach-Object {
if ($_ -and -not $_.Trim().StartsWith('#')) {
$kv = $_ -split '=', 2
if ($kv.Count -eq 2) { $settings[$kv[0].Trim()] = $kv[1].Trim().Trim("'") }
}
} catch {
Write-Error "Error during download: $_"
return
}
return $settings
}
# Decompressing KHDB.zip
function Get-InstallationPath([hashtable]$settings) {
$p = $settings['InstallationPath']
if ([string]::IsNullOrWhiteSpace($p)) { return $scriptRoot }
if ([System.IO.Path]::IsPathRooted($p)) { return $p }
return (Join-Path -Path $scriptRoot -ChildPath $p)
}
function New-HttpClient {
Add-Type -AssemblyName System.Net.Http
$client = [System.Net.Http.HttpClient]::new()
$client.Timeout = [TimeSpan]::FromSeconds(600)
$client.DefaultRequestHeaders.UserAgent.ParseAdd('Elysium/1.1 (+Update-KHDB)')
return $client
}
function Build-BlobUri([string]$account, [string]$container, [string]$sas) {
if ([string]::IsNullOrWhiteSpace($account)) { throw 'storageAccountName is missing or empty.' }
if ([string]::IsNullOrWhiteSpace($container)) { throw 'containerName is missing or empty.' }
if ([string]::IsNullOrWhiteSpace($sas)) { throw 'sasToken is missing or empty.' }
$sas = $sas.Trim()
if (-not $sas.StartsWith('?')) { $sas = '?' + $sas }
$ub = [System.UriBuilder]::new("https://$account.blob.core.windows.net/$container/khdb.txt.zip")
$ub.Query = $sas.TrimStart('?')
return $ub.Uri.AbsoluteUri
}
function Invoke-DownloadWithRetry([System.Net.Http.HttpClient]$client, [string]$uri, [string]$targetPath) {
$retries = 5
$delay = 2
for ($i = 0; $i -lt $retries; $i++) {
try {
$resp = $client.GetAsync($uri, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).Result
if (-not $resp.IsSuccessStatusCode) {
$code = [int]$resp.StatusCode
if (($code -ge 500 -and $code -lt 600) -or $code -eq 429 -or $code -eq 408) { throw "Transient HTTP error $code" }
throw "HTTP error $code"
}
$totalBytes = $resp.Content.Headers.ContentLength
$stream = $resp.Content.ReadAsStreamAsync().Result
$fs = [System.IO.File]::Create($targetPath)
try {
$buffer = New-Object byte[] 8192
$totalRead = 0
while (($read = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
$fs.Write($buffer, 0, $read)
$totalRead += $read
if ($totalBytes) {
$pct = ($totalRead * 100.0) / $totalBytes
Write-Progress -Activity "Downloading khdb.txt.zip" -Status ("{0:N2}% Complete" -f $pct) -PercentComplete $pct
} else {
Write-Progress -Activity "Downloading khdb.txt.zip" -Status ("Downloaded {0:N0} bytes" -f $totalRead) -PercentComplete 0
}
}
} finally {
$fs.Close(); $stream.Close()
}
return
} catch {
if ($i -lt ($retries - 1)) {
Write-Warning "Download failed (attempt $($i+1)/$retries): $($_.Exception.Message). Retrying in ${delay}s..."
Start-Sleep -Seconds $delay
$delay = [Math]::Min($delay * 2, 30)
} else {
throw
}
}
}
}
function Validate-KHDBFile([string]$path) {
if (-not (Test-Path $path)) { throw "Validation failed: $path not found" }
$lines = Get-Content -Path $path -Encoding UTF8
if (-not $lines -or $lines.Count -eq 0) { throw 'Validation failed: file is empty.' }
$regex = '^[0-9A-Fa-f]{32}$'
$invalid = $lines | Where-Object { $_ -notmatch $regex }
if ($invalid.Count -gt 0) {
throw ("Validation failed: {0} invalid lines detected." -f $invalid.Count)
}
# Deduplicate and normalize line endings
$unique = $lines | ForEach-Object { $_.Trim() } | Where-Object { $_ } | Sort-Object -Unique
Set-Content -Path $path -Value $unique -Encoding ASCII
}
function Update-KHDB {
Start-UpdateTranscript -BasePath $scriptRoot
try {
Expand-Archive -Path "khdb.txt.zip" -DestinationPath . -Force
Remove-Item -Path "khdb.txt.zip" -Force # Delete the zip file after extraction
Write-Host "KHDB decompressed and cleaned up successfully."
$settings = Read-ElysiumSettings
$installPath = Get-InstallationPath $settings
if (-not (Test-Path $installPath)) { New-Item -Path $installPath -ItemType Directory -Force | Out-Null }
$storageAccountName = $settings['storageAccountName']
$containerName = $settings['containerName']
$sasToken = $settings['sasToken']
$uri = Build-BlobUri -account $storageAccountName -container $containerName -sas $sasToken
$client = New-HttpClient
$tmpDir = New-Item -ItemType Directory -Path ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "elysium-khdb-" + [System.Guid]::NewGuid())) -Force
$zipPath = Join-Path -Path $tmpDir.FullName -ChildPath 'khdb.txt.zip'
$extractDir = Join-Path -Path $tmpDir.FullName -ChildPath 'extract'
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
Write-Host "Downloading KHDB from Azure Blob Storage..."
Invoke-DownloadWithRetry -client $client -uri $uri -targetPath $zipPath
Write-Host "Download completed. Extracting archive..."
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
$extractedKHDB = Get-ChildItem -Path $extractDir -Recurse -Filter 'khdb.txt' | Select-Object -First 1
if (-not $extractedKHDB) { throw 'Extracted archive does not contain khdb.txt.' }
# Validate content
Validate-KHDBFile -path $extractedKHDB.FullName
# Compute target path and backup
$targetKHDB = Join-Path -Path $installPath -ChildPath 'khdb.txt'
if (Test-Path $targetKHDB) {
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
$backupPath = Join-Path -Path $installPath -ChildPath ("khdb.txt.bak-$ts")
Copy-Item -Path $targetKHDB -Destination $backupPath -Force
Write-Host "Existing KHDB backed up to $backupPath"
}
# Atomic-ish replace: move validated file into place
Move-Item -Path $extractedKHDB.FullName -Destination $targetKHDB -Force
Write-Host "KHDB updated at $targetKHDB"
Write-Host "KHDB update completed successfully."
} catch {
Write-Error "Error decompressing KHDB: $_"
return
Write-Error ("KHDB update failed: {0}" -f $_.Exception.Message)
throw
} finally {
try { if ($tmpDir -and (Test-Path $tmpDir.FullName)) { Remove-Item -Path $tmpDir.FullName -Recurse -Force } } catch {}
Stop-UpdateTranscript
}
}