ADGPO-001: GPO Inventory with Link Status
- Platform
- Active Directory
- Category
- AD Group Policy
- Severity
- Info
- Zero Trust pillar
- Governance (weight 1)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
For each Group Policy Object in the domain the check reads: - The GPO DisplayName, Id (GUID), DomainName, CreationTime, ModificationTime, Owner, and gPCFileSysPath - gPCMachineExtensionNames and gPCUserExtensionNames (which client-side extensions are configured) - gPCFunctionalityVersion and versionNumber on both the GPC and the GPT.ini in SYSVOL (GPC / GPT version skew indicates replication or tampering issues) - Every gPLink attribute on every Site, Domain, and OU in the forest, parsed into the GUID of the linked GPO, link order, link enabled flag (bit 0), and enforced flag (bit 1) - GpoStatus (AllSettingsEnabled, UserSettingsDisabled, ComputerSettingsDisabled, AllSettingsDisabled) - WMI filter assignment (gPCWQLFilter) - Security filtering: the DACL on the GPO container, specifically the trustees with ApplyGroupPolicy (extended right edacfd8f-ffb3-11d1-b41d-00a0c968f939) plus Read The output is a single denormalized record per GPO with one row per link, so a GPO linked to three OUs produces three rows, each labeled with the SOM (scope of management) DN, link order, enabled flag, and enforced flag. Unlinked GPOs are reported with a null SOM to make orphan GPOs explicit. The check uses Get-GPO -All for the GPO list, the gPLink attribute on each container for link enumeration (more reliable than Get-GPInheritance, which only reports a single starting OU), and an LDAP read of the GPC DACL for security filtering and delegation.
Why it matters
Group Policy is the primary configuration-management plane in Active Directory and one of the highest-leverage attack surfaces in the forest. A GPO linked to the Domain Controllers OU runs SYSTEM-level code on every DC at the next refresh; a GPO linked to the Domain Root applies to every member computer and user. Attackers who can edit a GPO that targets Tier-0 have a one-step path to domain compromise (T1484.001). Defenders who lack a GPO inventory cannot reason about that risk: they do not know which GPOs target their DCs, which ones are linked-but-disabled (a common attacker staging pattern, because a disabled link can be silently re-enabled), or which ones contain user-rights-assignment, restricted-groups, scheduled-task, or startup-script extensions that warrant deeper review. Orphan GPOs (existing in SYSVOL or the GPC but linked nowhere) are also a finding: they accumulate stale and often forgotten settings, and a malicious operator can link them later to suddenly activate dormant configuration. GPC / GPT version mismatches indicate either FRS / DFSR replication problems or out-of-band tampering directly in SYSVOL. This check produces no severity finding by itself: it is the foundational data set that makes every other ADGPO check actionable.
Attack path
1. Reconnaissance: the attacker enumerates GPOs with PowerView (Get-DomainGPO), SharpHound (-CollectionMethod GPOLocalGroup), or directly via LDAP, and pulls the gPLink attribute on every OU to map which GPOs apply where. BloodHound visualises the GPO -> OU -> Computer / User edges as a graph. 2. Target selection: the attacker prioritises GPOs linked to the Domain Controllers OU, the Domain Root, or OUs containing Tier-0 assets. Linked-but-disabled GPOs are also valued because their settings can be activated without creating a new policy. 3. Edit primitive: with WriteProperty on gPCFileSysPath or the SYSVOL share, or with Edit Settings rights on the GPO, the attacker injects a startup script, a scheduled immediate task, a user rights assignment (SeDebugPrivilege, SeImpersonatePrivilege), or a restricted-groups entry adding their account to local Administrators on every targeted machine. Tools: SharpGPOAbuse, PowerView Set-DomainObject, native Group Policy Management Editor. 4. Link primitive: with WriteProperty on the gPLink attribute of a container (the right hidden behind Manage Group Policy Links delegation), the attacker links an attacker-controlled GPO to a sensitive OU, or re-enables a disabled link on an existing weaponized GPO. 5. Execution: Group Policy refresh on targeted machines (default 90 minutes plus a random offset, or immediate via gpupdate / Invoke-GPUpdate) runs the malicious payload as SYSTEM on every computer in scope. 6. Cleanup: the attacker reverts the GPO content (or the link) after execution, leaving only the GPC versionNumber increment as a trace. Without a pre-incident inventory, the defender has no baseline to diff against.
How Guerrilla assesses it
Guerrilla calls Get-GPO -All to enumerate every GPO in the domain, then walks every OU, the Domain Root, and each Site under CN=Sites,CN=Configuration to read the gPLink and gPOptions attributes. Each gPLink value is parsed into the [LDAP://cn={GUID},cn=policies,cn=system,DC=...] segments and the trailing flag bits (0 = enabled link, 1 = disabled, 2 = enforced) are decoded. For each GPO the check also reads gPCMachineExtensionNames and gPCUserExtensionNames so the consumer can tell at a glance which client-side extensions are configured (Group Policy Preferences, Scripts, Registry, Security, Software Installation). The DACL on each GPO container under CN=Policies,CN=System is read via LDAP and ACEs are emitted with IdentityReference, ActiveDirectoryRights, and the ObjectType GUID, so trustees holding the ApplyGroupPolicy extended right or WriteProperty on the GPO are visible. The check does not require Get-GPInheritance, which short-circuits on inheritance blocks; it walks the tree directly so blocked-inheritance OUs are still represented. Output is suitable for piping into Export-Csv for offline diffing across runs.
Recommended value
Complete GPO inventory documented with link status, scope, and owner for each GPO
Remediation
Generate a full GPO inventory using Get-GPO -All and Get-GPOReport. Document each GPO's purpose, owner, link locations, and enforcement status. Establish a GPO naming convention and ensure all GPOs conform to it. Implement a GPO change management process.
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.
| Scenario | Expected verdict |
|---|---|
| clean | PASS |
| empty-list | WARN |
| throttled | Not Assessed |
Framework mappings
- NIST SP 800-53
- CM-8, CM-8(1)
- MITRE ATT&CK
- T1484.001