[REQ-END-167] Account Policy: Cached Logons and PBKDF2 Iteration Count for Endpoints

Target Scope

  • Applicable Systems: Tier 2 Client Workstations and Member Servers.
  • Operating Systems: Windows 10 Enterprise/Professional (1809 and above), Windows 11 Enterprise/Professional (all builds), Windows Server 2016 (and above).

Implementation Details


Rationale

When domain users authenticate against Windows workstations, the operating system can cache authentication verifiers locally to permit subsequent logons if an Active Directory Domain Controller is unreachable. Hardening this mechanism limits local credential exposure and renders offline attacks computationally unfeasible:

Technical Threat Vectors and Defense Mechanics

  1. DCC2 / MSCacheV2 Storage Mechanism: Domain credential caches are stored in the local registry at HKLM\SECURITY\Cache as MSCacheV2 / DCC2 records. These verifiers are generated by executing PBKDF2-HMAC-SHA1 hashing over the user's NTLM password hash concatenated with their lowercase username. If an attacker dumps the local SECURITY and SYSTEM registry hives (via tools like Mimikatz, Volume Shadow Copies, or offline disk mounts), they can extract these hashes for offline brute-force cracking.
  2. Preventing Credential Accumulation (CachedLogonsCount = 0): In enterprise desktop environments and stationary member servers, systems always possess network connectivity to Active Directory Domain Controllers. Disabling logon caching (CachedLogonsCount = 0) instructs Winlogon to never write credential verifiers to the registry. When multiple users or support personnel log into a shared workstation, no password hashes remain behind on disk.
  3. Hardening Roaming Field Laptops (NL$IterationCount = 1954): In organizations with mobile workforces where laptops frequently operate away from corporate networks and VPNs, disabling caching completely can cause business interruption. For such roaming assets, caching may be capped at a strict minimum (1 or 2 entries), while simultaneously configuring NL$IterationCount = 1954. Standard Windows configurations use only 10,240 PBKDF2 derivation rounds, allowing GPU cracking arrays to test millions of passwords per second. Because Windows calculates total iterations using the formula (NL$IterationCount + 1) * 1024, setting the value to 1954 increases derivation rounds to 2,001,920 (over 2 million iterations). This ~200x increase dramatically reduces cracking speed, neutralizing automated dictionary and brute-force tools.
  4. Baseline Comparison (Endpoint vs PAW): Tier 0 PAWs strictly require CachedLogonsCount = 0 with zero exceptions due to the catastrophic risk of compromising directory administrative hashes. Standard Tier 2 endpoints enforce 0 by default on fixed workstations and member servers, while leveraging the fortified 1954 iteration count alongside full-disk BitLocker encryption on portable laptops.

Legacy Impact & Compatibility

  • Offline Authentication on Disconnected Laptops: If CachedLogonsCount is set to 0 on mobile laptops operating off-network, users cannot log on until they establish network connectivity to an Active Directory Domain Controller (e.g., via pre-logon Always-On VPN). Organizations deploying CachedLogonsCount = 0 globally must ensure pre-logon network tunnel capabilities exist.
  • CPU Overhead during Logon: Increasing NL$IterationCount to 1954 introduces a negligible processing delay (typically 50-150 milliseconds on modern multi-core processors) during offline authentication calculation, which is imperceptible to users.
  • SYSTEM Privilege Prerequisite: Setting NL$IterationCount requires modifying HKLM\SECURITY\Cache, which is ACLed exclusively to NT AUTHORITY\SYSTEM. Script deployment or Group Policy Preferences must execute in the computer (SYSTEM) context.

Implementation Steps

Option A: Group Policy Object (GPO) Configuration (Preferred)

  1. Open the Group Policy Management Console (gpmc.msc).
  2. Edit or create the target GPO (e.g., GPO_Hardening_Endpoints_Desktops).
  3. Navigate to: Computer Configuration\Policies\Windows Settings\Security Settings\Local Policies\Security Options
  4. Double-click Interactive logon: Number of previous logons to cache (in case domain controller is not available).
  5. Check Define this policy setting and set the cache value to 0 logons (or 2 for a dedicated roaming laptops OU).
  6. Navigate to: Computer Configuration\Preferences\Windows Settings\Registry
  7. Right-click Registry, select New -> Registry Item:
    • Action: Update
    • Hive: HKEY_LOCAL_MACHINE
    • Key Path: SECURITY\Cache
    • Value name: NL$IterationCount
    • Value type: REG_DWORD
    • Value data: 1954 (Decimal)
  8. Link the GPO to the appropriate workstation Organizational Units.

Option B: PowerShell & Registry Configuration (Remediation / Non-GPO)

Download Script: Configure-EndAccountCachedLogons.ps1

# Configure-EndAccountCachedLogons.ps1
# Description: Disables cached domain logons and fortifies PBKDF2 iteration count on Endpoints.

Write-Host "Configuring Endpoint cached logon restrictions and PBKDF2 iterations..." -ForegroundColor Cyan

# 1. Disable cached logons count
$WinlogonPath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
if (-not (Test-Path $WinlogonPath)) {
    New-Item -Path $WinlogonPath -Force | Out-Null
}
Set-ItemProperty -Path $WinlogonPath -Name "CachedLogonsCount" -Value 0 -Type DWord -Force

# 2. Configure PBKDF2 Iteration Count
$CachePath = "HKLM:\SECURITY\Cache"
if (-not (Test-Path $CachePath)) {
    New-Item -Path $CachePath -Force | Out-Null
}
Set-ItemProperty -Path $CachePath -Name "NL`$IterationCount" -Value 1954 -Type DWord -Force

Write-Host "Cached logons count disabled (0) and PBKDF2 iteration count configured (1954)." -ForegroundColor Green

To audit the hardening status:

Download Script: Get-EndAccountCachedLogonsStatus.ps1

# Get-EndAccountCachedLogonsStatus.ps1
# Description: Audits cached logons count and PBKDF2 iteration count on Endpoints.

Write-Host "--- Auditing Endpoint Cached Logons and PBKDF2 Settings ---" -ForegroundColor Cyan
$script:Vulnerable = $false

# 1. Audit CachedLogonsCount
$WinlogonPath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
if (-not (Test-Path $WinlogonPath)) {
    Write-Host "    [!] MISSING KEY: $WinlogonPath" -ForegroundColor Red
    $script:Vulnerable = $true
} else {
    $CacheCount = (Get-ItemProperty -Path $WinlogonPath -Name "CachedLogonsCount" -ErrorAction SilentlyContinue).CachedLogonsCount
    if ($CacheCount -ne 0) {
        Write-Host "    [!] VULNERABLE: CachedLogonsCount is '$CacheCount' (Expected: 0)" -ForegroundColor Red
        $script:Vulnerable = $true
    } else {
        Write-Host "    [+] CachedLogonsCount: 0 (Secure - Cache Disabled)" -ForegroundColor Green
    }
}

# 2. Audit NL$IterationCount
$CachePath = "HKLM:\SECURITY\Cache"
if (-not (Test-Path $CachePath)) {
    Write-Host "    [!] MISSING KEY: $CachePath" -ForegroundColor Red
    $script:Vulnerable = $true
} else {
    $IterCount = (Get-ItemProperty -Path $CachePath -Name "NL`$IterationCount" -ErrorAction SilentlyContinue)."NL`$IterationCount"
    if ($IterCount -ne 1954) {
        Write-Host "    [!] VULNERABLE: NL`$IterationCount is '$IterCount' (Expected: 1954)" -ForegroundColor Red
        $script:Vulnerable = $true
    } else {
        Write-Host "    [+] NL`$IterationCount: 1954 (Secure - ~2M PBKDF2 Iterations)" -ForegroundColor Green
    }
}

if ($script:Vulnerable) {
    Write-Output "Non-Compliant"
    exit 1
} else {
    Write-Output "Compliant"
    exit 0
}

Option C: Manual Verification

Verify the applied registry configuration using command line queries:

reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v CachedLogonsCount

Confirm that CachedLogonsCount returns 0x0.

To inspect the SECURITY\Cache key (using elevated command prompt via psexec -s cmd.exe):

reg query "HKLM\SECURITY\Cache" /v NL$IterationCount

Confirm that NL$IterationCount returns 0x7a2 (Decimal 1954).


Sources & Compliance References

  • CIS Microsoft Windows 10 Enterprise Benchmark: Section 2.3.9.4 (Ensure 'Interactive logon: Number of previous logons to cache' is set to '0' logons)
  • CIS Microsoft Windows 11 Enterprise Benchmark: Section 2.3.9.4 (Ensure 'Interactive logon: Number of previous logons to cache' is set to '0' logons)
  • CIS Microsoft Windows Server 2022 Benchmark: Section 2.3.9.4 (Ensure 'Interactive logon: Number of previous logons to cache' is set to '0' logons)
  • DoD Windows 11 Computer STIG: Rule SV-220721r879621_rule (Setting cached domain logons to 0)
  • ANSSI Active Directory Hardening Guide: Recommendations on local credential caching and LSASS offline protection
  • MITRE ATT&CK: T1003.005: Cached Domain Credentials
  • Related Controls: REQ-PAW-156: Account Policy: Cached Logons and PBKDF2 Iteration Count for PAWs, REQ-END-163: Account Policy: Password Policy for Endpoints

results matching ""

    No results matching ""