ADTRADE-001: Group Policy Preferences cpassword Leftovers in SYSVOL

Platform
Active Directory
Category
AD Adversary Tradecraft Indicators
Severity
Critical
Zero Trust pillar
Visibility & Analytics (weight 2)
Golden fixtures
3
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check recursively scans the Policies subtree of every domain SYSVOL share and inspects every Group Policy Preferences XML file for the cpassword attribute. The relevant files, all under \\<domain>\SYSVOL\<domain>\Policies\{GUID}\(Machine|User)\Preferences\, are: - Groups.xml (local users and groups, including the "Add a local Administrator" preference) - ScheduledTasks.xml (scheduled tasks and immediate scheduled tasks with a run-as account) - Services.xml (service account credentials) - DataSources.xml (ODBC data source connection strings) - Printers.xml (printer connection credentials) - Drives.xml (mapped drive credentials) For each XML file that matches, the check captures: the full UNC path of the XML, the GPO GUID extracted from the path, the resolved GPO DisplayName via the Group Policy Container in AD, the userName / runAs / accountName attribute from the same XML node, the literal cpassword value, and the file LastWriteTime so the operator can correlate against the era when the preference was created. The check does not decrypt the cpassword in place: it reports presence. Decryption is trivial (the 32-byte AES key is constant and public) but is left to the remediation workflow so the artefact and the credential rotation can be tracked separately. The scan walks SYSVOL using SMB on the PDC emulator by default, which avoids DFSR replication races.

Why it matters

cpassword is the textbook example of a "patched but not remediated" vulnerability. MS14-025 closed the door on creating new GPP secrets, but the patch deliberately did not touch existing XML in SYSVOL because Microsoft could not safely guess which credentials were still in production use. Years later, the original administrators have left, the documentation is gone, and the XML is still there. The recovery is one-sided: any authenticated user (every domain account, including low-privileged service accounts, kiosk accounts, and helpdesk accounts) has Read access to SYSVOL by design, so the credentials are effectively published to the entire user population. The static AES-256 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) is documented in MS-GPPREF section 2.2.1.1.4 and is hard-coded into PowerSploit, Metasploit, Empire, and every red-team primer. The blast radius depends on what the preference set up: local Administrator accounts on every workstation, a service running as a tier-0 account, or a scheduled task running as Domain Admin all turn into immediate forest compromise. Because the data is exfiltrated by a normal LDAP / SMB read it generates no anomalous telemetry and is one of the first things every adversary checks during initial recon. This is why it is classified as a Tradecraft Indicator rather than a configuration finding: the presence of these files is high-signal evidence that the environment has not had an adversarial review.

Attack path

1. Initial access: the attacker has any authenticated domain identity. A guest contractor account, a phished helpdesk account, or a low-privilege service account is sufficient. No special rights are required. 2. SYSVOL enumeration: the attacker connects to \\<domain>\SYSVOL\<domain>\Policies and recursively lists XML files. PowerSploit ships Get-GPPPassword, which does this in one line: Get-GPPPassword. Metasploit has post/windows/gather/credentials/gpp. Impacket ships Get-GPPPassword.py for non-Windows operators. 3. cpassword harvest: the tool greps the XML for cpassword= and captures the surrounding userName / runAs attribute so the operator knows which account the credential belongs to. 4. Offline decryption: the cpassword is base64-decoded, the trailing equals signs are padded if needed, and the result is AES-256-CBC decrypted with the published 32-byte key and a zero IV. The plaintext password drops out. No interaction with the domain is needed for this step; it is a pure offline operation. 5. Lateral movement: with the recovered credential the attacker logs into whatever the GPP preference managed. Common high-value cases: a "Local Admin password reset" preference that set the same local Administrator password on every workstation (full lateral movement primitive), a scheduled task running as a Tier-0 account (instant Tier-0 compromise), or an SQL service account that turns out to be a domain admin. 6. Persistence: even after the credential is rotated, the attacker may relink or re-stage a malicious GPP preference using a different XML name, betting that defenders will only audit the names they have already seen.

How Guerrilla assesses it

Guerrilla resolves the PDC emulator with Get-ADDomain, then enumerates every Group Policy Container under CN=Policies,CN=System and constructs the SYSVOL UNC for each GPO. It performs a recursive Get-ChildItem against \\<pdc>\SYSVOL\<domain>\Policies filtered to *.xml, then runs Select-String for the literal token "cpassword" against the contents of each file. For matches it parses the XML with [xml] and extracts the cpassword node attribute plus the sibling userName, runAs, accountName, or newName attribute depending on the preference type, and records the GPO GUID parsed from the file path, the LastWriteTime of the XML, and the file owner where available. The check deliberately uses the PDC emulator copy of SYSVOL to avoid DFSR replication windows producing inconsistent results across DCs. The check does not write to SYSVOL and does not decrypt; it only reads. A clean run returns zero rows. Any non-zero result is a Critical finding.

Recommended value

Zero cpassword attributes anywhere under \\domain\SYSVOL\domain\Policies\**\*.xml.

Remediation

Scan SYSVOL: Get-ChildItem -Path \\<domain>\SYSVOL\<domain>\Policies -Recurse -Include *.xml | Select-String 'cpassword'. For each match: (1) rotate the password of the account whose credential is exposed (the username is in the same XML), (2) audit logs for use of that credential since the preference was created, (3) delete the GPP preference once the new credential is in place. Microsoft's KB2962486 has the cleanup guidance.

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 ADTRADE-001
ScenarioExpected verdict
cleanPASS
known-badFAIL
throttledNot Assessed

Framework mappings

NIST SP 800-53
IA-5, AC-6
CIS AD Benchmark
10.1.1
MITRE ATT&CK
T1552.006