ADGPO-002: GPO vacías
- Plataforma
- Active Directory
- Categoría
- AD Group Policy
- Severidad
- Low
- Pilar de Zero Trust
- Governance (peso 0)
- Fixtures de referencia
- 3
- Cobertura de ramas
- Observada: los fixtures prueban los veredictos que ejercitan
- Procedencia
- baseline
Qué comprueba
Las GPO que no contienen ninguna configuración definida (las secciones de configuración de equipo y de usuario están vacías) añaden complejidad innecesaria al procesamiento de la directiva de grupo y pueden indicar tareas de configuración abandonadas o artefactos de pruebas que nunca se depuraron
Por qué importa
Empty GPOs are primarily a hygiene problem, but they have two security relevance vectors. First, they slow down Group Policy processing: every linked GPO must be evaluated by the Group Policy engine on each refresh cycle, and empty GPOs still consume LDAP and SYSVOL round trips. On large estates with hundreds of linked but empty GPOs at the site or domain level, this measurably extends logon time and gpupdate duration, which masks real policy-processing failures in the event log. Second, they are a pre-staged surface for an attacker who gains GPO edit rights through a delegated permission, a misconfigured ACL, or a compromised Group Policy Creator Owners member. Modifying an existing empty GPO does not create a new gPLink, does not generate a "new GPO created" audit event, and inherits whatever links the GPO already has. An attacker can drop a Scheduled Task, Immediate Task, Registry preference, or a malicious startup script into an empty GPO linked at the Domain Controllers OU and have it execute on every DC at the next refresh. Empty GPOs are also a frequent residue of GPP password leakage (CVE-2014-1812): the Group Policy Preferences XML was deleted but the GPO shell was not, and the SYSVOL history may still contain cpassword fragments in backup or older policy versions.
Ruta de ataque
1. Discovery: the attacker, having compromised a user with delegated GPO edit rights or membership in Group Policy Creator Owners, enumerates GPOs with Get-GPO -All and identifies candidates that are (a) empty and (b) linked to a high-value scope. PowerView Get-DomainGPO and BloodHound (CollectionMethod GPOLocalGroup) surface the same data. 2. Target selection: the attacker prefers an empty GPO linked at the Domain Controllers OU, the Domain Root, or a Tier-0 server OU. Because the GPO already has the gPLink, no link change is needed and no SACL on the OU fires. 3. Weaponization: using GPMC, PowerShell (Set-GPRegistryValue, Set-GPPrefRegistryValue), or SharpGPOAbuse, the attacker writes a malicious payload into the GPO. Common payloads are an Immediate Scheduled Task (T1053.005) running as SYSTEM, a logon script that executes a beacon, or a Restricted Groups entry that adds the attacker to the local Administrators group on every target. 4. Replication: SYSVOL replicates the new gPCFileSysPath contents through DFSR to every DC, and the GPO version number increments. Because the GPO already existed, the change appears in audit logs as a GPO modification on an old object rather than a new GPO creation. 5. Execution: targeted machines pick up the policy at the next refresh cycle (90 minutes by default plus a 30-minute randomization, immediate on next reboot for startup scripts). On the Domain Controllers OU, this is code execution as SYSTEM on every DC. 6. Cleanup: the attacker reverts the GPO to empty after execution, leaving the GPO display name and link unchanged. To a defender skimming GPMC, nothing has changed.
Cómo lo evalúa Guerrilla
Guerrilla loads the GroupPolicy module, calls Get-GPO -All -Domain $env:USERDNSDOMAIN, then for each GPO calls Get-GPOReport -Guid $gpo.Id -ReportType Xml. The XML is parsed with [xml] cast and the Computer.ExtensionData and User.ExtensionData nodes are inspected. A GPO is classified as empty when neither half contains an Extension node with at least one child policy element. The check pulls supplementary metadata from the GPO object itself (CreationTime, ModificationTime, GpoStatus, Computer.DSVersion, User.DSVersion, Computer.SysvolVersion, User.SysvolVersion) and resolves linked scopes via Get-ADOrganizationalUnit -LDAPFilter "(gPLink=*$($gpo.Id)*)" plus the domain root and Sites container. Output rows include DisplayName, Id, IsEmpty (bool), GpoStatus, IsLinked (bool), LinkedScopes (string array), CreationTime, ModificationTime, and a Notes field that calls out the high-risk combinations: empty plus linked to DC OU, empty plus linked to Domain Root, empty plus all settings disabled, and empty plus modified within the last 30 days.
Valor recomendado
Ninguna GPO vacía en el dominio; todas las GPO contienen al menos una configuración definida
Remediación
Identifique las GPO sin configuraciones definidas con Get-GPOReport en formato XML y comprobando si hay elementos ExtensionData vacíos. Verifique que las GPO vacías no sean marcadores de posición para uso futuro. Elimine las GPO realmente vacías tras confirmar que no están referenciadas por ninguna automatización ni documentación.
Veredictos probados con fixtures
Cada veredicto de esta tabla está probado por un fixture de referencia en la suite de pruebas que valida el módulo. La tabla se deriva de la última ejecución en verde; no puede editarse a mano.
| Escenario | Veredicto esperado |
|---|---|
| clean | PASS |
| known-bad | WARN |
| throttled | Not Assessed |
Mapeos a marcos de referencia
- NIST SP 800-53
- CM-2, CM-7
- MITRE ATT&CK
- T1484.001