ACL Abuse (DACL)
Full command arsenal in the cheatsheetIn Active Directory every object (users, groups, computers, GPOs, the domain object itself) carries a security descriptor, and inside it a DACL (Discretionary Access Control List): the list of ACEs (Access Control Entries) that defines who can do what to that object. When those permissions are granted too liberally (to an ordinary user, to an overly broad group, through inheritance), they stop being configuration and become an escalation path that relies on no exploit at all: just on using the right that shouldn't be there.
The model, concretely. The DACL lives in the object's nTSecurityDescriptor attribute and is readable over LDAP with any domain account. Each ACE binds a principal (who) to a right (what) over the object (where). That is exactly what BloodHound collects and draws: it turns thousands of ACEs into a graph and answers the key question, what is the shortest path from where I am to Domain Admin by chaining misconfigured permissions.
The abuses, each with its own page. Depending on the exact right BloodHound draws, the abuse changes:
- GenericAll: full control. Over a user, reset their password or plant Shadow Credentials; over a group, add yourself; over a computer, configure RBCD.
- GenericWrite: write non-protected attributes. Inject an SPN for a targeted Kerberoasting, plant Shadow Credentials or set a logon script.
- ForceChangePassword: change another user's password without knowing the old one. A direct horizontal pivot.
- WriteDACL: rewrite the object's own DACL, i.e. grant yourself any other right (typically the replication rights for a DCSync).
- WriteOwner: change the object's owner; the owner can always rewrite the DACL, so it is a two-step path to full control.
- AddMember /
WritePropertyonmember: add yourself to a privileged group.
How it plays out in practice. The flow is always the same: enumerate the writable ACEs, abuse the one you want and verify the new state instead of assuming it.
# enumerate what rights a principal we control holds (PowerView)
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs |
? { $_.SecurityIdentifier -eq (Get-DomainUser <me>).objectsid }# write/read ACEs from Linux (Impacket): owner and DACL
owneredit.py -action write -new-owner <me> -target <target> <domain>/<me>:<pass>
dacledit.py -action write -rights <right> -principal <me> -target-dn <DN> <domain>/<me>:<pass>bloodyAD and net rpc cover the same primitives with different syntax. The rigour rule: after every abuse that changes state, a short check (a login, Get-ADUser, net rpc group members, an LDAP query of the DACL) is the proof the permission took effect.
Nuance. BloodHound flagging an edge does not guarantee it is exploitable here and now: it may depend on the target's password, on the account being enabled, on inherited permissions a GPO reverts, or on delegation conditions. The edge is the hint; the verified abuse is the proof.
How to detect it. ACL abuse is not caught on the read (enumerating the DACL over LDAP is indistinguishable from a legitimate query), but on the write and on the subsequent use. Changing a DACL or an owner generates Event ID 5136 (a directory service object was modified) and 4670 (permissions on an object were changed); the concrete effect adds its own event depending on the abused right: password reset 4724, group addition 4728/4732/4756, replication 4662. All of it requires enabling Audit Directory Service Changes with SACLs on the Tier-0 objects. The strategy that works is correlating by actor: a low-privilege user that within minutes modifies a DACL and exercises the freshly granted right is the signature of the chain. Proactively, running BloodHound defensively finds the paths before the attacker does.
Defence. Least privilege on the ACEs, with special focus on the domain object and the DC account (where a WriteDACL equals DCSync). Review groups that are suspicious by design (Account Operators, Exchange Windows Permissions) and prune ACEs that are inherited or over-granted before they become a path.