ACL Paths in Active Directory: From Helpdesk to Domain Admin
Cybersecurity
BloodHound's value is showing the chain of ACEs that turns a junior helpdesk account into a domain compromise. We cover the rights to hunt, the events to log, and the cleanup that breaks the path.
By Arjun Raghavan, Security & Systems Lead, BIPI · November 29, 2024 · 8 min read
Most domains have between 50,000 and 500,000 access control entries. BloodHound's job is to find the dozen ACEs that compose into a path from a low-priv account to a Domain Admin. We have seen seven-hop chains starting from a printer maintenance account and ending at krbtgt. The chain is never one bad permission. It is a sequence of small, reasonable-looking grants stitched together over a decade.
How attackers find this
BloodHound is the canonical tool. The new BloodHound CE replaces the legacy BloodHound 4.x and uses the same Cypher queries against a Neo4j graph.
- Collect with SharpHound.exe -c All,GPOLocalGroup --ldapusername user --ldappassword pass. The collector enumerates objects, ACLs, sessions, and group memberships.
- Or use bloodhound.py -c All -u user -p pass -d domain.local -dc dc01.domain.local from a Linux host without dropping a binary on the network.
- The query that produces the report finding: Find Shortest Paths to Domain Admins from Owned. After importing the collection, mark a low-priv account as Owned and let BloodHound compute the chain.
- Common high-impact ACEs: GenericAll on a user (full control: reset password, modify any attribute), GenericWrite (write any attribute, including msDS-AllowedToActOnBehalfOfOtherIdentity for RBCD), WriteDACL (rewrite the ACL itself), WriteOwner (take ownership then grant rights), and ForceChangePassword (reset without knowing the old password).
- Exploit ForceChangePassword with NetExec: nxc smb dc01 -u helpdesk -p pass -M change-password -o USER=target_user NEWPASS=Summer2024!. The new password is set without prompting and the original user is locked out of their account next time they log in.
The pattern that produces real findings is delegation done by clicking. A 2018 ticket said helpdesk needs to reset passwords for the support OU, an admin clicked Delegate Control, and the resulting ACE applied to the entire support OU including a stale account that was later moved into a privileged group. BloodHound finds this in seconds.
What defenders see
Directory Service Changes auditing is off by default in older domains. Turning it on is the prerequisite. Once enabled, 5136 events fire on every modification to AD objects.
- Hunt 5136 events where the modified attribute is nTSecurityDescriptor on tier-0 objects (Domain Admins, Enterprise Admins, krbtgt, AdminSDHolder). Any change here outside a documented project is incident-worthy.
- 4738 user account changed events that show password resets where the SubjectUserName is not the same as the TargetUserName indicate a privileged user resetting another's password. Most are legitimate helpdesk activity. Outliers (resetting a privileged account) are the alert.
- 5145 detailed file share access on SYSVOL with WriteData rights from non-admin accounts catches GPO-based persistence attempts.
- Use BloodHound defensively. Run a weekly collection from a service account, diff the Owned-to-DA path counts, and alert on new paths. The defensive equivalent of pentest reconnaissance is the same query.
Remediation
ACL cleanup in a mature domain is a project, not a sprint. The order matters: protect tier-0 first, then prune the rest.
- Audit AdminSDHolder. Anything there propagates to all protected groups every hour. Remove non-default ACEs immediately. Get-Acl 'AD:CN=AdminSDHolder,CN=System,DC=domain,DC=local' is the starting point.
- Identify every account with explicit ACEs on tier-0 objects (DCs, Domain Admins group, krbtgt). The list should be empty except for the BUILTIN admin groups. Anything else is a delegation that needs justification or removal.
- Run Find Shortest Paths to Domain Admins from Everyone in BloodHound. For each edge in the resulting paths, decide: keep with documentation, replace with a more restrictive ACE, or remove. This is months of work but produces a map.
- Use Microsoft's Tiered Administrative Model and Authentication Policy Silos to prevent tier-0 accounts from logging into lower-tier hosts. This breaks paths even if the ACE is still wrong, because the privileged credential never lands on a host the attacker controls.
- Implement a quarterly BloodHound diff process owned by the AD team, not the pentest team. The detection of new paths is a continuous control, not an annual finding.
Every ACE in your domain is the result of a request that someone said yes to. The cleanup is the audit of those yeses.
After serious ACL hygiene, the BloodHound report for a low-priv user shows zero paths to Domain Admin. We have driven this number from sixteen to zero on a 40,000-user domain. It took 14 months. The result is that the next pentester has to find a different path, and most of them do not.
Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.