ReadLAPSv2Password
Summary
Description
Identification
PowerShell
function Find-ReadLAPSv2Password {
[CmdletBinding()]
param (
[string]$OutputPath = "ReadLAPSv2PasswordAcls.csv",
[ValidateSet('computer','organizationalUnit','container')]
[string[]]$Classes = @('computer','organizationalUnit','container')
)
Write-Verbose "Loading ActiveDirectory module..."
if (-not (Get-Module -Name ActiveDirectory)) {
Import-Module ActiveDirectory -ErrorAction Stop
}
$aclType = [System.Security.AccessControl.AccessControlType]::Allow
$rightToRead = [System.DirectoryServices.ActiveDirectoryRights]::ReadProperty
$rootDSE = [ADSI]"LDAP://RootDSE"
$schemaNC = $rootDSE.schemaNamingContext
function Get-AttributeGuid {
param ([string]$Name)
$path = "LDAP://CN=$Name,$schemaNC"
try {
$node = [ADSI]$path
} catch {
Write-Warning " • Cannot bind to schema object for '$Name': $_"
return [Guid]::Empty
}
$propCol = $node.Properties["schemaIDGUID"]
if (-not $propCol -or $propCol.Count -eq 0) {
Write-Warning " • schemaIDGUID missing for '$Name'"
return [Guid]::Empty
}
$bytes = $propCol[0]
if (-not ($bytes -is [byte[]])) {
Write-Warning " • schemaIDGUID for '$Name' is not a byte[]"
return [Guid]::Empty
}
try {
return New-Object System.Guid -ArgumentList (, $bytes)
} catch {
Write-Warning " • Failed to construct Guid for '$Name': $_"
return [Guid]::Empty
}
}
Write-Verbose "Retrieving LAPS attribute GUIDs..."
$plainGuid = Get-AttributeGuid -Name "ms-LAPS-Password"
$encryptedGuid = Get-AttributeGuid -Name "ms-LAPS-EncryptedPassword"
if ($plainGuid -eq [Guid]::Empty) {
Throw "Could not resolve GUID for ms-LAPS-Password cannot continue."
} elseif ($encryptedGuid -eq [Guid]::Empty) {
Write-Warning "Could not resolve GUID for ms-LAPS-EncryptedPassword; encrypted entries will be skipped."
}
$results = [System.Collections.Generic.List[PSObject]]::new()
Write-Verbose "Retrieving all objects of class: $($Classes -join ', ')"
$objects = foreach ($class in $Classes) { Get-ADObject -LDAPFilter "(objectClass=$class)" -Properties distinguishedName,objectClass}
foreach ($obj in $objects) {
$dn = $obj.DistinguishedName
$class = $obj.objectClass
Write-Verbose " ⋯ processing $dn ($class)"
try {
$entry = [ADSI]"LDAP://$dn"
$aces = $entry.ObjectSecurity.GetAccessRules(
$true, # includeExplicit
$false, # includeInherited
[System.Security.Principal.NTAccount]
)
foreach ($ace in $aces) {
if ($ace.AccessControlType -ne $aclType) { continue }
if (-not ($ace.ActiveDirectoryRights -band $rightToRead)) { continue }
if ($ace.IsInherited) { continue }
if ($ace.ObjectType -eq [Guid]::Empty) { continue }
if ($ace.ObjectType -eq $plainGuid) {
$attr = 'ms-LAPS-Password'
}
elseif ($encryptedGuid -ne [Guid]::Empty -and $ace.ObjectType -eq $encryptedGuid) {
$attr = 'ms-LAPS-EncryptedPassword'
}
else { continue }
$results.Add([PSCustomObject]@{
'Target Object DN' = $dn
'Object Type' = $class
'Identity Reference' = $ace.IdentityReference.Value
'Access Type' = $ace.AccessControlType
'Right' = "ReadProperty ($attr)"
'Inherited' = $ace.IsInherited
'GUID' = $ace.ObjectType
})
}
} catch {
Write-Warning "Failed to enumerate ACLs on $dn : $_"
}
}
$unique = $results | Sort-Object 'Target Object DN','Object Type','Identity Reference','Right','GUID' -Unique
if ($unique.Count -gt 0) {
Write-Host "Found $($unique.Count) unique LAPS ACL entries."
Write-Verbose "Exporting to $OutputPath"
$unique | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Export complete: $OutputPath"
}
else {Write-Host "No matching LAPS ACL entries found."}
}Active Directory Users and Computers

Exploitation
Windows


Linux


Mitigation

Detection
Event ID
Description
Fields/Attributes
References
References
Last updated
Was this helpful?