AD-PATH-001: Control paths from non-tier-0 principals to tier 0¶
high Attack paths MITRE ATT&CK T1098, T1484 Reads: derived from other findings
Principals outside tier 0 have a chain of memberships, ACLs, GPO, certificate or delegation rights that ends in control of tier 0.
Also known as: attack-paths, tier0-paths
Why it matters¶
Single checks look at one object at a time. Attackers do not: they chain whatever they find. A help desk group with reset password on a server admin, who is local admin on the Entra Connect server, which holds the sync account's password, which can DCSync, is four ordinary-looking delegations and one domain compromise.
Any principal with such a chain is tier 0 whether or not it is in an admin group: its password, its sessions and every machine it logs on to are as valuable as a domain admin's. Attack tools such as BloodHound find these paths in minutes.
How ad-doctor detects it¶
ad-doctor builds a control graph from the snapshot, without a graph database. An edge A -> B means A controls B or can become B:
| Edge | Source |
|---|---|
member of |
group member, including memberships a GPO writes through the DCs |
owns, takeover rights (full control, write/WriteDacl/WriteOwner, write msDS-KeyCredentialLink, reset password, ...) |
owner and ACEs on users, computers, groups, OUs and the domain head |
... (inherited), contains |
inheritable ACEs on OUs and containers, and control of a container over what is below it; AdminSDHolder-protected objects are excluded |
DCSync |
both replication rights on the domain head |
link GPOs, linked to domain |
write access to gPLink, and GPO links to the domain or the Domain Controllers OU for a GPO that reaches a writable DC |
GPO applies to, GPO inherited by, GPO reaches |
whoever can write a GPO controls what it applies to: from the GPO through its links on OUs, the domain head and sites, down the OU tree to computers and users |
admin to via GPO ... |
local administrator (or equivalent) groups set by Group Policy; admin on a computer becomes that computer account |
hosts sync account |
an Entra Connect server holds its sync account's password |
enroll (ESC1-3), write template (ESC4), full control on PKI objects, ManageCA (ESC7) |
certificate templates, PKI containers and CA permissions |
read gMSA password |
msDS-GroupMSAMembership |
Tier 0 is the built-in admin and operator groups, domain controllers, krbtgt, the domain
head, the Domain Controllers OU, AdminSDHolder, CA servers and the PKI objects. A reverse
breadth-first search from tier 0 gives the shortest path from every other principal.
Each object is one principal that holds a right itself, with its shortest path, broad groups first, for example:
Domain Users -[enroll (ESC1-3)]-> template LabESC1
LabServerAdmins -[admin to via GPO LabLocalAdmins]-> ENTRA01$ -[hosts sync account]-> MSOL_0a1b2c3d4e5f -[DCSync]-> corp.example
GPO reach follows Group Policy, not containment. Disabled links, Block Inheritance and
Enforced count, because they sit on the OU and the writer of a GPO cannot change them. What
sits on the GPO does not hold its writer back: a disabled computer or user side stays in the
graph, with a caveat in the path text, because the writer can flip the flags attribute. A
security filter stops a writer of values, but not one who owns the GPO or can rewrite its
DACL: that path runs through a node GPO ... with its filter changed. A filter naming a group
the snapshot does not hold (another domain's, or one not readable) cannot be judged, so the
GPO is assumed to apply, with a caveat and a note naming it. Since MS16-072 Windows fetches
user policy as the computer, so user-side reach also needs some computer to be able to read
the GPO.
A GPO that reaches only a read-only DC gets no linked to domain edge, because an RODC cannot
write the domain; an RODC itself counts as tier 0, so the path to it stays. A GPO reaches
computers and users, not groups or the OU itself, and it does reach objects with inheritance
disabled. The steps between the GPO and the account are scope nodes such as users under Lab:
gpo_editor -[full control]-> LabOuReach -[GPO applies to]-> users under Lab -[GPO reaches]-> svc_sql
Members who only inherit a path through a group are counted in the detail ("19 of 20 enabled users (95%) have a path") instead of being listed. Remote logon rights a GPO grants (RDP, WinRM, DCOM) are exported to BloodHound but not followed, because logon is not control.
Attributes and probes read
membernTSecurityDescriptor (owner, ACEs, inheritable ACEs)gPLinkGPO local group settings in SYSVOLcertificate template and CA ACLsmsDS-GroupMSAMembership
Severity¶
Always high: every path reported ends in control of a tier-0 object, so the start of the path is in effect tier 0. The detail adds when a broad group (Domain Users, Authenticated Users, Everyone and similar) has a path, which makes every user tier 0.
False positives and limits¶
- Intended delegations into tier 0, such as the Entra Connect sync account's DCSync right. The path is real; the fix is to treat the start of it as tier 0 (see AD-PRIV-011). Accept it only after that, in an accepted-risk file.
- Local accounts and local groups on servers are invisible over LDAP, so paths through them are missed rather than over-reported; the same goes for sessions and logons.
- GPO reach assumes WMI filters match (the path shows the caveat), ignores Deny ACEs on the GPO, and assumes a user in scope logs on somewhere. Empty GPOs and disabled sides count, because the writer fills them in or turns them on. It can also miss: loopback processing is not modelled, and with more than one site, site links are followed only to the domain controllers of that site (the scan says so in a note). A DC whose site is unknown counts as reached, with a caveat.
- Deny ACEs that cancel an allow are not modelled; a reported ACL step may be blocked in practice. Confirm with the steps below before removing a right in a hurry.
Fix¶
-
Start with broad groups and the shortest paths. A path from Domain Users or Authenticated Users makes every account tier 0, so it comes first in the list.
-
See what one principal can reach, from a saved snapshot:
-
Break each path at its first step: remove the ACE, the group membership, the GPO edit right, the template enrollment right or the local admin grant that starts it. The single check named in the step usually says how, for example AD-ACL-004, AD-GPO-006 or AD-ADCS-001. Review an ACE before removing it:
-
Where the step cannot be removed, promote its start to tier 0: move the account or server under tier-0 administration, with the same logon restrictions as domain admins.
-
Explore the graph in BloodHound when many paths share steps:
See BloodHound export.
Verify¶
To accept the risk instead, add an entry to the file passed with --accept (see accepted risks):
[[accept]]
check = "AD-PATH-001"
objects = ["..."] # optional; without it the whole check is accepted
reason = "..."
expires = 2027-03-31
Related checks¶
- AD-ACL-001
- AD-ACL-004
- AD-ACL-007
- AD-ACL-008
- AD-GPO-004
- AD-GPO-006
- AD-ADCS-001
- AD-ADCS-013
- AD-ACL-006
References¶
Microsoft and vendors
- Enterprise access model
- Implementing least-privilege administrative models
- Deploying Group Policy Security Update MS16-072 (AskDS)
Research
Tools
MITRE ATT&CK
Available since 0.1.0.