
Four misconfigurations, no CVE: the over-privileged service-account chain that takes a whole forest
The domain compromises that teach the most are the ones with no CVE in them. No memory corruption, no unpatched service, nothing a patch cycle would have closed. Just four ordinary configuration choices that are each defensible on their own and catastrophic in sequence. Follow those four links and you go from one low-value foothold to Domain Admin of an entire forest, and the same chain crosses a forest trust into a second forest on the way. This is the capstone post for a small series: each link has its own deep-dive, and here you learn how they assemble, because the assembly is what you audit against.
What you will learn
- How four independently reasonable settings combine into total forest compromise.
- The order of the chain and the single prerequisite each link needs from the one before it.
- Why attackers reach for configuration rather than exploits, and what that means for defense.
- How to reproduce the whole chain in a lab by stitching together the component labs.
- The one idea that makes defense tractable: you do not fix all four, you break any one on every DC.
Prerequisites and scope: you hold one credential in the first forest and can reach a domain controller in the target forest over a routed path. Every link is a misconfiguration or an over-broad permission, not a bug, so every link closes to a password policy, an ACL, or a group-membership review, not a patch.
The mental model: a chain, not a key
A lot of security teaching frames compromise as finding "the" vulnerability, a single key that opens the door. This chain is the opposite and it is more common in mature environments: no door is forced. Picture a series of rooms, each unlocked from inside the previous one. You are let into room one by a weak password. Room one holds the key to room two. Room two holds the key to room three. Room four is the vault. Nobody picked a lock; every door was opened with a key found in the last room, and every key was left there by a reasonable-sounding decision.
The defensive consequence of that shape is the most important thing in this post: you do not need to lock every door. A chain breaks at its weakest present link, so locking any one door strands the attacker in the previous room. That is why least privilege, not patching, defends against this class.
The chain in one picture
Link 1: a reachable, kerberoastable, weak-password account
A bidirectional forest trust lets a principal in the first forest request service tickets for accounts in the second. That is the trust working as designed. The problem is what it reaches: a service account in the target forest with admincount=1, a Service Principal Name set, and a password a human chose years ago.
impacket-GetUserSPNs 'CORP.LOCAL/held_user:Password1' -target-domain VENDOR.LOCAL \
-dc-ip 10.10.20.5 -request -outputfile roast.hashes
hashcat -m 13100 roast.hashes /usr/share/wordlists/rockyou.txt
Why it works, and the clock and resolution gotchas, are in cross-forest Kerberoasting over a trust (and the in-domain basics in Kerberoasting from Kali). The link exists because a privileged service account kept a crackable password. A managed password breaks this link by itself.
Link 2: ReadGMSAPassword, the delegation nobody audits
The account you just cracked holds ReadGMSAPassword over a Group Managed Service Account. A gMSA is supposed to remove the human-password problem: its password is 240 bytes of machine-managed randomness that rotates automatically. But the directory lets you nominate which principals may retrieve it, and here an ordinary (roastable) account was nominated. So you read the gMSA's current NT hash straight from LDAP, no cracking.
nxc ldap 10.10.20.5 -u svc_sql -p '<cracked>' --gmsa
# -> gmsa_svc$ NT <nthash>
The mechanism and the msDS-ManagedPassword blob are in ReadGMSAPassword. The link exists because the retrieval list was scoped to a non-tier-0 account.
Link 3: the managed account is in a privileged group
A gMSA is only as dangerous as what it can do, and here it is a member of BUILTIN\Server Operators on the domain controller. That group can reconfigure services on a DC (which run as SYSTEM) and it carries SeBackupPrivilege. So the gMSA logs in over WinRM and its token already holds the privilege that ends the game.
nxc winrm 10.10.20.5 -u gmsa_svc$ -H <nthash>
# -> (Pwn3d!) token holds SeBackupPrivilege + SeRestorePrivilege
Why this mild-sounding group is tier-0, and both of its escalation routes, are in Server Operators to Domain Admin. The link exists because a service account was placed in a built-in privileged group instead of being granted one narrow right.
Link 4: the backup privilege reads the directory database
SeBackupPrivilege lets its holder read any file regardless of DACL. On a DC that file is NTDS.dit, which holds every hash including krbtgt. It is locked by the running directory service, so you snapshot the volume, then copy it in backup mode to bypass the lock and the ACL.
diskshadow -> shadow of C: -> expose as Z:
robocopy /B Z:\Windows\NTDS ntds.dit ; reg save HKLM\SYSTEM system.hive
impacket-secretsdump -ntds ntds.dit -system system.hive LOCAL
# -> Administrator hash, krbtgt hash (+AES), every account in VENDOR.LOCAL
The exact sequence and why backup mode beats the lock are in SeBackupPrivilege on a domain controller. With krbtgt the forest is yours. The link exists because a backup-capable privilege reached a non-backup account.
The crossing that did not work (and why that is the lesson)
Faced with the trust, the instinct is to forge a golden ticket in the forest you own and inject the target forest's Enterprise Admins SID through SID history. It fails, and the failure is a control doing its job: forest-trust SID filtering strips injected SIDs with a RID below 1000, and every built-in privileged group sits below that line. A separate trap waits for anyone forging with the RC4 key on a patched DC. Both are in why your cross-forest golden ticket is not admin. The durable takeaway: the crossing that worked was a real credential the trust legitimately let us request, not a forged SID. Attackers reach for configuration because configuration is what is left unlocked.
Build it in a lab
The whole chain is the five component labs stitched together, so build it incrementally and watch each key appear in the next room:
- Two forests with a bidirectional trust, from the cross-forest Kerberoast lab.
- A roastable
svc_sqlin the target forest with a weak password; roast and crack it. - A gMSA whose retrieval list contains
svc_sql; read its hash per the ReadGMSAPassword lab. - Add the gMSA to
Server Operators; confirmwhoami /privshowsSeBackupPrivilegeper the Server Operators lab. - Extract
NTDS.ditper the SeBackup lab.
Then do the exercise that teaches the defense: remove any one link (rotate svc_sql to a managed password, or empty the gMSA retrieval list, or pull the gMSA out of Server Operators) and rerun. Watch the chain die at that step.
Detection, across the chain
No single alert catches this, which is the point. Watch the whole shape:
- Link 1: event 4769 with RC4 (
0x17) for many SPNs from one source, especially across a trust. - Link 2: LDAP reads of
msDS-ManagedPassword(event 4662) by anything but the service's own hosts. - Link 3: membership of built-in privileged groups as a standing inventory, and changes to it (4728/4732/4756).
- Link 4: shadow-copy creation and
diskshadow/robocopy /BagainstNTDS.dit, andSeBackupPrivilegeat logon (event 4672) for a non-backup account.
Feed your own directory to BloodHound and the entire chain renders as a path from svc_sql to the DC before an attacker walks it. The attacker's map and your audit are the same graph.
Prevention: break any one link
- Managed passwords on service accounts, so Link 1 has nothing to crack.
- Scope
ReadGMSAPasswordto tier-0 hosts only; audit the retrieval list like Domain Admins. - Empty the built-in privileged groups (Server Operators, Backup Operators, Account Operators).
- Keep
SeBackupPrivilegeandSeRestorePrivilegeoff anything that is not your backup system, and treat that system as tier-0. - Keep forest-trust SID filtering on and consider selective authentication across the trust.
Each bullet closes one line of the diagram independently. You need any one of them on every DC, which is exactly why least privilege, not patching, defends against this class.
Check yourself
- Why is "break any one link" a stronger defensive frame than "fix every link"?
- Trace what each link hands to the next. What is the single thing Link 2 needs from Link 1?
- Why did the forged cross-forest golden ticket fail where the Kerberoast succeeded?
- A defender has budget to harden exactly one thing on every DC this quarter. Name a defensible choice and say which link it breaks.
Answers:
- Because a chain stops at its weakest present link, so one lock strands the attacker. Fixing all four is ideal but not required; one is sufficient per DC, which makes the problem tractable.
- Each link hands a credential or privilege the next consumes. Link 2 needs exactly the cracked password of
svc_sqlfrom Link 1, becauseReadGMSAPasswordis checked against that principal. - SID filtering stripped the injected built-in SID (RID below 1000), so the ticket authenticated without privilege. The Kerberoast used a real, legitimately issued ticket for a weak account, which the trust was designed to hand over.
- For example, empty Server Operators and Backup Operators (breaks Link 3), or mandate managed passwords on service accounts (breaks Link 1). Either one alone stops this specific chain.
Use
Authorized and educational use only: your own lab, a directory you own, or an engagement with written permission. This is a defensive walkthrough of a documented chain, tools named rather than carried, written so the people who run Active Directory can find this shape in their own environment and break it. It is not a runbook for use against systems you do not own.
References
- MITRE ATT&CK, Kerberoasting (T1558.003): https://attack.mitre.org/techniques/T1558/003/
- MITRE ATT&CK, OS Credential Dumping: NTDS (T1003.003): https://attack.mitre.org/techniques/T1003/003/
- Microsoft, Group Managed Service Accounts overview: https://learn.microsoft.com/en-us/windows-server/security/group-managed-service-accounts/group-managed-service-accounts-overview
- Microsoft, Security Identifiers and SID filtering across trusts: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers
- Microsoft, Protected Users and privileged group hardening: https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/protected-users-security-group