ADSCRIPT-004: Hardcoded Credentials in Scripts

Platform
Active Directory
Category
AD Logon Scripts & Network Shares
Severity
Critical
Zero Trust pillar
Applications & Workloads (weight 2)
Golden fixtures
3
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check enumerates every file under \\<domain>\NETLOGON and \\<domain>\SYSVOL\<domain>\scripts (and the broader SYSVOL policies tree) that has a script extension or is referenced by a User scriptPath attribute, a Group Policy logon / startup script, or a scheduled task action. Targeted extensions include .bat, .cmd, .ps1, .psm1, .vbs, .js, .wsf, .kix, .pl, .py, .ini, .xml, .config, and .reg. For each file the content is read with a low-privilege session and matched against a curated regex set: - net use ... /user:DOMAIN\name password - password=, passwd=, pwd= (case insensitive, common config syntaxes) - credential / secret / apikey / api_key / token / bearer - ConnectionString= containing User Id= and Password= - runas /user: ... with a literal password following - PsExec.exe -u -p <literal> - Group Policy Preferences cpassword= (separate ADGPO check, cross-referenced here) - PowerShell ConvertTo-SecureString -AsPlainText where the source string is a literal - Base64-encoded blobs adjacent to credential keywords Matches are emitted with the UNC path, file size, last write time, ACL summary, line number, and the matched keyword. The check does not exfiltrate the secret itself, only the keyword and surrounding 16 bytes of redacted context, so the audit log is safe to forward to a SIEM.

Why it matters

NETLOGON and SYSVOL are replicated to every domain controller and are readable by Authenticated Users by design, because the client-side extensions and the Group Policy engine need to read them on behalf of every signed-in account. There is no ACL boundary you can apply on the share without breaking logon for the entire domain. A password placed in a logon script is therefore equivalent to publishing it on an internal wiki that has zero access control. Attackers know this and treat SYSVOL enumeration as a first-hour action on every engagement: SharpHound, snaffler, ManySweeper, and the original Get-GPPPassword from PowerSploit all pivot through the share. The credentials that typically surface are service account passwords (often with SeServiceLogonRight and membership in a privileged group), SQL sa accounts, vendor backup accounts with local administrator rights across the fleet, and API tokens for ITSM or monitoring platforms with domain-wide reach. Once harvested, the credential gives the attacker a non-interactive logon path that bypasses MFA, survives password resets of the compromising user, and is rarely covered by conditional access. The blast radius is the privilege level of whatever account the script was authenticating as, which in practice is frequently Domain Admin or local administrator on every workstation.

Attack path

1. Initial foothold: the attacker authenticates as any domain user (phishing, password spray, vendor account, or a domain-joined workstation they sit on). 2. Share enumeration: the attacker mounts \\<domain>\SYSVOL and \\<domain>\NETLOGON. No special tooling required; net view and dir suffice. Snaffler (https://github.com/SnaffCon/Snaffler) and ManySweeper automate the walk with regex matching tuned to credentials. 3. Pattern matching: the attacker grep / Select-String for the same keyword set the auditor uses (password, pwd, cpassword, apikey, ConnectionString, ConvertTo-SecureString). Findings are usually present within seconds because the corpus is small and the patterns are unambiguous. 4. Credential extraction: literal passwords are copied as-is. Group Policy Preferences cpassword values are decrypted with the published AES-256 key (Get-GPPPassword, gpp-decrypt) in milliseconds. Base64 or weakly obfuscated blobs are reversed with one-liners. 5. Lateral movement: the harvested credential is replayed with runas, PsExec, WinRM, or impacket-wmiexec. Service accounts with SeServiceLogonRight on multiple hosts give the attacker a fleet-wide foothold without ever touching a user workstation. 6. Privilege escalation: if the script ran as a member of Domain Admins, Backup Operators, Account Operators, or any group with replication rights, the attacker proceeds directly to DCSync (secretsdump.py -just-dc) and forges a Golden Ticket from the krbtgt hash. 7. Persistence: the attacker leaves the original script in place (so defenders see no change) and uses the harvested credential as a long-lived backdoor. Rotation of the user who first compromised the domain has no effect on this path.

How Guerrilla assesses it

Guerrilla resolves the domain SYSVOL and NETLOGON UNC paths from the LDAP rootDSE (configurationNamingContext -> CN=Sites,CN=Configuration ... and the dnsHostName of the closest DC), then uses Get-ChildItem -Recurse -Force across the replicated content with an explicit extension allowlist. Each candidate file is read once and matched against the credential regex set described above. The walker honors a size cap (default 5 MB) to avoid stalls on large binary blobs that legitimately live under Policies. Findings include the UNC path, the share ACL (read via Get-Acl), the file owner, the last modifier (where SACL auditing is enabled, correlated to event 4663), the matched keyword, and the line number. The captured secret value itself is replaced with a SHA256 hash in the output so the report can be archived without re-exposing the credential. The check also cross-references the User class scriptPath attribute and Group Policy CSE references so a credential bearing file that has been removed from SYSVOL but is still referenced by an account or a policy is surfaced as a separate finding.

Recommended value

No hardcoded credentials, passwords, or API keys in any NETLOGON or SYSVOL scripts

Remediation

Scan all scripts in NETLOGON and SYSVOL for patterns indicating credentials: password, passwd, pwd, credential, secret, apikey, token, connectionstring, and similar keywords. Replace hardcoded credentials with secure alternatives such as Windows Credential Manager, gMSA accounts, or encrypted configuration files with restricted access. Rotate any credentials found in scripts immediately.

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 ADSCRIPT-004
ScenarioExpected verdict
cleanPASS
known-badFAIL
throttledNot Assessed

Framework mappings

NIST SP 800-53
IA-5(1), SC-28, IA-5(7)
ANSSI
vuln_cleartext_password
MITRE ATT&CK
T1552.001, T1059