ADPWD-016: LAPS Deployment Status
- Platform
- Active Directory
- Category
- AD Password & Lockout Policies
- Severity
- High
- Zero Trust pillar
- Identity (weight 2)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
The check binds to a writable DC and queries the default computer NC for every objectClass=computer where operatingSystem starts with "Windows" and the object is not disabled. For each computer it reads the following attributes in a single LDAP search: - msLAPS-Password (Windows LAPS, clear-text, base64-wrapped JSON containing the account name and password) - msLAPS-EncryptedPassword (Windows LAPS, DPAPI-NG encrypted, when encryption is enabled) - msLAPS-EncryptedPasswordHistory (rotation history when configured) - msLAPS-PasswordExpirationTime (next scheduled rotation, FileTime) - ms-Mcs-AdmPwd (legacy LAPS, clear-text only) - ms-Mcs-AdmPwdExpirationTime (legacy LAPS expiration, FileTime) - lastLogonTimestamp, pwdLastSet, operatingSystem, operatingSystemVersion (for triage) Each computer is then classified as one of: PASS (a current Windows LAPS or legacy LAPS password is present and the expiration time is in the future), FAIL_NO_LAPS (neither Windows LAPS nor legacy LAPS attributes are populated), FAIL_EXPIRED (an attribute is present but the expiration is in the past, indicating the CSE has not rotated the password on schedule, often because the machine is offline or the GPO is not applying), or FAIL_CLEARTEXT (msLAPS-Password is populated on a tenant where msLAPS-EncryptedPassword should be in use). Stale computers (lastLogonTimestamp older than 90 days) are reported separately so triage can distinguish a deployment gap from object hygiene. The check does not require Domain Admin. It does require read on the LAPS attributes, which by default is restricted to the computer itself and to delegated readers; the check tolerates AccessDenied on individual attributes by classifying based on attribute presence rather than value (it only needs to know whether a password is stored, not what it is).
Why it matters
A shared local administrator password is the single most reliable lateral-movement primitive in a Windows estate. Every workstation imaging process that bakes in a known local admin password, every "BUILTIN\Administrator renamed and given a corporate password", and every legacy Group Policy Preferences cpassword that pre-dates the GPP patch (MS14-025 / CVE-2014-1812) produces the same outcome: capture one NTLM hash from one machine and the attacker has SYSTEM on every other machine that shares it via Pass-the-Hash. This collapses the entire workstation tier into a single trust boundary. The blast radius is the full set of machines that share the password. In a typical enterprise that is the entire desktop fleet plus a meaningful slice of the server fleet, because servers are commonly imaged from the same gold image. From a foothold workstation an attacker pivots to every other workstation in seconds (impacket's wmiexec, smbexec, atexec; CrackMapExec / NetExec; PsExec), harvests cached domain credentials from each, and is one Kerberoast or DCSync away from Domain Admin. LAPS removes the primitive entirely: each machine has its own random 14 to 64 character password, rotated on a schedule, and the password is stored in AD under an ACL that, when delegated correctly, only the helpdesk tier that owns that OU can read. LAPS coverage gaps are equally important. A fleet that is 95 percent covered is functionally identical to a fleet that is 0 percent covered if the 5 percent uncovered machines share an old image password, because the attacker only needs one. Expired passwords matter because they indicate the CSE has stopped rotating, which usually means the GPO has stopped applying (broken delegation, blocked inheritance, WMI filter regression) and the existing password is now indefinitely valid. Clear-text storage matters because anyone with GenericRead on the computer object (which often includes Authenticated Users by misconfiguration) can read the password directly via LDAP, defeating the point of the encryption feature shipped in Windows LAPS.
Attack path
1. Foothold: the attacker lands as a low-privileged user on one workstation (phishing payload, malicious browser extension, drive-by, exposed RDP). They escalate to SYSTEM via a kernel exploit, a service misconfiguration, or by abusing an unquoted service path; on a machine without LAPS this step is unnecessary because the local admin password is already known. 2. Hash capture: from SYSTEM the attacker dumps the SAM (reg save HKLM\SAM, secretsdump.py -sam, or in-memory via lsassy / Mimikatz sekurlsa::logonpasswords). The NTLM hash of the local Administrator account is extracted (T1003.002). 3. Fleet enumeration: the attacker enumerates other workstations and servers via LDAP (Get-ADComputer, NetExec --gen-relay-list, BloodHound collection). No special rights are required. 4. Lateral spray: the attacker passes the captured hash against every machine in the fleet (NetExec smb -u Administrator -H <hash> --local-auth, impacket-wmiexec, impacket-smbexec). Every machine that shares the password authenticates and returns a SYSTEM shell. This is T1550.002, Pass the Hash, with T1078.003, Valid Accounts: Local Accounts. 5. Credential harvesting: on each lateral hop the attacker dumps LSASS for cached domain user tokens and DPAPI material (T1003.001). Within minutes the attacker holds dozens of domain user contexts including, statistically, at least one with Tier 1 (server) or Tier 0 (DC) rights. 6. Domain compromise: from a Tier 1 hop the attacker Kerberoasts service accounts, locates a writable group, or runs DCSync from a delegated principal. From a Tier 0 hop the attacker dumps NTDS.dit directly. Domain Admin is reached without ever using a credential other than the original local admin hash and its harvested by-products. Where LAPS is deployed properly, step 4 fails on the first hop: the captured hash is unique to the source machine and does not authenticate anywhere else. The attacker is forced into far noisier techniques (Kerberoasting from an unprivileged context, AS-REP roasting, ADCS template abuse) that mature detection programs catch.
How Guerrilla assesses it
Guerrilla uses Get-ADComputer with an LDAPFilter that restricts to enabled Windows machines and an explicit Properties list covering both Windows LAPS (msLAPS-Password, msLAPS-EncryptedPassword, msLAPS-EncryptedPasswordHistory, msLAPS-PasswordExpirationTime) and legacy Microsoft LAPS (ms-Mcs-AdmPwd, ms-Mcs-AdmPwdExpirationTime) attributes, plus lastLogonTimestamp, pwdLastSet, operatingSystem, and distinguishedName. The query is paged (1000 objects per page) so it scales to large estates. For each computer the classification logic is: - If msLAPS-Password or msLAPS-EncryptedPassword is set and msLAPS-PasswordExpirationTime is in the future: PASS (Windows LAPS). - Else if ms-Mcs-AdmPwd is set and ms-Mcs-AdmPwdExpirationTime is in the future: PASS (legacy LAPS, with an informational note that the legacy CSE is end-of-life and should be migrated to Windows LAPS). - Else if any LAPS attribute is set but the expiration is in the past: FAIL_EXPIRED. - Else: FAIL_NO_LAPS. - Independent flag: if msLAPS-Password (clear-text) is populated on a machine whose OU GPO requires encryption, raise FAIL_CLEARTEXT as a secondary finding. The check also confirms the schema is extended for both LAPS variants by reading the Schema NC for attributeSchema objects named msLAPS-Password and ms-Mcs-AdmPwd; if the schema is not extended at all the check fails the entire domain with a single high-severity finding rather than per-computer FAIL_NO_LAPS noise. For change detection, defenders should pair this check with directory service auditing (Event ID 4662) on the LAPS attributes to detect password retrieval, Event ID 4624 LogonType 3 with the local Administrator account for off-host use of recovered passwords, and Microsoft Defender for Identity LAPS-related alerts. Honeypot computer objects with attractive names and a delegated read ACL produce extremely high-fidelity alerts when an attacker enumerates LAPS at scale.
Recommended value
LAPS deployed to 100% of domain-joined Windows computers. No computers with missing or expired LAPS passwords
Remediation
Deploy the LAPS client (CSE) to all domain-joined computers via GPO, SCCM, or Intune. Configure LAPS GPO settings for password complexity, length (at least 20 characters), and age (30 days). Verify deployment by checking the ms-Mcs-AdmPwd or msLAPS-Password attribute on computer objects. Investigate any computers without LAPS passwords
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), AC-6
- CIS Benchmark
- 18.2.1
- ANSSI
- R42
- NSA / ASD
- LAPS-1
- CIS AD Benchmark
- 5.7.1
- MITRE ATT&CK
- T1078.003, T1003