ADGPO-005: Duplicated GPOs

Platform
Active Directory
Category
AD Group Policy
Severity
Low
Zero Trust pillar
Governance (weight 1)
Golden fixtures
3
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check loads the full GPO inventory collected by Invoke-ADAudit from the domain (each GPO carries DisplayName, GUID, and DN harvested from CN=Policies,CN=System,DC=<domain>). For every GPO it tests the DisplayName against two regular expression patterns: (1) [\s_-]*(copy|backup|old|v\d|test|temp|clone|dup), which captures suffixes like " - Copy", "_backup", "_old", "_v2", "-test", "_temp", "_clone", "_dup"; and (2) \s*\(\d+\)\s*$, which captures the Windows duplicate-paste suffix " (1)", " (2)", and so on. When a match is found, the check strips the suffix to derive a candidate base name and searches the remaining GPO set for an exact DisplayName match with a different GUID. If a sibling exists, both GPOs are reported as a potential duplicate pair. The check raises WARN when at least one pair is found and PASS when no patterns match across the full GPO set. The check does not yet perform full settings-diff via XML report comparison; that is an extension hook for future hash-based deduplication.

Why it matters

Duplicate GPOs are a low-severity finding but they create real operational and security pain. First, every additional GPO that a computer or user processes during logon adds CSE (Client Side Extension) evaluation time and increases the chance of gpupdate failures. Second, when two GPOs with overlapping settings are linked at different OU depths or with different enforcement and block-inheritance flags, the precedence outcome becomes hard to predict; troubleshooting "why is this setting not applying" turns into a multi-hour RSoP exercise. Third, the duplicate pattern is a known attacker hiding spot: an adversary with GPO edit rights (see ADGPO-001 GPO permissions checks) can drop a malicious scheduled task or service definition inside an unlinked "Policy_backup" object that a future admin may relink without reviewing. Fourth, duplicates inflate SYSVOL replication volume and DFSR queue depth on every domain controller. The blast radius is bounded (this is configuration drift, not direct privilege escalation), but the finding is a reliable indicator of weak Group Policy change-control discipline, which correlates with higher-severity findings elsewhere in the ADGPO category.

Attack path

Duplicated GPOs are not directly exploited; they enable two adjacent attacker behaviors. Scenario 1 (hidden persistence). An attacker who has compromised an account with GPO edit rights on a duplicated, unlinked policy (for example "Workstation Hardening_backup") edits the backup to add a malicious Immediate Scheduled Task or a Group Policy Preferences (GPP) registry value. Because the policy is not linked, gpresult and routine RSoP exports do not surface the change. The attacker waits, or socially engineers an administrator into relinking the backup as part of a rollback exercise, at which point the malicious settings activate against every computer in the target OU. This pattern is described in the T1484.001 references and is functionally identical to the "evil GPO" sub-technique tracked by Mandiant and SpecterOps. Scenario 2 (config drift exploitation). Two near-duplicate GPOs assign conflicting settings (for example one enables LSA Protection / RunAsPPL and the duplicate does not). Depending on link order, block-inheritance, and enforced flags, the weaker setting wins on a subset of machines. Attackers fingerprint endpoints via Get-GPResultantSetOfPolicy or local registry reads and target the hosts that received the weaker policy with credential-theft tools (Mimikatz, LSASS dumping). In both scenarios the duplicate itself is not the vulnerability; it is the cover that lets a real change land without being seen. Removing duplicates closes the cover.

How Guerrilla assesses it

Guerrilla collects the GPO inventory during Invoke-ADAudit by enumerating (objectClass=groupPolicyContainer) objects under CN=Policies,CN=System,DC=<domain> over LDAP, capturing DisplayName, cn (the GUID), DN, gPCFileSysPath, gPCMachineExtensionNames, and gPCUserExtensionNames. ADGPO-005 then iterates the in-memory GPO list and applies the two regex patterns (suffix words and parenthesized counter) to each DisplayName. For each match it strips the suffix to produce a candidate base name and searches the remaining list for a different-GUID GPO with that exact DisplayName. Pairs are accumulated into a PotentialDuplicates collection that includes the duplicate DisplayName, GUID, the inferred BaseName, and the matching regex Pattern. The detection logic runs entirely against cached LDAP data and does not require Group Policy Management Console, the GroupPolicy PowerShell module, or RSAT on the analyst workstation. The check returns WARN with the count and the list of duplicate DisplayNames when at least one pair is found, PASS with the total GPO count when none are found, and SKIP when GPO data is not present in the audit bundle.

Recommended value

No duplicate GPOs; each GPO has a unique purpose and non-overlapping settings

Remediation

Export all GPO reports in XML format and compare settings across GPOs to identify duplicates. Consolidate duplicate GPOs into a single GPO where possible. Update OU links to reference the consolidated GPO. Test the consolidated GPO in a staging OU before removing the duplicates.

Fixture-proven verdicts

Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.

Verdict scenarios for ADGPO-005
ScenarioExpected verdict
cleanPASS
known-badWARN
throttledNot Assessed

Framework mappings

NIST SP 800-53
CM-2, CM-3
MITRE ATT&CK
T1484.001