This is the story of a real penetration test. The client, a mid-sized financial services firm with roughly 2,500 employees, hired us for an internal Active Directory assessment. They gave us a single domain user account - the same level of access any new hire would receive on their first day. Four hours later, we owned the domain.
Every detail in this article is real, pulled from our engagement notes and timestamps. Company names, usernames, hostnames, and IP addresses have been anonymized. The attack path, the tools, the timing, and the decisions are exactly as they happened.
For each step, we will explain what we did, why we did it, and what defensive control could have stopped us. This is not a showcase. It is a blueprint for understanding how AD environments actually fall.
The Rules of Engagement
The client's security team defined the scope: full internal AD assessment, assume-breach model, starting from a standard domain user account. The account they gave us, "j.testing," was a member of "Domain Users" only. No special group memberships, no admin rights on any workstation, no elevated privileges of any kind. Our testing laptop was connected to a dedicated VLAN with standard employee network access.
The objective was clear: determine whether an attacker with basic domain credentials could escalate to Domain Admin, and if so, how quickly and through which path.
We started our timers at 09:00.
Hour One (09:00 - 10:00): Reconnaissance and Graph Collection
09:00 - 09:12: LDAP Enumeration
Before running anything heavy, we started with quiet LDAP queries to understand the environment's shape. Using NetExec (the maintained fork of CrackMapExec), we enumerated basic domain information:[1]
nxc smb 10.50.1.1 -u j.testing -p 'Provided_Password' --groups
The domain, which we will call ACMEFIN.LOCAL, was running at a Windows Server 2016 functional level. Two domain controllers: DC01 and DC02. The domain had 2,847 user accounts, 312 computer objects, and 186 groups. Standard size for this type of organization.
We ran a quick check for low-hanging fruit: accounts with Kerberos pre-authentication disabled (AS-REP roastable) and accounts with SPNs registered (Kerberoastable).
GetNPUsers.py ACMEFIN.LOCAL/j.testing:Provided_Password -dc-ip 10.50.1.1 -format hashcat
No AS-REP roastable accounts. Good for the client. But the SPN enumeration told a different story.
GetUserSPNs.py ACMEFIN.LOCAL/j.testing:Provided_Password -dc-ip 10.50.1.1
Fourteen user accounts with SPNs registered. This was above average. We noted the list and moved on to graph collection.
09:12 - 09:28: BloodHound Collection and Analysis
We ran BloodHound.py from our Linux testing laptop to collect the full AD graph:[2]
bloodhound-python -u j.testing -p 'Provided_Password' -d ACMEFIN.LOCAL -dc DC01.ACMEFIN.LOCAL -c All
Collection completed in about seven minutes, producing JSON files for users, groups, computers, GPOs, ACLs, and session data. We imported everything into BloodHound Community Edition and began querying.
The first query we always run: "Shortest Paths to Domain Admins from Owned Principals." With only j.testing marked as owned, BloodHound showed no direct path. Expected. We expanded our search.
"Find Kerberoastable Users with Path to Domain Admin" revealed the finding that would define this engagement. An account called "svc_sqlreport" had an SPN of MSSQLSvc/SQLREPORT01.ACMEFIN.LOCAL:1433 and was a member of a nested group chain: svc_sqlreport was in "SQL Service Accounts," which was in "Server Administrators," which had GenericAll permissions on the "IT Infrastructure" OU. Several servers in that OU had Domain Admins logged in, according to the session data BloodHound collected.
But the more interesting path was simpler. svc_sqlreport was a member of a group called "Backup Operators Extended," which had been granted the "Replicating Directory Changes All" privilege on the domain object. This was the DCSync path. If we could crack svc_sqlreport's password, we would not need lateral movement at all.
Defense that would have stopped us: Reviewing and removing unnecessary replication privileges. There is no legitimate reason for a SQL reporting service account to have DCSync rights. This was likely granted during a migration or backup configuration and never cleaned up.
09:28 - 09:35: Decision Point
At this point we had two potential paths forward. Path A was to Kerberoast the 14 SPN accounts, crack what we could, and hope svc_sqlreport was among the cracked passwords. Path B was to look for other avenues, like ADCS misconfigurations or delegation abuse, in case the Kerberoasting did not yield results. We chose to pursue both in parallel but started with Kerberoasting since it required no additional access and could run alongside other enumeration.
Hour Two (10:00 - 11:00): Kerberoasting and Cracking
09:35 - 09:40: Requesting Service Tickets
We used Impacket's GetUserSPNs.py to request TGS tickets for all 14 SPN accounts:[3]
GetUserSPNs.py ACMEFIN.LOCAL/j.testing:Provided_Password -dc-ip 10.50.1.1 -request -outputfile tgs_hashes.txt
All 14 tickets were returned in seconds. Examining the hash format, 11 of the 14 used RC4 encryption (Hashcat mode 13100), meaning the accounts had not been configured for AES-only Kerberos. The remaining three used AES256 (mode 19700), which is significantly slower to crack.
The 11 RC4 hashes included svc_sqlreport. We could already feel the path opening up.
09:40 - 10:45: Hash Cracking
We transferred the hashes to our cracking rig, a dedicated workstation with two NVIDIA RTX 4090 GPUs. For Kerberos 5 TGS-REP RC4 hashes (mode 13100), this setup achieves approximately 14 billion candidates per second.[4]
Our cracking approach follows a specific methodology. We start with a targeted wordlist built from OSINT about the company: the company name, founding year, city, products, and common password patterns. We then move to larger wordlists with rule-based mutations.
Phase 1: Company-specific wordlist with best64.rule. Run time: 30 seconds. Results: two passwords cracked.
Phase 2: rockyou.txt with OneRuleToRuleThemAll.rule. Run time: approximately 12 minutes. Results: four more passwords cracked, bringing the total to six out of eleven RC4 hashes.
Phase 3: Larger wordlists (weakpass_3a combined with Kaonashi) with dive.rule. We let this run while we analyzed the already-cracked accounts.
The cracked accounts and their passwords:
- svc_backup: "Backup2019!"
- svc_sqlreport: "SqlReport#2021"
- svc_sharepoint: "SP_Service1"
- svc_monitoring: "Monitor123"
- svc_printer: "Print2020"
- svc_legacy_app: "Welcome1"
svc_sqlreport's password, "SqlReport#2021," cracked during the rockyou phase with rule mutations. It was a 15-character password that met typical complexity requirements (uppercase, lowercase, number, special character) but was derived from the service name itself. This pattern is extremely common in service accounts.
Defense that would have stopped us: Group Managed Service Accounts (gMSAs) generate 240-character random passwords that are rotated automatically. Migrating svc_sqlreport to a gMSA would have made Kerberoasting useless. Alternatively, a 25+ character truly random password would have resisted our cracking for years, not minutes.
Hour Three (11:00 - 12:00): Privilege Escalation via DCSync
10:50 - 11:05: Validating the Cracked Credential
Before attempting DCSync, we validated the credential and confirmed the account's privileges. First, a simple authentication check:
nxc smb DC01.ACMEFIN.LOCAL -u svc_sqlreport -p 'SqlReport#2021'
The output showed "[+] ACMEFIN.LOCAL\svc_sqlreport:SqlReport#2021" with a green checkmark. The password was valid and the account was not locked or disabled.
Next, we confirmed the DCSync privileges. Using PowerView-equivalent LDAP queries through NetExec, we verified that the "Backup Operators Extended" group held DS-Replication-Get-Changes-All on the domain object. We double-checked with an ACL query through ldapsearch, confirming the extended right GUID (1131f6ad-9c07-11d1-f79f-00c04fc2dcd2, which corresponds to DS-Replication-Get-Changes-All) was present on the group's ACE.
11:05 - 11:15: DCSync - Extracting the krbtgt Hash
With a confirmed account that had replication privileges, DCSync was straightforward:[5]
secretsdump.py ACMEFIN.LOCAL/svc_sqlreport:'SqlReport#2021'@DC01.ACMEFIN.LOCAL -just-dc-user krbtgt
The output returned the krbtgt account's NTLM hash in under two seconds. With this hash, we could forge a Golden Ticket to impersonate any user in the domain, including Domain Admins.
We then performed a full DCSync to extract all domain hashes for our report:
secretsdump.py ACMEFIN.LOCAL/svc_sqlreport:'SqlReport#2021'@DC01.ACMEFIN.LOCAL -just-dc-ntlm -outputfile acmefin_hashes
2,847 NTLM hashes dumped in approximately 40 seconds. This included the Administrator account, all Domain Admin accounts, and every user in the directory.
Defense that would have stopped us: Monitoring Event ID 4662 on domain controllers for access to the directory replication ACE GUIDs by non-DC accounts. Microsoft Defender for Identity (formerly Azure ATP) detects DCSync activity out of the box. Many SIEM solutions include detection rules for this as well.
11:15 - 11:30: Forging the Golden Ticket
With the krbtgt hash in hand, we forged a Golden Ticket to demonstrate full domain compromise:[6]
ticketer.py -nthash [KRBTGT_HASH] -domain-sid S-1-5-21-XXXXXXXXXX -domain ACMEFIN.LOCAL administrator
We exported the ticket and set the KRB5CCNAME environment variable to use it:
export KRB5CCNAME=administrator.ccache
Then validated it by accessing the domain controller's C$ share:
smbclient.py ACMEFIN.LOCAL/[email protected] -k -no-pass
Full read/write access to the domain controller's file system. Domain compromise was complete.
11:30 - 12:00: Demonstrating Impact
For the report, we demonstrated several impact scenarios that a real attacker could execute from this position:
- Full credential dump: All 2,847 user password hashes extracted, enabling offline cracking and pass-the-hash attacks against every account in the organization.
- Domain controller access: Administrative command execution on both DCs via PsExec, demonstrating the ability to modify Group Policy, create new accounts, or deploy malware to every domain-joined machine.
- Persistence: The Golden Ticket itself serves as persistence. Even if every password in the domain were reset, the forged ticket would remain valid until the krbtgt password is changed twice.
- Data access: We demonstrated access to file shares containing financial data, HR records, and client information, all accessible to the Domain Admins group.
The Timeline: Four Steps in Four Hours
Let us summarize the kill chain with exact timestamps:
- 09:00 - 09:28 (28 minutes): LDAP enumeration and BloodHound graph collection. Identified the attack path.
- 09:35 - 09:40 (5 minutes): Kerberoasted 14 service accounts.
- 09:40 - 10:45 (65 minutes): Cracked 6 of 11 RC4 hashes, including svc_sqlreport.
- 10:50 - 11:30 (40 minutes): Validated credentials, performed DCSync, forged Golden Ticket, demonstrated domain compromise.
Total elapsed time: 2 hours and 30 minutes from kickoff to Domain Admin. We had budgeted four hours. The remaining time was spent on documentation and exploring additional attack paths for comprehensive reporting.
What Could Have Stopped Us at Each Step
This is the section we care about most. Each step in this chain could have been broken by specific, implementable controls.
Step 1: Reconnaissance (BloodHound)
BloodHound collection is difficult to prevent entirely because it uses legitimate LDAP queries. However, the information it reveals can be reduced.
- Reduce attack surface: Regularly audit and clean up group nesting, especially groups with privileged ACLs. Use BloodHound defensively to find and eliminate unnecessary paths to Domain Admins.[7]
- Detect collection: Monitor for rapid LDAP queries that enumerate all objects, particularly sessions. MDI (Microsoft Defender for Identity) flags BloodHound collection as a reconnaissance alert.
- Restrict session enumeration: The NetSessionEnum function (used by BloodHound to map logged-in users to computers) can be restricted via the NetCease tool or GPO-based permissions.
Step 2: Kerberoasting
- Eliminate the attack: Migrate all service accounts to gMSAs. This is the definitive fix. gMSA passwords are 240 characters and rotated every 30 days by default.
- Mitigate the attack: For accounts that cannot use gMSAs, enforce passwords of 25+ characters generated randomly. At this length, even RC4 hashes are infeasible to crack with current hardware.[8]
- Detect the attack: Monitor Event ID 4769 for TGS requests using RC4 encryption (encryption type 0x17), especially in bulk. A single user requesting tickets for many SPN accounts in a short window is a strong Kerberoasting indicator.
- Force AES: Configure service accounts to support only AES256 Kerberos encryption. AES hashes are orders of magnitude slower to crack.
Step 3: Excessive Privileges (DCSync Rights)
- Audit replication privileges: Only domain controller machine accounts and the two built-in groups (Domain Admins, Enterprise Admins) should have DS-Replication-Get-Changes-All. Regularly query the domain object's ACL to verify this.
- Use a tiered model: Service accounts should operate within their tier. A SQL reporting account has no business being in a group with domain replication rights. Implementing Microsoft's Enterprise Access Model (formerly the tiered administrative model) prevents this kind of privilege creep.[9]
- Detect DCSync: Event ID 4662 with the replication GUIDs, requested by a non-DC account, is the definitive indicator. This should be a high-priority SIEM alert.
Step 4: Golden Ticket Forgery
- Prevention: If DCSync is prevented, Golden Tickets cannot be forged (the attacker needs the krbtgt hash).
- Rotation: Change the krbtgt password periodically (every 180 days is a reasonable interval). This limits the window during which a stolen hash remains valid.
- Detection: Golden Tickets can be detected by looking for TGTs with anomalous lifetimes, TGTs that lack corresponding AS-REQ events on the DC, or tickets using RC4 when the environment is configured for AES.
The Bigger Picture: Why This Keeps Happening
This engagement was not unusual. The specific path varies, but the outcome is consistent. In our internal AD assessments over the past two years, we have achieved Domain Admin or equivalent in over 85% of engagements. The median time to domain compromise is under six hours.
The root causes are remarkably consistent across organizations of all sizes:
- Legacy service accounts with weak passwords: Accounts created years ago with passwords that met the complexity policy of the time but are trivially crackable by modern GPUs.
- Privilege creep: Groups accumulate permissions over time. A temporary grant for a migration project becomes permanent because nobody removes it.
- Flat network architecture: No segmentation between user workstations, servers, and domain controllers. Once you have domain credentials, you can reach everything.
- Absent monitoring: The specific events that indicate AD attacks (4769, 4662, 4768) are either not collected, not alerted on, or drowned in noise.
The encouraging news is that every link in this kill chain has a specific, well-documented defense. None of these defenses require exotic tools or massive budgets. gMSAs are a built-in AD feature. BloodHound is free and open source. Event log monitoring is a standard SIEM capability. The challenge is not technology. It is prioritization.
Recommendations We Delivered
Our report to the client included 23 findings across critical, high, medium, and low severities. The top five recommendations, ordered by impact on reducing the attack surface, were:
- Migrate all service accounts to gMSAs (or enforce 25+ character random passwords where gMSAs are not feasible). Timeline: 90 days. This eliminates Kerberoasting as a viable attack vector.
- Audit and remediate DCSync privileges. Remove the "Replicating Directory Changes All" right from all non-DC accounts. Timeline: immediate.
- Deploy Microsoft Defender for Identity on all domain controllers. This provides detection for Kerberoasting, DCSync, BloodHound collection, Pass-the-Hash, Golden Ticket usage, and dozens of other AD attack techniques. Timeline: 30 days.
- Implement a tiered administrative model. Separate Tier 0 (domain controllers and AD management), Tier 1 (servers), and Tier 2 (workstations) with PAWs (Privileged Access Workstations) for Tier 0 administration. Timeline: 6-12 months for full implementation.[10]
- Enable Credential Guard on all Windows 10/11 workstations and Windows Server 2016+ servers to protect against credential dumping. Timeline: 60 days.
Lessons for Your Organization
If you read this walkthrough and thought "that could be us," you are probably right. Not because your team is negligent, but because AD environments accumulate technical debt at a rate that outpaces most organizations' ability to remediate it.
Start with three actions this week:
- Run
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName,PasswordLastSet | Select Name,ServicePrincipalName,PasswordLastSetto identify your Kerberoastable accounts and how old their passwords are. - Check your domain object's ACL for non-default replication rights:
Get-ACL "AD:\DC=yourdomain,DC=com" | Select-Object -ExpandProperty Access | Where-Object {$_.ObjectType -match "1131f6ad|1131f6aa"} - Download BloodHound Community Edition and run it against your own environment. The paths it reveals will tell you exactly where to focus your hardening efforts.
Four hours is what it took us. A motivated adversary with persistent access might take four days or four weeks, but they will find the same paths. The question is whether those paths will still exist when they look.
Sources
- NetExec - Network Execution Tool (successor to CrackMapExec)
- BloodHound - Active Directory Attack Path Mapping (SpecterOps)
- MITRE ATT&CK - T1558.003: Kerberoasting
- Hashcat - Advanced Password Recovery
- MITRE ATT&CK - T1003.006: DCSync
- MITRE ATT&CK - T1558.001: Golden Ticket
- SpecterOps - BloodHound Versus Ransomware: A Defender's Guide
- AD Security - Cracking Kerberos TGS Tickets Using Kerberoast
- Microsoft - Enterprise Access Model (Tiered Administration)
- Microsoft - Best Practices for Securing Active Directory
How Fast Could We Compromise Your Domain?
We run these exact assessments for organizations across every industry. If your AD environment has not been tested in the last 12 months, let us show you what an attacker would find.
Book a Consultation Our Services