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_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:

The Timeline: Four Steps in Four Hours

Let us summarize the kill chain with exact timestamps:

  1. 09:00 - 09:28 (28 minutes): LDAP enumeration and BloodHound graph collection. Identified the attack path.
  2. 09:35 - 09:40 (5 minutes): Kerberoasted 14 service accounts.
  3. 09:40 - 10:45 (65 minutes): Cracked 6 of 11 RC4 hashes, including svc_sqlreport.
  4. 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.

Step 2: Kerberoasting

Step 3: Excessive Privileges (DCSync Rights)

Step 4: Golden Ticket Forgery

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:

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:

  1. 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.
  2. Audit and remediate DCSync privileges. Remove the "Replicating Directory Changes All" right from all non-DC accounts. Timeline: immediate.
  3. 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.
  4. 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]
  5. 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:

  1. Run Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName,PasswordLastSet | Select Name,ServicePrincipalName,PasswordLastSet to identify your Kerberoastable accounts and how old their passwords are.
  2. 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"}
  3. 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.


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
-- views
Link copied!
Lorikeet Security

Lorikeet Security Team

Penetration Testing & Cybersecurity Consulting

We've completed 170+ security engagements across web apps, APIs, cloud infrastructure, and AI-generated codebases. Everything we publish here comes from patterns we see in real client work.