ADGPO-012: cPassword/GPP Password Detection
- Platform
- Active Directory
- Category
- AD Group Policy
- Severity
- Critical
- Zero Trust pillar
- Governance (weight 1)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
Guerrilla enumerates every domain controller via Get-ADDomainController -Filter * and resolves the SYSVOL UNC path for each (\\<dc>\SYSVOL\<domain>\Policies). For each Policies\{GUID} folder it recursively searches the Machine and User subtrees for the six known GPP XML filenames: - Groups.xml (Local Users and Groups) - Services.xml (Services preference) - ScheduledTasks.xml (Scheduled Tasks and Immediate Tasks) - DataSources.xml (Data Sources / ODBC) - Printers.xml (Printers preference) - Drives.xml (Drive Maps) For each XML file located, the check loads the document with [xml] and walks every element selecting nodes that carry a cpassword attribute. Any non-empty value is captured along with the GPO GUID, the GPO display name (resolved via Get-GPO), the path to the file, the element type (User, Group, NewName, runAs, Username, etc.), and the userName / accountName attribute that the recovered password belongs to. The check then performs the AES decryption inline using the documented 32-byte key (4e 99 06 e8 fc b6 6c c9 fa f4 93 10 62 0f fe e8 f4 96 e8 06 cc 05 79 90 20 9b 09 a4 33 b6 6c 1b) and a zero IV, padded to a length divisible by 4 with the Base64 alphabet, and emits both the raw cpassword and the cleartext so the operator can immediately scope the exposure. The check also captures the GPO security filtering and the OUs that the GPO is linked to so the impacted machine set is known.
Why it matters
The GPP cpassword vulnerability is one of the most reliable and lowest-effort privilege escalation paths in Active Directory. Any authenticated domain user has Read on SYSVOL by design (the share is the distribution mechanism for Group Policy, and every client must be able to read it to apply policy). That means any compromised workstation account, any low-privilege service account, any kiosk session, and any unauthenticated attacker who has phished a single user can recover every credential ever embedded in GPP. The credentials are almost always local administrator passwords pushed to a fleet of machines, scheduled task identities running with elevated rights, or service accounts that have been delegated rights on member servers. Once recovered, the credential typically grants local Administrator on hundreds or thousands of machines simultaneously, which yields LSASS dumping on every box, Tier 1 lateral movement, and a short path to a Domain Admin token or a Tier 0 service account hash. Because the XML file remains in SYSVOL even after the corresponding GPP item is deleted from the Group Policy Management Editor (unless the GPO itself is deleted or the file is manually removed), and because the historical files often survive GPO renames and reorganisations, the exposure persists for years past the original administrative action. MS14-025 closed the door on new entries but explicitly did not sweep SYSVOL, and Microsoft documented in the same advisory that existing cpasswords must be located and removed by the administrator.
Attack path
Step 1: Foothold. The attacker holds any authenticated domain context: a phished user, a compromised service account, an over-privileged scanner identity, or an interactive session on any domain-joined host. Step 2: SYSVOL enumeration. The attacker runs Get-DomainGPOLocalGroup, gpp-decrypt, Get-GPPPassword (PowerSploit), or simply dir /s \\<domain>\SYSVOL\*\Groups.xml from a domain-joined client. Tools such as Metasploit smb_enum_gpp, CrackMapExec --gpp-passwords, and the Impacket Get-GPPPassword.py work identically from non-joined attacker hosts holding any valid domain credential. Step 3: Parse and decrypt. The tool reads the XML, extracts the cpassword attribute, base64-decodes after padding, and decrypts with AES-256-CBC using the public Microsoft key and a zero IV. The output is the cleartext password. Step 4: Identify the account. The same XML names the account: userName on Groups.xml, runAs on ScheduledTasks.xml, accountName on Services.xml, username on Drives.xml, and so on. The attacker now has account plus password, fully decrypted, with no cracking. Step 5: Lateral movement. Because the deployed account is almost always a local administrator on every targeted machine (the entire reason GPP was used), the attacker authenticates over SMB with PsExec, WinRM with Invoke-Command, RPC with wmiexec, or a Pass-the-Hash if the NTLM hash is preferred. CrackMapExec smb -u local_admin -p Recovered --shares verifies access on every host in seconds. Step 6: Escalation. With local Administrator on the targeted fleet, the attacker dumps LSASS (procdump, comsvcs.dll, nanodump) to recover cached domain admin tokens, runs Mimikatz sekurlsa::logonpasswords, or pivots via DCSync once a Domain Admin session is captured. Average time from initial SYSVOL read to Domain Admin in red-team engagements where a cpassword is present: under fifteen minutes.
How Guerrilla assesses it
Guerrilla resolves the list of domain controllers from the Get-ADDomainController -Filter * cmdlet, then for each DC opens \\<dc>\SYSVOL\<domain>\Policies and recursively enumerates the six known GPP XML filenames using Get-ChildItem -Recurse -Include with the file list. Each match is parsed as XML and a Select-Xml expression of //*[@cpassword] returns every element carrying the attribute. The check captures the file UNC path, the parent GPO GUID (parsed from the path), the GPO friendly name resolved via Get-GPO -Guid, the element local name (so the operator knows whether the credential belongs to a local user, a service runAs identity, a scheduled task principal, a mapped drive, an ODBC data source, or a printer connection), and the named account from the userName / runAs / accountName / username attribute. AES decryption is performed in-process with the documented MS-GPPREF key so the operator immediately knows what to rotate. The check also queries the GPO link map (gPLink attribute on every OU) and the GPO security filtering DACL so the report can name the OUs and the machine collection actually impacted. Because SYSVOL is replicated via DFSR, reading from a single healthy DC is sufficient in a converged domain, but the check iterates every DC to surface replication-skew anomalies where a stale file persists on one replica.
Recommended value
No cPassword values present in any GPP XML files in SYSVOL
Remediation
Search all SYSVOL GPO folders for XML files containing cpassword attributes in Groups.xml, Services.xml, Scheduledtasks.xml, DataSources.xml, Printers.xml, and Drives.xml. Remove all GPP items that contain stored passwords. Use LAPS, gMSA, or other modern credential management solutions instead. Apply MS14-025 patch to prevent new cPassword creation.
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 |
| known-bad | FAIL |
| throttled | Not Assessed |
Framework mappings
- NIST SP 800-53
- IA-5(1), SC-28
- ANSSI
- vuln_gpp_passwords
- MITRE ATT&CK
- T1552.006, T1552.001