52 min read

Two Checkmarks and the Keys to the Kingdom: How Active Directory's Replication Protocol Became the Longest-Lived Credential Attack on Windows

MS-DRSR was designed for domain controllers to replicate secrets to each other. Its access check gates on an ACL, not on whether the caller is a DC. Eleven years after Mimikatz proved it, no patch can fix it.

Permalink

1. Two Checkmarks and the Keys to the Kingdom

A non-admin service account, created during a 2017 file-server migration and never cleaned up, holds exactly two access-control entries on the contoso.local domain object: Replicating Directory Changes and Replicating Directory Changes All. From a Windows 11 workstation -- not a domain controller, not a tier-zero admin host, just a desk -- the attacker opens a Mimikatz prompt and types:

lsadump::dcsync /domain:contoso.local /user:krbtgt

Sixty seconds later they have the krbtgt NT hash and Kerberos AES keys, and they own the domain. Credential Guard, enabled on every workstation in the building, never saw the credential transit anywhere in its scope.

That last sentence is the punchline of the entire field. The secret never touches the attacker's LSASS, so Credential Guard's design has nothing to say. The keys move from a remote domain controller's on-disk database, over an RPC channel, into the attacker's process memory. Credential Guard isolates LSASS on the local machine. It has no jurisdiction over what a remote DC chooses to send when asked nicely.

The 60-second timeline is not a marketing number. One RPC round trip per principal is the protocol's per-principal cost, fixed by specification. For a single high-value target -- and krbtgt is the highest-value target in any Active Directory forest, because its long-term key signs every Kerberos ticket -- the attack is over before a typical SOC operator has finished pouring coffee.

The four people whose names recur in this story are worth meeting now. Benjamin Delpy (gentilkiwi) wrote Mimikatz and authored both the DCSync read primitive (2015) and, with Vincent Le Toux, the DCShadow write primitive (2018). Vincent Le Toux built the original DCShadow implementation and the PingCastle posture-assessment tool. Sean Metcalf (Trimarc / ADSecurity) translated DCSync into operator vocabulary in the weeks after its release. Microsoft's Defender for Identity team ships the canonical first-party detections that fire on this attack class today.

This story is what happens when a 23-year-old domain-controller-to-domain-controller protocol's access check turns out to gate on an ACL, not on whether the caller is a domain controller. Two ACEs on one object should not give an attacker the entire credential trove. The fact that they do is not a bug in the implementation. It is a 1999 design assumption -- that nobody who is not a DC would ever speak this protocol -- that survived twenty-five years as a social convention and was nowhere written down in the access-check code.

The next section explains why Microsoft built this protocol in the first place, and why its access check forgot to ask the one question that would have closed the loophole.

2. Why the Protocol Exists at All

Rewind to February 17, 2000. Microsoft ships Windows 2000 Server, and Active Directory replaces the old NT 4.0 PDC/BDC model [2]. NT 4.0 was single-master: one Primary Domain Controller held the authoritative account database, every Backup Domain Controller held a read-only copy, and a password change on the PDC propagated to BDCs through a hub-and-spoke replication channel. AD inverts the model. Every domain controller in an AD domain holds a writable copy of the directory; a password change on any DC must propagate to every other DC within minutes; the replication topology is a mesh, not a star.

Multi-master replication is the design constraint that forces MS-DRSR's existence. If any DC can accept a write, then every DC must be able to pull every change -- including secret attributes like unicodePwd, dBCSPwd, ntPwdHistory, lmPwdHistory, and supplementalCredentials -- from every other DC. There is no second protocol. Replication of secrets is replication, and replication is MS-DRSR [3].

MS-DRSR (Directory Replication Service Remote Protocol)

The RPC protocol by which any Active Directory domain controller can replicate any object, including secret attributes, from any other DC in the same forest. Layered over DCE/RPC; the current public specification is revision 46.0 dated March 9, 2026 [3]. MS-DRSR is the mechanism that makes AD's multi-master replication invariant work.

IDL_DRSGetNCChanges

The MS-DRSR method (opnum 3) that returns changed objects within a naming context. A calling DC supplies a target DN and a set of replication flags; the called DC returns the object's attribute values, with secret attributes encrypted under a session-derived key. This is the protocol method that DCSync invokes.

Ctrl + scroll to zoom
MS-DRSR's place in the AD multi-master replication model: every DC pulls every change, including secret attributes, from every peer DC over IDL_DRSGetNCChanges.

The access check that gates IDL_DRSGetNCChanges is defined in [MS-DRSR] §4.1.10. It asks one question: does the calling principal hold the appropriate extended rights on the naming-context root being replicated? Extended rights are AD's mechanism for control-access permissions that do not fit into the standard ACL bit set [3].

Extended Right

A schema-defined access-control right identified by a GUID rather than by a standard ACL bit. Extended rights are granted via an access-control entry on a target object and checked at runtime by the operation that requires them. The three replication extended rights are the canonical example: each is identified only by GUID, and each is checked by IDL_DRSGetNCChanges against the caller's effective rights on the naming-context root.

Naming Context (NC)

A top-level replication partition of the Active Directory database. Every AD forest has at least three NCs: the Schema NC, the Configuration NC, and one Domain NC per domain (plus optional Application NCs). DCSync operates against the Domain NC root.

Three extended rights together form what practitioners call the rights triad. The two-checkmark version from §1 is the most-common configuration; the third right unlocks a smaller set of attributes flagged confidential. Microsoft's own AD schema documentation enumerates each one [4][5][6]:

Rights Triad

The combination of three replication extended rights on a naming-context root: DS-Replication-Get-Changes (the baseline read), DS-Replication-Get-Changes-All (unlocks secret attributes), and DS-Replication-Get-Changes-In-Filtered-Set (unlocks attributes with the confidential flag). The first two are what most operators mean when they say "DCSync rights"; the third is sometimes required for completeness.

RightDisplay nameRights-GUIDWhat it unlocksIntroduced
DS-Replication-Get-ChangesReplicating Directory Changes1131f6aa-9c07-11d1-f79f-00c04fc2dcd2Baseline replication readWindows 2000 Server [4]
DS-Replication-Get-Changes-AllReplicating Directory Changes All1131f6ad-9c07-11d1-f79f-00c04fc2dcd2Secret attribute replication (unicodePwd, ntPwdHistory, etc.) [5]Windows Server 2003
DS-Replication-Get-Changes-In-Filtered-SetReplicating Directory Changes In Filtered Set89e95b76-444d-4c62-991a-0facbeda640cConfidential-flag attributes [6]Windows Server 2008

In a freshly-installed AD domain, four principal sets hold the rights triad by default on the Domain NC root: the Domain Controllers group, the Domain Admins group, the Enterprise Admins group, and the built-in Administrators group [7]. Every other ACE on that object is a deliberate delegation choice made by some operator at some point in the domain's history.

Now read the access check carefully. It asks whether the caller holds the rights. It does not ask anything about who the caller is. The protocol does not check whether the caller's Service Principal Name is GC/... or ldap/... or anything else. It does not check whether the caller's machine account is in the Domain Controllers group. It does not check whether the caller's Kerberos service ticket was issued for a DC service. The whole gate is the ACL on one object.

This is the most consequential design omission in any Microsoft network protocol. Every other replication-style protocol in Windows ships some form of caller-machine-identity assertion. MS-DRSR shipped without one because, in 1999, nobody on the design team imagined an unprivileged workstation would speak the DC-to-DC protocol.

The 1999 closed-population design assumption is the load-bearing fiction underneath this whole story. The protocol's designers assumed -- entirely reasonably for the deployment universe of that decade -- that the only software that would ever implement an MS-DRSR client was the DC role itself, which Microsoft shipped, signed, and audited. No defender in 1999 was thinking about a Python script speaking DRSUAPI from a desk. The assumption was a social convention dressed as a security model, and it survived for fifteen years.

If the protocol exists to replicate every secret in the directory, and the access check is the ACL on one object, what stopped anyone from abusing it for the protocol's first fifteen years? That accidental safety period is the subject of the next section.

3. The Fifteen-Year Accidental Safety Period

Between 2000 and 2015, attackers who wanted the entire credential trove of an Active Directory domain had exactly one road open to them: reach a domain controller and steal its database. The reasons are not subtle. The credentials lived in one file -- C:\Windows\NTDS\NTDS.dit, an Extensible Storage Engine database protected by a Password Encryption Key wrapped under the BootKey scattered across four registry values in the SYSTEM hive [8]. Without code execution on a DC, there was no obvious way to ask the directory for its secrets in bulk.

NTDS.dit

The on-disk Extensible Storage Engine ("Jet Blue") database that holds every Active Directory object, including secret attributes. Located at C:\Windows\NTDS\NTDS.dit on every domain controller. The file is locked while AD DS is running; offline copying requires either Volume Shadow Copy snapshots, ntdsutil ifm bundling, or DC downtime [9].

Three sub-techniques bloomed inside this constraint, and MITRE catalogs them collectively as T1003.003 OS Credential Dumping: NTDS [9]. Each is operationally distinct, and each requires the same precondition.

G1a -- Volume Shadow Copy plus offline parse. The attacker runs vssadmin create shadow /for=C: on a domain controller, creating an instant point-in-time snapshot. They copy NTDS.dit and SYSTEM out of the shadow path, exfiltrate both files, and parse them offline with Csaba Barta's ntdsxtract toolkit [8] or Impacket's secretsdump.py running in offline mode. The parse walks the datatable ESE table row by row, decrypts the PEK with the BootKey, and decrypts each principal's secret attributes with the PEK.

G1b -- ntdsutil Install From Media. The built-in command ntdsutil "activate instance ntds" "ifm" "create full C:\Temp\IFM" packages NTDS.dit and the SYSTEM hive into a clean bundle, intended for legitimate seeding of a new replica DC. With local admin on any DC, an attacker invokes it without involving VSS.

G1c -- LSASS injection of the long-term DC secrets. Mimikatz's pre-DCSync technique reads cached long-term secret material (including the krbtgt key) directly out of lsass.exe memory on a domain controller via lsadump::lsa /inject /name:krbtgt. The variant that turned this surface into a persistence implant was Skeleton Key, disclosed by the Dell SecureWorks Counter Threat Unit on January 12, 2015 [10]. Skeleton Key patches the NTLM and Kerberos validation routines in LSASS on a DC so that a single master password works for any account.

Skeleton Key sits at the boundary between credential dumping and persistence. It does not produce usable NT hashes or Kerberos keys for offline forging; it gives the attacker a backdoor at the authentication step. The 2015 community debate over Skeleton Key versus the (then-imminent) DCSync technique was settled decisively by DCSync's August release: dumping the hashes is more useful than backdooring the auth path, because dumped hashes survive a DC reboot and are forge-ready material [10].
Sub-techniqueMechanismCanonical toolEmitted artifactHost artifact on DC
G1a VSS + offline parsePoint-in-time snapshot, file copy, offline ESE parsevssadmin + secretsdump.py / ntdsxtractNT hashes, Kerberos keys, password historyVSS event in system log
G1b ntdsutil IFMBuilt-in admin command produces clean bundlentdsutil "ac i ntds" "ifm"Identical to G1aIFM staging directory
G1c LSASS injectRead long-term secrets from lsass.exe memorymimikatz lsadump::lsa /injectkrbtgt key and other LSA-cached secretsProcess access of lsass.exe

The structural cost across all three is the same: code execution as SYSTEM on a domain controller. Read that requirement slowly. In a mature enterprise with even a basic tiered-administration model -- no interactive logon to DCs from workstations, restricted-admin RDP, Privileged Access Workstations for Domain Admin sessions, Protected Users group membership for Tier Zero principals -- DCs are the most defended boundary in the network. An attacker who has crossed that boundary has, in operational terms, already won. The credential dump is the trophy lap.

Ctrl + scroll to zoom
Generation 1's three roads to credential extraction. All three converge on the same precondition: SYSTEM-level code execution on a domain controller.

This is what made the closed-population design assumption survive its first fifteen years. The protocol's design was open to abuse from any joined workstation that held the rights triad, but nobody noticed because the cheaper attack road -- compromise a DC, parse the database offline -- still passed through a defended chokepoint. The ACL on the Domain NC was nowhere on a defender's risk register, because no offensive tooling existed that treated the ACL as the gate.

There was a question waiting to be asked, though. What if you could ask the DC to send you the credentials, using a protocol the DC already speaks fluently with its peers? The protocol's wire format is published. Microsoft Learn hosts the IDL. The DCs trust each other's calls by ACL. The only missing piece was a client implementation that any attacker could run from any joined machine.

In August 2015 the missing piece arrived.

4. Generation by Generation

August 11, 2015, 01:27 Central European Time. Benjamin Delpy commits 47,132 insertions to the Mimikatz repository in a single push titled "DCSync in mimikatz & for XP/2003." The diff introduces four new modules -- kull_m_rpc_drsr.c/.h and kull_m_rpc_ms-drsr.h/_c.c -- generated from the [MS-DRSR] IDL. They are an MS-DRSR client surface, slotted into kuhl_m_lsadump.c as the new lsadump::dcsync command [11][12]. Vincent Le Toux is credited as co-author.

Six weeks later Sean Metcalf writes the canonical operator post and presents the technique at DerbyCon V on Friday, September 25, 2015, in the Track 1 (Break Me) slot from 3:00 to 3:50 pm [7][13]. The closed-population assumption shatters in a weekend.

What follows is the story of four generations of attacker approaches against this protocol, each motivated by the operational limit of the previous one.

Generation 2: DCSync (2015-08-11 onward)

Mimikatz becomes a DRSUAPI client. Operator invocation is one line:

lsadump::dcsync /domain:contoso.local /user:krbtgt

Behind that line, six wire steps fire:

Ctrl + scroll to zoom
DCSync on the wire: the six-step IDL_DRSGetNCChanges round trip. The attacker binds to the target DC's DRSUAPI endpoint, requests one principal, decrypts the reply with the session-derived key, and emits a hash record.

The wire format is one round trip per principal. To dump every account in the domain, Mimikatz's /all /csv mode iterates the request server-side via the same opnum with paginating up-to-date vectors. Per-call wire size is a few kilobytes for a single user; full-domain bulk dumps run to tens of megabytes. Wall-clock time is dominated by network latency to the target DC [7][14].

The Generation-1 precondition is gone. The attack runs from any joined workstation. The Generation-1 host artifacts -- VSS events, IFM staging directories, multi-megabyte file copies -- all disappear. The only on-the-wire signature is "an IDL_DRSGetNCChanges call from an IP that is not a domain controller" -- which has to be detected at the protocol layer, not the host layer.

Sean Metcalf's 2015 post named the detection recipe in the same breath as the attack: "Configure IDS to trigger if DsGetNCChange request originates an IP not on the 'Replication Allow List' ..." [7]. Every network detection rule in this space, including Microsoft's own ATA "Unusual Protocol Implementation" category two years later, descends from that one sentence [15].

DCSync is read-only. The ACL pair the attack exploits does not include directory-write rights. An attacker who wants to plant SID-history backdoors, modify userAccountControl flags, or write to AdminSDHolder needs a different primitive. The same trust loophole that gave them read access turns out to support a symmetric write side.

Generation 3: DCShadow (2018-01-24)

January 23-24, 2018. Benjamin Delpy and Vincent Le Toux present at BlueHat IL in Tel Aviv. The talk is titled "Active Directory: What can make your million dollar SIEM go blind?" [16]. Four days later, on January 27, 2018, Delpy pushes the mainline merge to Mimikatz with commit ab18bd1, subject "Pushing @vletoux DCShadow in current branch with some adaptations" [17].

Vincent Le Toux contributed the original implementation; the BlueHat IL talk shared joint Delpy/Le Toux billing; the Mimikatz mainline merge commit ab18bd103a5cd7e26fb8d475c5ea0157d6633ca9 is dated 2018-01-27 01:37:55 +0100, four days after the conference disclosure. Le Toux is the same author behind PingCastle's posture-assessment tooling and the canonical dcshadow.com reference site [17][18].

DCShadow inverts DCSync. Where DCSync makes the attacker a DRSUAPI client, DCShadow makes the attacker a DRSUAPI server. The mechanism: temporarily register an nTDSDSA object plus the associated SPNs in the Configuration NC; signal to a legitimate DC that the new "DC" wants to push changes via IDL_DRSReplicaAdd followed by IDL_DRSReplicaSync; the legitimate DC pulls the attacker's pre-staged writes through the replication channel as if they were legitimate peer replication; deregister to clean up [19][18].

Ctrl + scroll to zoom
DCShadow: register, replicate, deregister. The attacker temporarily becomes a DC in the Configuration NC, pushes arbitrary writes through the replication channel that the directory's audit subsystem ignores by design, and removes the rogue registration afterwards.
SACL-silent

A directory operation that does not generate the standard Event ID 4662 / 4738 / 5136 object-modification events that the Domain Services Auditing subsystem emits for normal writes. Legitimate DC-to-DC replication is SACL-silent by design -- the audit subsystem intentionally suppresses change events on the replication channel to avoid drowning every DC in audit traffic on every directory change. DCShadow writes are SACL-silent because they ride the same channel.

That last design fact is the entire point of the talk title. A SIEM watching object-modification events sees nothing when a DCShadow write lands, because the modifications arrive on the replication channel that the SIEM intentionally ignores as routine DC chatter. The original 2018 framing -- "your million-dollar SIEM goes blind" -- was correct for SIEMs that monitored only object-modification events. We will see in §6 how that framing has aged.

DCShadow is write capability. An attacker who reaches it can plant SID-history backdoors (write S-1-5-21-...-519 for Enterprise Admins into a low-privileged account's sIDHistory), modify userAccountControl to clear ACCOUNTDISABLE on dormant high-privilege accounts, add ACEs to AdminSDHolder (which then propagate via the SDProp process to every protected admin account every 60 minutes), or set msDS-AllowedToActOnBehalfOfOtherIdentity on a target computer to enable resource-based constrained delegation chains.

Generation 4: Permission-graph attacks (2018-present)

By 2018 the attack-side question had shifted. Holding the rights triad directly was no longer the interesting precondition; the interesting question was how to reach it transitively, through whatever chain of ACL delegations a real-world domain happened to contain. The umbrella term that emerged is permission-graph attack. Its terminal edge is still DCSync; its novelty is the path that gets you to the terminal.

Three primitives anchor this generation. Elad Shamir's Wagging the Dog (January 28, 2019) showed how writing msDS-AllowedToActOnBehalfOfOtherIdentity on a target computer object enables S4U2Self plus S4U2Proxy impersonation of any user to that computer [20]. Shamir's Shadow Credentials (June 21, 2021) demonstrated that writing msDS-KeyCredentialLink on a target account adds an attacker-controlled certificate trust, enabling Kerberos PKINIT authentication as that account without resetting its password [21]. And Sean Metcalf's earlier work on AdminSDHolder template abuse showed that writing the AdminSDHolder ACL causes SDProp to propagate the new ACL onto every protected admin account every 60 minutes -- self-healing persistence that survives defender cleanup [22].

The unifying observation: DCSync is a terminal in a permission graph. The graph's nodes are AD principals; its edges are individual access-control entries (WriteDACL, WriteOwner, GenericAll, WriteProperty, AddMember, ForceChangePassword). Whoever can traverse the graph to the rights triad on the domain root has DCSync transitively. The attacker's job is no longer to invoke IDL_DRSGetNCChanges; it is to find the shortest path through the graph from a foothold to the rights triad. The defender's mirror job is to enumerate all paths into the rights triad and either prune them or monitor them.

Ctrl + scroll to zoom
The replication attack class timeline, 2000-2026. Attacker generations are stacked above; major defender milestones are stacked below.

To make the read-side access check decision concrete -- and to expose how thin it actually is -- here is the logic of the gate written as a runnable function. This is pseudocode for the decision, not the protocol bytes:

JavaScript DCSync access check decision (illustrative simulation, not exploit code)
// Illustrative model of the MS-DRSR access check on IDL_DRSGetNCChanges.
// Returns "secrets returned" or "ACCESS_DENIED" given a caller's effective
// rights on the naming-context root.
function dcsyncAccessCheck(callerRights, ncRootDn, requestedAttrs) {
const GET_CHANGES         = '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2';
const GET_CHANGES_ALL     = '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2';
const GET_CHANGES_FILTERED = '89e95b76-444d-4c62-991a-0facbeda640c';

const SECRET_ATTRS = new Set(['unicodePwd', 'dBCSPwd',
  'ntPwdHistory', 'lmPwdHistory', 'supplementalCredentials']);
const wantsSecrets = requestedAttrs.some(a => SECRET_ATTRS.has(a));

// Baseline read requires GetChanges.
if (!callerRights.has(GET_CHANGES)) return 'ACCESS_DENIED';
// Secret attributes require GetChangesAll.
if (wantsSecrets && !callerRights.has(GET_CHANGES_ALL))
  return 'ACCESS_DENIED';

// Notice what is NOT checked: caller's SPN, machine-group membership,
// ticket service, source IP. The access gate is the ACL, full stop.
return 'secrets returned';
}

const attacker = new Set([
'1131f6aa-9c07-11d1-f79f-00c04fc2dcd2',
'1131f6ad-9c07-11d1-f79f-00c04fc2dcd2',
]);
console.log(dcsyncAccessCheck(attacker, 'DC=contoso,DC=local',
['unicodePwd', 'ntPwdHistory']));

Press Run to execute.

Four generations, eleven years, no Generation 5 in sight. What is the single insight that lets all of this exist, and why has nobody patched it?

5. There Is No DC Check

The whole structural error of this protocol is one missing question. Specification [MS-DRSR] §4.1.10 defines the access check on IDL_DRSGetNCChanges as: does the calling principal hold the rights triad on the naming context being replicated? [3] That is the whole gate. There is no second check that asks "is the caller's service principal name a domain-controller SPN?" or "is the caller's machine account in the Domain Controllers group?" or "was the caller's Kerberos service ticket issued for a DC service?" The spec is empirically and literally just an ACL check on the NC root.

The empirical proof that a non-DC client succeeds lives in Mimikatz's kuhl_m_lsadump.c and its DRSUAPI client surface in kull_m_rpc_drsr* [12]. Mimikatz is software running on a workstation. It binds to the DRSUAPI interface UUID, calls IDL_DRSGetNCChanges, and the call returns. The protocol's behavior is correct by specification. The security model is the bug.

"A major feature added to Mimkatz in August 2015 is 'DCSync' which effectively 'impersonates' a Domain Controller and requests account password data from the targeted Domain Controller. DCSync was written by Benjamin Delpy and Vincent Le Toux." -- Sean Metcalf, ADSecurity, September 2015 [7]

Read Metcalf's verb carefully: impersonates. The scare quotes are doing work. The Mimikatz client is not pretending to be a DC in any cryptographic sense. It is not forging a machine-account ticket. It is not spoofing an SPN. It is not bypassing any signature check.

It is honestly making an authenticated call as the principal it actually is -- some user or service account that happens to hold the rights triad -- and the protocol honestly responds because its gate is satisfied. The "impersonation" framing is operator vocabulary borrowed from the social model the protocol was written under.

The 1999 designers assumed only DCs would speak. By that social contract, anyone who speaks must be a DC. The spec encoded the social contract by way of not encoding it at all. The ACL was the whole gate because, in 1999, the ACL was always satisfied by something that was always a DC.

Ctrl + scroll to zoom
What the MS-DRSR access check asks (left branch) and what it does not ask (right branch, shown ghosted to emphasize structural absence).

This is the article's intellectual fulcrum. The 1999 closed-population assumption -- only DCs speak this protocol -- survives in 2026 as an open-population reality (anyone with the rights speaks it), and the closed-population assumption is nowhere written down in the access-check code. The fix that would close the model would require a second gate. The spec did not write one. The implementation cannot synthesize one without breaking every legitimate consumer that already operates without one (more on this in §8).

The protocol's design is correct. The security model is the bug. No patch can fix this without breaking Active Directory replication itself.

There is a temptation, on first encountering this, to assume the missing gate is an oversight that Microsoft will eventually fix. That intuition is wrong, and it is wrong for a deeper reason than "Microsoft has not gotten around to it." If the protocol is the bug and the protocol cannot be amended, what defenses can possibly work in 2026? That question carries us into the next section.

6. What 2026 Actually Ships Against This

If the protocol cannot be fixed, the defender's question is no longer "how do I prevent DCSync?" but "which layer catches which class of attempt?" Four production detection layers ship against this attack class in 2026. None of them is individually sufficient. A fifth layer -- the architectural one that would close the structural error -- does not exist and is not coming.

Posture: enumerate who holds the rights

The posture layer reads the static ACL on the Domain NC root and surfaces every principal that holds any of the three rights. Microsoft Defender for Identity ships this as an Accounts security posture assessment family, computed continuously from MDI's per-DC sensors [23]. Vincent Le Toux's PingCastle exposes it as the C-DCSync finding in its critical-risks section. Tenable Identity Exposure exposes it as an indicator of exposure. Christopher Keim's 2025 practitioner guide documents the PowerShell pattern that AD administrators without a posture-tool license can run on demand [24]:

Python Posture-layer inventory of rights-triad holders on a sample domain root ACL
# Illustrative model of the posture-layer check.
# In production, replace SAMPLE_ACL with output from Get-Acl in PowerShell
# or python-ldap against the live Domain NC root.

GET_CHANGES          = '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2'
GET_CHANGES_ALL      = '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'
GET_CHANGES_FILTERED = '89e95b76-444d-4c62-991a-0facbeda640c'
TRIAD = {GET_CHANGES, GET_CHANGES_ALL, GET_CHANGES_FILTERED}

DEFAULTS = {
  'BUILTIN\\Administrators',
  'CONTOSO\\Domain Controllers',
  'CONTOSO\\Domain Admins',
  'CONTOSO\\Enterprise Admins',
  'NT AUTHORITY\\ENTERPRISE DOMAIN CONTROLLERS',
}

SAMPLE_ACL = [
  {'principal': 'CONTOSO\\Domain Admins',     'right': GET_CHANGES},
  {'principal': 'CONTOSO\\Domain Admins',     'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\Enterprise Admins', 'right': GET_CHANGES},
  {'principal': 'CONTOSO\\Enterprise Admins', 'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\backup_svc_2017',   'right': GET_CHANGES},
  {'principal': 'CONTOSO\\backup_svc_2017',   'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\MSOL_a1b2c3',       'right': GET_CHANGES},
  {'principal': 'CONTOSO\\MSOL_a1b2c3',       'right': GET_CHANGES_ALL},
]

residual = {}
for ace in SAMPLE_ACL:
  if ace['right'] in TRIAD and ace['principal'] not in DEFAULTS:
      residual.setdefault(ace['principal'], set()).add(ace['right'])

for principal, rights in residual.items():
  print(f"{principal}: {len(rights)} of 3 replication rights")

Press Run to execute.

The residual set is the operational unit of work. In a freshly-installed domain it is empty. In a ten-year-old forest with a history of mergers and migrations it typically contains five to twenty entries -- a mix of legitimately delegated identity-sync products and forgotten service accounts from projects nobody on the current operations team remembers.

Tier Zero

In Microsoft's Enhanced Security Administrative Environment and the BloodHound conventions, the set of principals and assets whose compromise yields domain-wide control. The krbtgt account, members of Domain Admins and Enterprise Admins, the Entra ID Connect MSOL_ sync account, and any non-default principal holding the rights triad on the domain root are all Tier Zero by construction.

MSOL_ account

The Microsoft Entra ID (formerly Azure AD) Connect synchronization service account, created on-premises during Entra Connect installation. The account name uses an MSOL_ prefix followed by a hex suffix. It legitimately holds the rights triad on the Domain NC root because it must replicate password hashes to the cloud directory; treating it as Tier Zero is the standard hardening recommendation.

Replication Allow List

Microsoft Defender for Identity's (and ATA's earlier) internal baseline of which computers in the domain legitimately speak DRSUAPI to which DCs. Incoming IDL_DRSGetNCChanges requests are matched against this baseline; a request from a source outside the list fires the External ID 2006 alert.

An earlier scope document for this article quoted an MDI assessment titled verbatim "Remove non-admin accounts with DCSync permissions." That exact title does not appear on the live MDI Accounts security-posture-assessment page in 2026 [23][25]. The surface exists -- MDI's Accounts and Hybrid security posture-assessment families together cover non-default principals with replication rights -- but the verbatim title was not reproducible.

Behavioral: catch the act after it fires

The behavioral layer watches network traffic and event logs for the act of DCSync or DCShadow as it happens. Microsoft's first-party stack lives in Defender for Identity and ships three canonical alerts [26]:

  • External ID 2006 -- "Suspected DCSync attack (replication of directory services)." Credential Access (TA0006), Persistence (TA0003). Technique T1003.006. Severity High. Trigger: a replication request is initiated from a computer that is not a domain controller.
  • External ID 2028 -- "Suspected DCShadow attack (domain controller promotion)." Defense Evasion (TA0005). Technique T1207. Trigger: a machine in the network tries to register as a rogue domain controller.
  • External ID 2029 -- "Suspected DCShadow attack (domain controller replication request)." Defense Evasion (TA0005). Technique T1207. Trigger: a suspicious replication request is generated against a genuine domain controller, indicative of DCShadow.

The product lineage is Microsoft Advanced Threat Analytics 1.7 (April 2017, where DCSync was covered under the umbrella "Unusual Protocol Implementation enhancements" detection category [15]); Azure Advanced Threat Protection (2018, where Tali Ash's July 24, 2018 Microsoft Tech Community post announced the two named DCShadow detections that became 2028 and 2029 [27]); and Defender for Identity (the Microsoft Ignite 2020 rebrand, week of September 22-24, 2020 [28]). The detection content carries forward unchanged across product renamings; what changes is the portal it surfaces in [29].

Open-source SIEM equivalents implement the same detection via Event ID 4662 on the domain object. The Sigma rule Mimikatz DC Sync (id 611eab06-a145-4dfa-a295-3ccc5c20f59a) fires on Event ID 4662 where Properties contains any of the three rights GUIDs or the literal string Replicating Directory Changes All, with AccessMask=0x100 [30]. Splunk's parallel detection Windows AD Replication Request Initiated by User Account (rule 51307514-1236-49f6-8686-d46d93cc2821) implements the equivalent SPL search with the same MITRE T1003.006 annotation and the same known-false-positive list (Azure AD Connect, dcdiag.exe /Test:Replications) [31].

The SACL-event detection layer (Sigma + Splunk + every other SIEM-side implementation) requires that the operator first enable Advanced Security Audit policy Audit Directory Services Access under DS Access, with SACLs on the domain root auditing the three rights against Everyone, Domain Computers, and Domain Controllers. A fresh-install AD does not have these SACLs by default [31]. The detection rule's documentation calls out the prerequisite explicitly; many operators discover it only after wondering why their Splunk dashboard is silent.

Network: NDR on the DRSUAPI interface

The network layer parses DCE/RPC traffic on the wire, identifies the DRSUAPI interface by its UUID, and fires when an IDL_DRSGetNCChanges call originates from a source outside the legitimate-DC baseline. The canonical 2025 reference is Trellix Advanced Research Center's "Silent Domain Hijack: Uncovering the DCSync Attack and Detecting with Trellix NDR", published in week 50 of 2025 [14]. Equivalent capability ships in Microsoft Defender for Identity's network analytics layer (the same sensor that powers External ID 2006) [26].

The Trellix writeup is explicit about the architecture: "Trellix NDR detects replication protocol abuse by analyzing abnormal DCE/RPC and MS-DRSR traffic. It detects DCSync-like behavior when replication requests are sent from non-DC hosts or unusual users" [14]. The detection is independent of host-side telemetry, so it survives EDR tampering and works in environments where a DC is un-sensored from MDI's perspective.

Graph: BloodHound traverses the permission graph

The graph layer was built specifically for Generation 4. BloodHound, originally released by Andy Robbins, Rohan Vazarkar, and Will Schroeder at DEF CON 24 on August 6, 2016, models "you have DCSync rights to the domain" as a directed edge from a principal to the domain node, computed by combining the separately-collected GetChanges and GetChangesAll ACEs through nested-group membership [32][33][34]. An operator queries "shortest path from any compromised principal to the DCSync edge into a Domain node" and gets back every transitive route into the rights triad.

The 2024-2026 release cadence is dense and matters:

  • BloodHound v6.0 (September 30, 2024) improved logic for identifying and creating complex edges requiring multiple permissions, including DCSync, when Authenticated Users or Everyone groups are involved [35]. This closed a long-standing blind spot in which rights granted to a wildcard principal (the worst kind of delegation drift, often dating from compatibility settings in pre-2003 forests) were not surfaced as DCSync edges.
  • BloodHound v6.3 (December 9, 2024) introduced the Butterfly algorithm -- bi-directional risk analysis. Where the historical query was "which principals can attack this target?", Butterfly adds "which targets can be attacked from this compromised principal?" SpecterOps describes the algorithm in their blog post Unwrapping BloodHound v6.3 with Impact Analysis: "This is a massive upgrade to BloodHound Enterprise's risk analysis capability with a new algorithm we call 'Butterfly'" [36][37].
  • BloodHound v8.0 (July 29, 2025) introduced OpenGraph, generalizing the graph engine to model attack paths across non-AD systems (GitHub, 1Password, NPM, Snowflake) using the same Cypher front-end. The DCSync edge remains AD-specific; OpenGraph's relevance is that hybrid-cloud principals can now be modeled end-to-end [38].

The graph layer is the only one that catches multi-hop chains to the rights triad. A principal A with GenericAll on group B, where B has the DCSync triad, is invisible to MDI's posture assessment but stands out as a one-hop path in BloodHound.

Ctrl + scroll to zoom
The four-layer defense architecture. Each layer takes different inputs, detects a different slice of the attack surface, and feeds a unified SOC alert queue.

The full layer-by-layer comparison is the load-bearing matrix of the entire 2026 SOTA:

LayerWhat it inputsWhat it detectsWhat it missesFalse-positive classDetection latencyCost
PostureNC-root ACLDirect grant of the rights triad to a non-default principalMulti-hop transitive paths; legitimate-principal abuseIdentity-sync products (Entra Connect MSOL_, third-party HR-IDM); legitimately delegated backup agents24h score recomputation; ACE changes near real timeBuilt in to MDI; PowerShell variant free
BehavioralEvent ID 4662 or sensor-captured DRSUAPI trafficThe act of DCSync, or the DCShadow registration / replication, after it happensPre-attack staging; compromised-DC speaker; un-sensored DC blind spotAzure AD Connect syncs; dcdiag.exe /Test:ReplicationsMinutes (alert "after the fact")MDI license; Sigma / Splunk free with SACL config
NetworkDCE/RPC packet captureWire signature of IDL_DRSGetNCChanges from non-DC sourceEncrypted RPC payloads (per-principal granularity); sub-DC replicas misclassifiedSame as behavioral plus Samba-DC peersSeconds (passive inspection)Commercial NDR appliance
GraphLDAP-collected ACEs and group nestingMulti-hop graph paths that could reach the rights triadNet-new ACEs created after the last collectionStale data showing principals that no longer hold the rightHours to weeks (collection cadence)BloodHound CE free; BHE commercial
Architectural (un-shipped)TPM-attested DC machine identityPre-empts non-DC speaker entirelyCompromised DC speaker; rogue nTDSDSA registrationN/AN/A (preventive)Requires Microsoft protocol amendment

Four layers, dozens of products, no shortage of detections. Why isn't the problem solved?

7. Which Gap Does Each Defense Close?

The matrix in §6 has one structural observation that earns its keep. Read down the What it misses column. Each detection layer has a class of cases it cannot see. The posture layer cannot see transitive paths. The behavioral layer cannot see pre-attack staging or compromised-DC speakers. The network layer cannot see encrypted RPC payloads. The graph layer cannot see net-new ACEs created after the last collection. That is the load-bearing reason a mature defender runs all four in parallel instead of picking one.

Run a thought experiment. Suppose you ship only the posture layer. Your MDI assessment is green: no non-default principals hold the rights triad. An attacker compromises a workstation belonging to an unrelated business unit, finds that the BU has GenericAll on a group LegacyApp_Operators that itself has WriteDACL on the BackupOperators group, and adds themselves to BackupOperators. BackupOperators inherits a forgotten 2014 delegation of the rights triad through three levels of nesting. Then DCSync runs.

The posture layer never saw this because the residual list at the NC root is the four defaults. The graph layer would have surfaced the path. The behavioral or network layer would have fired the moment the DCSync call hit the wire. Without those layers, your green dashboard is a single-layer fantasy.

Now consider the inverse. You ship only the behavioral layer. MDI fires External ID 2006 -- but only after the request hits the DC. Your SOC's mean response time is twelve minutes. The attacker's mean complete-the-extraction time is sixty seconds. The detection is real; the response window is not.

The same structural observation applies on the attack side. The four attack primitives have very different precondition costs:

Attack primitivePre-conditionOutputDefault detection layerTier of damage
DCSync via MimikatzRights triad on NC rootEvery secret-attribute value for one or all principalsMDI 2006; Sigma 611eab06; Splunk 51307514; NDRDomain takeover (via Golden Ticket from krbtgt)
DCSync via ImpacketSame as Mimikatz; no on-target binary footprintSame as Mimikatz, plus PtH / PtT auth modesSame as Mimikatz (wire signature is identical)Domain takeover
DCShadowDomain Admin, local administrator on a DC, or KRBTGT hash (for rogue-DC registration) [19][18]Arbitrary directory write, SACL-silentMDI 2028 + 2029Domain persistence (SID-history, AdminSDHolder ACE re-grant)
Gen-4 chainsAny ACE that transitively leads to the triadReach DCSync, then DCSync's outputBloodHound DCSync edge inbound pathsDomain takeover (composite)

DCSync via Mimikatz and via Impacket [39] share the output (domain takeover via credential theft) and the default detection (the wire signature is the same). Their pre-conditions are identical. The Hacker Recipes documents Impacket's invocation surface for both pass-the-hash and pass-the-ticket modes [40]. This is why Impacket's secretsdump.py -just-dc has become the universal red-team and IR tool, while Mimikatz remains the reference implementation that every blue-team detection still names.

The Generation-4 row is the interesting one. Its pre-condition is dramatically cheaper than the other three (any ACE that leads to the triad, rather than the triad in hand). Its detection is by graph traversal, not by wire signature. This is why the 2024-2026 frontier in this space has been the graph layer: the attack-side cost asymmetry favors the chain-finding problem, so the defense-side investment has landed there.

If even the hypothetical perfect architectural fix would not close the class, what are the actual theoretical limits of any possible defense?

8. Why the Protocol Cannot Be Fixed

Two structural ceilings bound any conceivable MS-DRSR amendment. Both are provable from the specification's own definition of what it must do; both have been corroborated by the post-2018 industry consensus that detection (not prevention) is the only viable defender posture.

Ceiling 1: replicated secret material is the data the protocol exists to carry. MS-DRSR is the mechanism by which Active Directory's multi-master replication invariant holds. If IDL_DRSGetNCChanges did not return secret attributes -- unicodePwd, dBCSPwd, ntPwdHistory, lmPwdHistory, supplementalCredentials -- then a password change on DC-A would not converge to DC-B within the replication interval. AD's "any DC accepts any write and the others catch up within minutes" property would collapse [3]. The protocol cannot stop returning secrets without ceasing to be the protocol. This is why "disable MS-DRSR" appears on every list of options that look attractive in a slide deck and break replication in production within minutes of being applied.

Ceiling 2: a machine-identity check on the caller would shift the attack class, not close it. Suppose Microsoft amended the access check on IDL_DRSGetNCChanges to require, in addition to the rights triad, a cryptographic proof that the caller's machine account is in the Domain Controllers group -- for example, that the call was made under a Kerberos service ticket issued for a DC SPN. This would defeat the Mimikatz-from-workstation case. It would also defeat every legitimate integration that today holds the rights triad on a non-DC service account: the Entra ID Connect MSOL_ account, third-party HR identity-management connectors, every backup and disaster-recovery tool that integrates at the AD level.

Worse, the new check would shift the attack class to compromising a DC's machine account -- CVE-2020-1472 Zerologon being the canonical worked example (see the §7 Aside for the mechanism). After a Zerologon-class compromise the attacker is a DC, so promoting the speaker check from (rights) to (rights and DC-identity) raises the bar but does not change the class [41].

Ctrl + scroll to zoom
The two structural ceilings on any MS-DRSR fix. Either branch -- removing the secret-return path or adding a caller-machine-identity check -- breaks the protocol or shifts the attack class without closing it.

The honest structural fix would require a different replication architecture: a TPM- or HSM-attested DC machine identity, bound to a sealed replication key, with secret attributes encrypted under that key on the wire. No caller without the sealed key (or its hardware-bound equivalent on a different DC) could ever decrypt the response.

Microsoft has not announced any such architecture. Its closest published precedent in the Windows security stack is the LSAIso trustlet that Credential Guard uses for LSASS isolation -- a per-host isolation primitive applied to a per-host secret store. Applying the same idea to a multi-party wire protocol that must interoperate with twenty-five years of installed identity-sync tooling is a different engineering problem at a different scale. Microsoft has not committed to it.

The replication attack class is structurally permanent. The honest defender response is detection-and-response, not prevention.

This is the article's humility moment. The reader who arrived at §5 thinking "this is fixable" should now understand why eleven years of attack/defense iteration have produced detection layers, not protocol revisions. The four-layer detection architecture is not a placeholder while we wait for Microsoft to ship the real fix. It is the real fix, conditional on the constraint that the protocol's job description does not change.

If the protocol is structurally unfixable, what exactly does 2026 still not solve operationally?

9. What 2026 Still Cannot Do

Five problems sit on the open-questions register in 2026. Each is documented in the literature. None has a satisfying answer.

The DCShadow gap window. MDI's External ID 2029 alert fires on the rogue DC's replication request, which is structurally after the rogue nTDSDSA registration has been committed. The alert documentation describes the detection as firing after the fact [26]. An attacker who completes the register-replicate-deregister cycle inside the alert's batch interval commits the persistence write before any SOC responder sees the alert. External ID 2028 (rogue promotion) fires earlier in the kill chain and partially closes the gap, but the gap is structural to the alert-batch model. The directory write that DCShadow lands -- a SID-history injection, an AdminSDHolder ACE re-grant -- survives the alert.

Encrypted-channel DCSync. DRSUAPI clients that negotiate AUTH_LEVEL_PKT_PRIVACY on the RPC binding (the modern hardened-DC default) encrypt the request and response bodies on the wire. Passive NDR sensors that depend on parsing the IDL_DRSGetNCChanges request to determine which principal is being targeted lose per-principal granularity.

The interface-bind packet is still in clear, so the existence of a DRSUAPI call is still visible, but the payload is not. The Microsoft channel-binding rollout that began in late 2023 (targeting LDAP rather than DRSUAPI, but cementing the broader trend toward encrypted directory traffic) makes this gap permanent on the wire side [42]. Detection moves into the DC itself via the MDI sensor model.

The legitimate-principal-compromise non-detection. A hijacked Domain Admin session that uses its rightful DCSync ability triggers no layer. The posture layer sees a default principal. The behavioral layer sees a request from a DC or admin workstation that the Replication Allow List baseline accepts. The network layer sees the same. The graph layer sees the principal as a default Tier Zero member. The MDI alert is explicit: the trigger is "a computer that isn't a domain controller" -- a compromised legitimate principal acting from a legitimately-baselined workstation does not fire it [26].

This is the failure mode that catches mature SOCs. The attacker who already has Domain Admin does not need to attack DCSync detection because DCSync detection is not designed for legitimate principal abuse. UEBA-style per-principal anomaly detection ("this DA has not run DCSync in 90 days; this DA running DCSync at 03:00 from a workstation it has not used before is anomalous") is the partial answer. No production product currently delivers it with low enough false-positive rates to be operationally useful for already-Tier-Zero principals.

Cross-forest replication abuse is under-instrumented. The interaction of DS-Replication-Get-Changes-In-Filtered-Set with the SPN-suffix routing matrix in multi-forest environments is poorly covered in public detection guidance. Large enterprises with M&A history hold dozens of trusts; the cross-trust edges are the least-audited surface in their identity architecture. BloodHound's SharpHound collector can enumerate cross-trust data, and v6.0's wildcard-principal fix improves the picture, but no fully automated detection pattern exists [35].

Delegation-drift residual long tail. Even with the MDI Accounts security posture assessment perfectly tuned, the long tail of forgotten ACE delegations across a twenty-five-year-old forest with mergers, acquisitions, decommissioned products, and migrations remains the canonical entry point. Christopher Keim frames it unambiguously [24]:

"The defaults aren't the problem. The problem is delegation drift, backup agents, identity sync products, and application service accounts accumulate these rights over time, often with no documentation and no review." -- Christopher Keim, "DCSync Attack: Finding and Fixing Replication Rights in Active Directory" (2025) [24]

The posture-layer detection is necessary but not sufficient; the human-process loop -- documented ownership, periodic review, removal of unjustified ACEs -- is what closes the residual. Most enterprise SOCs are not staffed to run this loop at the cadence the residual requires.

Open problemWhy it mattersCurrent best partial result
DCShadow gap windowPersistence write commits before SOC sees the alertConfigure MDI to surface External ID 2028 (rogue promotion) with automated investigation and response to block RPC traffic from the suspected source [43]
Encrypted-channel DCSyncPassive NDR loses per-principal granularityHybrid deployment: NDR for cross-DC visibility, MDI on-DC sensor for per-principal granularity [14]
Legitimate-principal compromise non-detectionThe Tier Zero principal who already has DCSync rights triggers nothingReduce the count of DCSync-capable principals to a number a human can monitor; surface their DCSync activity to a high-severity review queue
Cross-forest replication abuseCross-trust DCSync paths are not enumerated by defaultSharpHound trust-collection methods; manual BloodHound inspection of foreign-domain principals
Delegation-drift residual long tailPosture surfaces the principals; humans still have to decide which are legitimateQuarterly posture review with documented justification per non-default principal

What can a defender actually do on Monday morning, given all of the above?

10. What a Defender Does on Monday Morning

Three action lanes, in priority order.

Lane 1: inventory the rights triad

Read the Domain NC root's ACL. Filter on the three rights GUIDs. Subtract the four default principal sets plus any legitimately delegated identity-sync product (Entra ID Connect's MSOL_ account is the canonical exclusion). Every entry that remains gets a documented owner and a documented justification, or the ACE gets removed.

Python Production-shape inventory of rights-triad holders, with operator commentary
# Operator-facing inventory script. The browser-runnable demo uses a
# hardcoded SAMPLE_ACL; in production, replace the SAMPLE_ACL with output
# from one of:
#   PowerShell:  Get-Acl "AD:$( (Get-ADDomain).DistinguishedName )"
#   python-ldap: ldap_search(ncroot_dn, attr='nTSecurityDescriptor')

GET_CHANGES          = '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2'
GET_CHANGES_ALL      = '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'
GET_CHANGES_FILTERED = '89e95b76-444d-4c62-991a-0facbeda640c'
TRIAD = {GET_CHANGES, GET_CHANGES_ALL, GET_CHANGES_FILTERED}

DEFAULT_OK = {
  'BUILTIN\\Administrators',
  'CONTOSO\\Domain Controllers',
  'CONTOSO\\Domain Admins',
  'CONTOSO\\Enterprise Admins',
  'NT AUTHORITY\\ENTERPRISE DOMAIN CONTROLLERS',
}

# MSOL_ accounts: legitimate Entra ID Connect sync principals.
# Exclude by prefix, never by exact name (the suffix is random).
def is_known_legitimate(principal):
  return principal in DEFAULT_OK or '\\MSOL_' in principal

SAMPLE_ACL = [
  {'principal': 'CONTOSO\\Domain Admins',     'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\MSOL_a1b2c3d4',     'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\backup_svc_2017',   'right': GET_CHANGES_ALL},
  {'principal': 'CONTOSO\\hr_idm_connector',  'right': GET_CHANGES},
  {'principal': 'CONTOSO\\fileserver_old$',   'right': GET_CHANGES_ALL},
]

findings = []
for ace in SAMPLE_ACL:
  if ace['right'] not in TRIAD:
      continue
  if is_known_legitimate(ace['principal']):
      continue
  findings.append(ace['principal'])

print("Principals to investigate:")
for p in sorted(set(findings)):
  print(f"  - {p}  ->  document owner or remove ACE")

Press Run to execute.

Anything in the Principals to investigate output is either a legitimately delegated service (document the owner and add to your exclusions; treat as Tier Zero) or a forgotten ACE from a project nobody remembers (remove it). Christopher Keim's framing is the operationally useful one: every common culprit is a backup tool, an identity-governance tool, or a service account from a long-dead migration [24].

Lane 2: enable the canonical alerts and audit

Three configuration items.

First, ensure Microsoft Defender for Identity (or an equivalent identity-threat-detection product) is deployed with a sensor on every DC. The un-sensored-DC gap that the MDI alert documentation explicitly warns about creates a structural blind spot that an attacker will preferentially target [26].

Second, enable Advanced Security Audit policy Audit Directory Services Access under DS Access and apply SACLs on the Domain NC root that audit the three replication rights against Everyone, Domain Computers, and Domain Controllers. This is what makes Event ID 4662 fire on the request, which is what the Sigma 611eab06 and Splunk 51307514 rules consume [30][31]. A fresh-install AD does not have these SACLs by default; the most common reason a SIEM dashboard for DCSync is silent is that the SACL never got applied.

Third, deploy or configure NDR coverage on the inter-DC subnet, with a rule that fires on DRSUAPI bind requests originating from source IPs outside the legitimate-DC baseline. Trellix NDR, Microsoft's MDI sensor, CrowdStrike Falcon, and community Zeek/Suricata rulesets all implement this [14]. Where commercial NDR is out of budget, Sysmon with the SwiftOnSecurity or Olaf Hartong modular configuration surfaces Event ID 3 (NetworkConnect) and Event ID 22 (DnsQuery) outbound from non-DC hosts to DC RPC endpoints; a SIEM correlation rule can combine this endpoint-side signal with Event ID 4662 on the DC to approximate the network-plus-host signature without an appliance budget.

Lane 3: run BloodHound on the domain quarterly

Collect with SharpHound at minimum quarterly. Continuous collection if BloodHound Enterprise is available. Run the canonical query for the DCSync edge into the domain node. Trace inbound paths. Close the longest path first -- the longest paths are the ones a human operator is least likely to have noticed and most likely to have been delegated decades ago for a reason nobody remembers.

The v6.0 wildcard-principal fix is particularly worth a re-run on any forest that has been operated since before 2003: legacy Authenticated Users or Everyone ACEs on the domain root are exactly the kind of thing that survived a Server 2003 upgrade silently and never showed up in any subsequent audit [35]. The v6.3 Butterfly algorithm lets you query the inverse view -- which targets fall if this principal is compromised? -- which is the right question to ask about any newly-discovered non-default DCSync holder [36][37].

What does not work

Four common misbeliefs are worth naming.

Renaming krbtgt does nothing. The account's Relative Identifier (RID 502) is fixed by AD's design and is what the TGT signing key derives against, not the sAMAccountName [45]. Renaming it to krbtgt-old-do-not-use confuses operators, not attackers.

Disabling MS-DRSR is not an option. The protocol is what makes AD replication work. Blocking opnum 3 at the RPC layer or refusing the DRSUAPI bind stops DCSync and stops every DC in the forest from talking to every other DC. Replication grinds. Password changes do not propagate. Domain joins fail. Within hours, the directory is split-brain across DCs, and within days, it is unrecoverable without DR-grade restore from backup: Microsoft's own AD-replication troubleshooting documentation walks the lingering-object pathology that produces exactly this split-brain when DCs stop replicating for longer than the tombstone lifetime [46].

A diagnostic one-liner for the SACL precondition

On any DC, run auditpol /get /subcategory:"Directory Service Access" from an elevated prompt. If the output reads No Auditing, your Sigma / Splunk SACL-event detection will not fire because Event ID 4662 is not being generated. Enable with auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable, then apply the SACL on the domain root as described in the Splunk rule's implementation notes [31].

The six FAQ items in the next section cover the misconceptions that did not fit into any single lane.

11. Frequently Asked Questions

Frequently asked questions

Doesn't Replicating Directory Changes All alone let you DCSync?

No. The access check on IDL_DRSGetNCChanges requires both the baseline DS-Replication-Get-Changes right and DS-Replication-Get-Changes-All to read secret attributes [4][5]. The All suffix unlocks the secret attribute set given the baseline right; it is not a self-sufficient gate. Christopher Keim's PowerShell pattern filters on both GUIDs together [24]. Confidential-flag attributes additionally require DS-Replication-Get-Changes-In-Filtered-Set. Some detection rules (Sigma 611eab06 included) accept either GUID in the SACL event because the operational cost of a false positive on the broader filter is lower than the risk of missing one of the two required ACEs being present without the other [30].

Doesn't Credential Guard protect me?

No. Credential Guard isolates LSASS-resident secrets in a separate virtual trust level so that local-memory attacks (Mimikatz sekurlsa::logonpasswords, comsvcs.dll mini-dumps of lsass.exe, and similar) cannot read cached credentials. DCSync does not touch the attacker's LSASS at all. The secret transits from a remote DC's NTDS.dit, over an encrypted MS-DRSR session, into the attacker's process memory. Microsoft's Credential Guard documentation lists the scenarios Credential Guard does and does not cover; MS-DRSR-based network credential extraction is not in scope [1]. This is one of the clearest examples in the Windows security model of a control that is right for one attack surface and orthogonal to another.

Isn't DCShadow undetectable?

Not anymore. The BlueHat IL 2018 "your million-dollar SIEM goes blind" framing was correct in 2018 against SIEMs that monitored only object-modification events: the replication writes are SACL-silent. By July 24, 2018, Tali Ash announced Azure ATP's two new preview detections, which fired on the rogue-DC promotion fingerprint (creating an nTDSDSA object in the Configuration NC) and the replication request from the rogue, respectively [27]. Those detections carried forward as Microsoft Defender for Identity External IDs 2028 and 2029 [26]. The writes themselves remain SACL-silent; the registration fingerprint that has to precede them is not. The honest contemporary statement is "DCShadow's writes are silent, but the rogue-DC scaffolding is not, and a sensored DC catches the scaffolding." A skilled attacker who completes the register-replicate-deregister cycle inside the alert batch interval may still commit the persistence write before SOC response.

Did Microsoft fix this in some patch?

No. The protocol's design is the issue. Microsoft has not announced any MS-DRSR amendment that would change the IDL_DRSGetNCChanges access check, because amending the access check breaks legitimate non-DC consumers (the Entra ID Connect MSOL_ account is the most prominent) and shifts the attack class to compromised DC machine accounts (Zerologon is the worked example [41]). The "fixes" that have shipped since 2015 are all detection: ATA 1.7 (April 2017) [15], Azure ATP (2018) [27], Microsoft Defender for Identity (post-Ignite 2020 rebrand) [28][29], and the posture-assessment families that surface non-default rights triad holders [23]. The protocol itself is the same protocol it was in Windows 2000 Server.

What does this mean for hybrid (Entra ID Connect) environments?

The MSOL_ sync account legitimately holds the rights triad on the Domain NC root because it must replicate password hashes to Entra ID. Treat it as Tier Zero with the hardening profile listed in §10's MSOL_ Aside (dedicated hardened host, no interactive logon, MFA on privileged use, conditional access restricted to the Entra Connect service identity) [25]. Critically, do not remove the ACE from the Domain NC root: doing so breaks Entra ID password hash sync within one replication interval, and your help desk will know about it within hours.

Is this the same as DCSync-over-LDAP?

No. DCSync is over DRSUAPI/MS-DRSR, not over LDAP. The directory's LDAP service refuses to return unicodePwd and related secret-attribute values regardless of caller privilege, because the attribute is marked confidential and the LDAP read path does not honor the replication extended rights. There is no "DCSync over LDAP" technique because LDAP simply does not return the data; MITRE T1003.006 names DRSUAPI explicitly as the protocol vector [47]. Operators occasionally confuse this with LDAPS (LDAP over TLS) or with the November 2023 LDAP signing and channel-binding rollout, both of which are channel-protection concerns rather than credential-read concerns.

Study guide

Key terms

MS-DRSR
Directory Replication Service Remote Protocol; the RPC interface by which any AD domain controller can replicate any object including secret attributes from any other DC.
IDL_DRSGetNCChanges
MS-DRSR's opnum-3 method that returns changed objects within a naming context; the protocol method DCSync invokes.
Extended Right
A schema-defined access-control right keyed by GUID rather than by standard ACL bit. Granted via ACE; checked at runtime by the operation that requires it.
Naming Context
A top-level replication partition of the Active Directory database. DCSync operates against the Domain NC root.
Rights Triad
DS-Replication-Get-Changes, DS-Replication-Get-Changes-All, and DS-Replication-Get-Changes-In-Filtered-Set extended rights on a naming-context root.
NTDS.dit
The on-disk Extensible Storage Engine database holding every AD object including secret attributes.
SACL-silent
A directory operation that does not generate the Event ID 4662/4738/5136 events normally emitted by Domain Services Auditing. Legitimate DC-to-DC replication is SACL-silent by design.
Tier Zero
Principals and assets whose compromise yields domain-wide control. KRBTGT, Domain Admins, the MSOL_ account, and any principal holding the rights triad are all Tier Zero.
MSOL_ account
The Entra ID Connect synchronization service account; legitimately holds the rights triad to replicate password hashes to the cloud directory.
Replication Allow List
MDI's internal baseline of which computers in the domain legitimately speak DRSUAPI to which DCs.

Flashcards

Flashcards

1 / 5

Comprehension questions

  1. Why does adding a caller-machine-identity check to MS-DRSR not close the attack class?

    Because compromising a DC's machine account (CVE-2020-1472 Zerologon being the canonical worked example) satisfies the new check while still enabling the original attack.

  2. Why is Credential Guard the wrong control for DCSync?

    Credential Guard isolates LSASS-resident secrets on the local machine. DCSync reads secrets from a remote DC's NTDS.dit over MS-DRSR; the secret never transits the attacker's LSASS.

  3. Why must the krbtgt password be rotated twice after a confirmed DCSync?

    Each AD account stores both the current and previous password. Rotating once invalidates only the older of the two keys; the most recently dumped key remains valid. Rotating a second time, after the first replication interval has converged, invalidates the dumped key.

  4. What does each of the four defense layers miss?

    Posture misses transitive paths. Behavioral misses pre-attack staging and compromised-DC speakers. Network misses encrypted RPC payloads. Graph misses net-new ACEs created after the last collection.

  5. Why is the DCShadow gap window structural?

    MDI External ID 2029 fires on the rogue's replication request after registration. An attacker who completes register-replicate-deregister inside the alert batch interval commits the persistence write before SOC response.

A final observation, since the closing should add something new. The protocol that this article calls structurally unfixable is not unusual. Most Microsoft security primitives that survive long enough enter the same regime -- the LSASS surface, the Kerberos delegation surface, the SMB authentication surface -- where the only honest answer is detection in depth because the protocol's job description and its abuse surface are the same surface viewed from different chairs.

The thing that makes MS-DRSR notable is the clarity with which the structural error is visible. Read §4.1.10 once and you are done. Everything from §6 onward is the industry's slow accumulation of detection layers around a gate that cannot be moved. Twenty-five years in, the gate is still where it was on February 17, 2000, and the four layers around it are still under active engineering.

References

  1. Microsoft Credential Guard considerations and known issues. https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard-considerations
  2. Microsoft News (2000). Gates Ushers in Next Generation of PC Computing With Launch of Windows 2000. https://news.microsoft.com/source/2000/02/17/gates-ushers-in-next-generation-of-pc-computing-with-launch-of-windows-2000/
  3. Microsoft (2026). [MS-DRSR] Directory Replication Service (DRS) Remote Protocol Specification. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/f977faaa-673e-4f66-b9bf-48c640241d47
  4. Microsoft DS-Replication-Get-Changes extended right. https://learn.microsoft.com/en-us/windows/win32/adschema/r-ds-replication-get-changes
  5. Microsoft DS-Replication-Get-Changes-All extended right. https://learn.microsoft.com/en-us/windows/win32/adschema/r-ds-replication-get-changes-all
  6. Microsoft DS-Replication-Get-Changes-In-Filtered-Set extended right. https://learn.microsoft.com/en-us/windows/win32/adschema/r-ds-replication-get-changes-in-filtered-set
  7. Sean Metcalf (2015). Mimikatz DCSync Usage, Exploitation, and Detection. https://adsecurity.org/?p=1729
  8. Csaba Barta ntdsxtract -- Active Directory forensic framework. https://github.com/csababarta/ntdsxtract
  9. MITRE OS Credential Dumping: NTDS (T1003.003). https://attack.mitre.org/techniques/T1003/003/
  10. Dell SecureWorks Counter Threat Unit (2015). Skeleton Key Malware Analysis. https://web.archive.org/web/2024/https://www.secureworks.com/research/skeleton-key-malware-analysis
  11. Benjamin Delpy (2015). Mimikatz commit 7717b7a: DCSync in mimikatz & for XP/2003. https://github.com/gentilkiwi/mimikatz/commit/7717b7a7173fa6a6b6566bbbc3e7372b464d988f
  12. Benjamin Delpy gentilkiwi/mimikatz. https://github.com/gentilkiwi/mimikatz
  13. Sean Metcalf (2015). DerbyCon V: Red vs. Blue: Modern Active Directory Attacks, Detection, and Protection. https://adsecurity.org/?p=1738
  14. Trellix Advanced Research Center (2025). Silent Domain Hijack: Uncovering the DCSync Attack and Detecting with Trellix NDR. https://www.trellix.com/blogs/research/silent-domain-hijack-detecting-dcsync-with-trellix-ndr/
  15. Microsoft (2017). Description of Microsoft Advanced Threat Analytics v1.7. https://support.microsoft.com/en-us/topic/description-of-microsoft-advanced-threat-analytics-v1-7-fc8e4afb-076b-69e1-058e-459ccf4bfcce
  16. Benjamin Delpy & Vincent Le Toux (2018). Active Directory: What can make your million dollar SIEM go blind?. https://www.youtube.com/watch?v=KILnU4FhQbc
  17. Benjamin Delpy (2018). Mimikatz commit ab18bd1: Pushing @vletoux DCShadow in current branch. https://github.com/gentilkiwi/mimikatz/commit/ab18bd103a5cd7e26fb8d475c5ea0157d6633ca9
  18. Vincent Le Toux DCShadow. https://www.dcshadow.com
  19. MITRE Rogue Domain Controller (T1207). https://attack.mitre.org/techniques/T1207/
  20. Elad Shamir (2019). Wagging the Dog: Abusing Resource-Based Constrained Delegation. https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html
  21. Elad Shamir (2021). Shadow Credentials: Abusing Key Trust Account Mapping for Account Takeover. https://eladshamir.com/2021/06/21/Shadow-Credentials.html
  22. Sean Metcalf (2015). Sneaky Active Directory Persistence #15: Abusing AdminSDHolder & SDProp to (Re)Gain Domain Admin Rights. https://adsecurity.org/?p=1906
  23. Microsoft Microsoft Defender for Identity Accounts security posture assessments. https://learn.microsoft.com/en-us/defender-for-identity/security-posture-assessments/accounts
  24. Christopher Keim (2025). DCSync Attack: Finding and Fixing Replication Rights in Active Directory. https://www.christopherkeim.com/post/dcsync-attack-finding-and-fixing-replication-rights-in-active-directory
  25. Microsoft Microsoft Defender for Identity Hybrid security posture assessments. https://learn.microsoft.com/en-us/defender-for-identity/security-posture-assessments/hybrid-security
  26. Microsoft Microsoft Defender for Identity security alerts (classic). https://learn.microsoft.com/en-us/defender-for-identity/alerts-mdi-classic
  27. Tali Ash (2018). Azure ATP brings you 2 new preview detections on DcShadow attack. https://techcommunity.microsoft.com/discussions/azureadvancedthreatprotection/azure-atp-brings-you-2-new-preview-detections-on-dcshadow-attack/218502
  28. Redmond Channel Partner (2020). Microsoft's Enterprise Security Lineup Gets a Defender-Centric Rebrand. https://rcpmag.com/articles/2020/09/28/microsoft-defender-security-rebrand.aspx
  29. Microsoft What's new in Microsoft Defender for Identity. https://learn.microsoft.com/en-us/defender-for-identity/whats-new
  30. Benjamin Delpy, Florian Roth, Scott Dermott, & Sorina Ionescu Sigma rule: Mimikatz DC Sync (611eab06-a145-4dfa-a295-3ccc5c20f59a). https://raw.githubusercontent.com/SigmaHQ/sigma/master/rules/windows/builtin/security/win_security_dcsync.yml
  31. Splunk Threat Research Team Windows AD Replication Request Initiated by User Account (rule 51307514-1236-49f6-8686-d46d93cc2821). https://research.splunk.com/endpoint/51307514-1236-49f6-8686-d46d93cc2821/
  32. Andy Robbins (2016). Introducing BloodHound. https://wald0.com/?p=68
  33. Andy Robbins, Rohan Vazarkar, & Will Schroeder (2016). Six Degrees of Domain Admin (DEF CON 24). https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Robbins-Vazarkar-Schroeder-Six-Degrees-of-Domain-Admin.pdf
  34. SpecterOps BloodHound DC-Sync edge documentation. https://bloodhound.specterops.io/resources/edges/dc-sync
  35. SpecterOps (2024). BloodHound v6.0.0 release notes. https://bloodhound.specterops.io/resources/release-notes/2024-09-30-v6-0-0
  36. SpecterOps (2024). Unwrapping BloodHound v6.3 with Impact Analysis. https://specterops.io/blog/2024/12/12/unwrapping-bloodhound-v6-3-with-impact-analysis/
  37. SpecterOps (2024). BloodHound v6.3.0 release notes. https://bloodhound.specterops.io/resources/release-notes/2024-12-09-v6-3-0
  38. SpecterOps (2025). BloodHound v8.0.0 release notes. https://bloodhound.specterops.io/resources/release-notes/v8-0-0
  39. Fortra Impacket secretsdump.py. https://github.com/fortra/impacket/blob/master/examples/secretsdump.py
  40. Active Directory: DCSync. https://www.thehacker.recipes/a-d/movement/credentials/dumping/dcsync
  41. Secura (2020). Zerologon: Unauthenticated domain controller compromise by subverting Netlogon cryptography (CVE-2020-1472). https://www.secura.com/uploads/whitepapers/Zerologon.pdf
  42. Microsoft (2025). 2020, 2023, and 2024 LDAP channel binding and LDAP signing requirements for Windows (KB4520412). https://support.microsoft.com/en-us/topic/2020-2023-and-2024-ldap-channel-binding-and-ldap-signing-requirements-for-windows-kb4520412-ef185fb8-00f7-167d-744c-f299a66fc00a
  43. Microsoft Microsoft Defender for Identity credential access alerts. https://learn.microsoft.com/en-us/defender-for-identity/credential-access-alerts
  44. Microsoft DART New-KrbtgtKeys.ps1 -- Reset the krbtgt account password / keys. https://github.com/microsoftarchive/New-KrbtgtKeys.ps1
  45. Microsoft Security identifiers (well-known SIDs and RIDs). https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers
  46. Microsoft How to detect and remove lingering objects in a Windows Server Active Directory forest (KB 910205). https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/information-lingering-objects
  47. MITRE OS Credential Dumping: DCSync (T1003.006). https://attack.mitre.org/techniques/T1003/006/
  48. Benjamin Delpy Mimikatz wiki: lsadump module. https://github.com/gentilkiwi/mimikatz/wiki/module-~-lsadump
  49. Sean Metcalf How Attackers Dump Active Directory Database Credentials. https://adsecurity.org/?p=2398
  50. Will Schroeder (2015). Mimikatz and DCSync and ExtraSids, Oh My. https://blog.harmj0y.net/redteaming/mimikatz-and-dcsync-and-extrasids-oh-my/