noid-privacy/Modules/AdvancedSecurity/Private/Test-WDigest.ps1

130 lines
5.2 KiB
PowerShell

function Test-WDigest {
<#
.SYNOPSIS
Test WDigest credential protection compliance
.DESCRIPTION
Verifies that WDigest is configured to NOT store plaintext credentials in LSASS memory.
Checks the UseLogonCredential registry value.
Expected: UseLogonCredential = 0 (Secure)
Insecure: UseLogonCredential = 1 (Plaintext credentials in memory!)
.EXAMPLE
Test-WDigest
Returns compliance status for WDigest protection
.OUTPUTS
PSCustomObject with compliance details
#>
[CmdletBinding()]
param()
try {
$wdigestRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest"
$result = [PSCustomObject]@{
Feature = "WDigest Protection"
Status = "Unknown"
Details = @()
UseLogonCredential = $null
Compliant = $false
Windows_Version = ""
Deprecated = $false
}
# Get Windows version
$osVersion = [System.Environment]::OSVersion.Version
$isWin11 = $osVersion.Major -ge 10 -and $osVersion.Build -ge 22000
$isWin11_24H2Plus = $isWin11 -and $osVersion.Build -ge 26100
if ($isWin11) {
$result.Windows_Version = "Windows 11 (Build $($osVersion.Build))"
if ($isWin11_24H2Plus) {
$result.Deprecated = $true
$result.Details += "Windows 11 24H2+ detected - WDigest setting is deprecated"
}
}
elseif ($osVersion.Major -eq 10) {
$result.Windows_Version = "Windows 10 (Build $($osVersion.Build))"
}
else {
$result.Windows_Version = "Windows $($osVersion.Major).$($osVersion.Minor) (Build $($osVersion.Build))"
}
# Check registry value
if (Test-Path $wdigestRegPath) {
$useLogonCred = (Get-ItemProperty -Path $wdigestRegPath -Name "UseLogonCredential" -ErrorAction SilentlyContinue).UseLogonCredential
if ($null -ne $useLogonCred) {
$result.UseLogonCredential = $useLogonCred
if ($useLogonCred -eq 0) {
$result.Status = "Secure"
$result.Compliant = $true
$result.Details += "UseLogonCredential = 0 (Plaintext credentials NOT stored)"
if ($result.Deprecated) {
$result.Details += "Note: Setting is deprecated but explicitly configured for backwards compatibility"
}
}
elseif ($useLogonCred -eq 1) {
$result.Status = "INSECURE!"
$result.Compliant = $false
$result.Details += "WARNING: UseLogonCredential = 1 (Plaintext credentials IN MEMORY!)"
$result.Details += "VULNERABLE to Mimikatz, WCE, and other credential dumping tools!"
}
else {
$result.Status = "Unknown Value"
$result.Compliant = $false
$result.Details += "UseLogonCredential = $useLogonCred (Unknown value)"
}
}
else {
# Value not set - default depends on OS version
if ($osVersion.Major -eq 6 -and $osVersion.Minor -le 2) {
# Windows 7/8 - default is 1 (INSECURE!)
$result.Status = "Insecure (Default)"
$result.Compliant = $false
$result.Details += "UseLogonCredential not set - Windows 7/8 default is 1 (INSECURE!)"
}
else {
# Windows 8.1+ - default is 0 (Secure)
$result.Status = "Secure (Default)"
$result.Compliant = $true
$result.Details += "UseLogonCredential not set - Windows 8.1+ default is 0 (Secure)"
if ($result.Deprecated) {
$result.Details += "Windows 11 24H2+: Setting is hardcoded secure (deprecated)"
}
}
}
}
else {
# Registry path doesn't exist
if ($osVersion.Major -eq 6 -and $osVersion.Minor -le 2) {
# Windows 7/8
$result.Status = "Insecure (No Config)"
$result.Compliant = $false
$result.Details += "WDigest registry path not found - Windows 7/8 default is INSECURE!"
}
else {
# Windows 8.1+
$result.Status = "Secure (Default)"
$result.Compliant = $true
$result.Details += "WDigest registry path not found - Windows 8.1+ default is secure"
}
}
return $result
}
catch {
Write-Log -Level ERROR -Message "Failed to test WDigest protection: $_" -Module "AdvancedSecurity" -Exception $_.Exception
return [PSCustomObject]@{
Feature = "WDigest Protection"
Status = "Error"
Details = @("Failed to test: $_")
Compliant = $false
}
}
}