fix(passphrase): store DPAPI-protected, never plaintext or echoed

Elysium.ps1 used Read-Host without -AsSecureString (echoed the AES
passphrase to the console) and persisted it as plaintext in
HKCU\Environment via SetEnvironmentVariable, readable by anyone with
console visibility or local registry access. Switched to
Read-Host -AsSecureString and store ConvertFrom-SecureString's DPAPI
output (decryptable only by the same user on the same machine)
instead of the raw value.

Extract-NTHashes.ps1, the only other consumer, now decrypts that
DPAPI-protected string back to a plain string via
ConvertTo-SecureString + NetworkCredential right before handing it to
Protect-FileWithAES. A stale plaintext value from a prior version is
detected and the operator is prompted to re-enter it.

DPAPI protection is Windows-only, consistent with the rest of this
Windows/AD-only tool; not runnable end-to-end on this (non-Windows)
dev machine, verified by AST parse only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 11:50:59 +02:00
parent 4740cd3e97
commit ec00518952
2 changed files with 27 additions and 12 deletions
+18 -9
View File
@@ -39,17 +39,26 @@ if (-Not (Test-Path $settingsFilePath)) {
Write-Host "ElysiumSettings.txt found." Write-Host "ElysiumSettings.txt found."
} }
# Attempt to retrieve the passphrase from the environment variable # The passphrase is persisted DPAPI-protected (current user + machine) via ConvertFrom-SecureString,
$passphrase = [System.Environment]::GetEnvironmentVariable("ELYSIUM_PASSPHRASE", [System.EnvironmentVariableTarget]::User) # never in plaintext, so it's only prompted for once per user/machine and never echoed to the console.
$storedPassphrase = [System.Environment]::GetEnvironmentVariable("ELYSIUM_PASSPHRASE", [System.EnvironmentVariableTarget]::User)
if ([string]::IsNullOrEmpty($passphrase)) { $havePassphrase = $false
Write-Host "No passphrase found in environment variables." if (-not [string]::IsNullOrEmpty($storedPassphrase)) {
$passphrase = Read-Host "Please enter your passphrase." try {
# Here you could choose to set the environment variable or simply use the passphrase for the current session [void](ConvertTo-SecureString -String $storedPassphrase -ErrorAction Stop)
[System.Environment]::SetEnvironmentVariable("ELYSIUM_PASSPHRASE", $passphrase, [System.EnvironmentVariableTarget]::User) $havePassphrase = $true
Write-Host "Passphrase stored as environment variable 'ELYSIUM_PASSPHRASE'."
} else {
Write-Host "Passphrase found in environment variables." Write-Host "Passphrase found in environment variables."
} catch {
Write-Warning "Stored passphrase is not in the expected protected format (leftover from an older Elysium version?). Re-enter it."
}
}
if (-not $havePassphrase) {
Write-Host "No passphrase found in environment variables."
$securePassphrase = Read-Host "Please enter your passphrase" -AsSecureString
[System.Environment]::SetEnvironmentVariable("ELYSIUM_PASSPHRASE", (ConvertFrom-SecureString -SecureString $securePassphrase), [System.EnvironmentVariableTarget]::User)
Write-Host "Passphrase stored (DPAPI-protected) as environment variable 'ELYSIUM_PASSPHRASE'."
} }
function Start-OrchestratorTranscript { function Start-OrchestratorTranscript {
+9 -3
View File
@@ -190,9 +190,15 @@ try {
try { $s3ForcePathStyle = [System.Convert]::ToBoolean($s3ForcePathStyle) } catch { $s3ForcePathStyle = $true } try { $s3ForcePathStyle = [System.Convert]::ToBoolean($s3ForcePathStyle) } catch { $s3ForcePathStyle = $true }
try { $s3UseAwsTools = [System.Convert]::ToBoolean($s3UseAwsTools) } catch { $s3UseAwsTools = $false } try { $s3UseAwsTools = [System.Convert]::ToBoolean($s3UseAwsTools) } catch { $s3UseAwsTools = $false }
# Retrieve the passphrase from a user environment variable # Retrieve the DPAPI-protected passphrase from a user environment variable (see Elysium.ps1)
$passphrase = [System.Environment]::GetEnvironmentVariable("ELYSIUM_PASSPHRASE", [System.EnvironmentVariableTarget]::User) $protectedPassphrase = [System.Environment]::GetEnvironmentVariable("ELYSIUM_PASSPHRASE", [System.EnvironmentVariableTarget]::User)
if ([string]::IsNullOrWhiteSpace($passphrase)) { throw 'Passphrase not found in ELYSIUM_PASSPHRASE environment variable.' } if ([string]::IsNullOrWhiteSpace($protectedPassphrase)) { throw 'Passphrase not found in ELYSIUM_PASSPHRASE environment variable. Run Elysium.ps1 once to set it.' }
try {
$securePassphrase = ConvertTo-SecureString -String $protectedPassphrase -ErrorAction Stop
} catch {
throw "ELYSIUM_PASSPHRASE is not in the expected DPAPI-protected format (leftover from an older Elysium version?). Re-run Elysium.ps1 to re-enter it."
}
$passphrase = [System.Net.NetworkCredential]::new('', $securePassphrase).Password
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $timestamp = Get-Date -Format "yyyyMMdd-HHmmss"