Access logged-in user's certificate store when running as SYSTEM

- Check if user's registry hive is loaded under HKEY_USERS\{SID}
- Use X509Store to access user's Root and CA stores via CurrentUserSession.SID
- Fallback to current process identity if user hive not loaded
- Log which user's certificates are being accessed
- Properly dedupe certificates from all stores by thumbprint
This commit is contained in:
GraceSolutions
2026-05-04 10:48:38 -04:00
parent 103181eedc
commit 903d87acf4
+88 -4
View File
@@ -477,14 +477,98 @@ Switch (Test-ProcessElevationStatus)
$CertificateExpirationThreshold = Get-Date
#Include both LocalMachine and CurrentUser CA stores
#Include LocalMachine CA stores
$CertificateStorePathList = New-Object -TypeName 'System.Collections.Generic.List[System.String]'
$CertificateStorePathList.Add('Cert:\LocalMachine\Root')
$CertificateStorePathList.Add('Cert:\LocalMachine\CA')
$CertificateStorePathList.Add('Cert:\CurrentUser\Root')
$CertificateStorePathList.Add('Cert:\CurrentUser\CA')
$CACertificates = Get-ChildItem -Path $CertificateStorePathList -ErrorAction SilentlyContinue | Where-Object {($_.NotAfter -gt $CertificateExpirationThreshold) -and ($_.Extensions | Where-Object {($_.Oid.FriendlyName -iin @('Basic Constraints')) -and ($_.CertificateAuthority -eq $True)})} | Sort-Object -Property @('Thumbprint') -Unique
#Include CurrentUser CA stores (use logged-in user's store if running as SYSTEM)
$UserCertificates = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]'
Switch (($Null -ine $CurrentUserSession) -and ([System.String]::IsNullOrEmpty($CurrentUserSession.SID) -eq $False))
{
{($_ -eq $True)}
{
#Check if user's registry hive is loaded under HKEY_USERS
$UserRegistryPath = "Registry::HKEY_USERS\$($CurrentUserSession.SID)"
Switch (Test-Path -Path $UserRegistryPath -ErrorAction SilentlyContinue)
{
{($_ -eq $True)}
{
$WriteLogMessage.Invoke(0, @("Accessing certificate store for user: $($CurrentUserSession.NTAccount) [SID: $($CurrentUserSession.SID)]"))
#Open user's Root and CA stores via X509Store
$UserStoreLocations = @(
@{Name = 'Root'; Location = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser}
@{Name = 'CA'; Location = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser}
)
ForEach ($StoreInfo In $UserStoreLocations)
{
Try
{
$UserCertStore = New-Object -TypeName 'System.Security.Cryptography.X509Certificates.X509Store' -ArgumentList @($StoreInfo.Name, $StoreInfo.Location)
$UserCertStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly -bor [System.Security.Cryptography.X509Certificates.OpenFlags]::OpenExistingOnly)
$UserCertificates.AddRange($UserCertStore.Certificates)
$UserCertStore.Close()
}
Catch
{
$WriteLogMessage.Invoke(1, @("Unable to access user certificate store `"$($StoreInfo.Name)`": $($_.Exception.Message)"))
}
}
}
Default
{
$WriteLogMessage.Invoke(1, @("User registry hive not loaded for SID: $($CurrentUserSession.SID). Using current process identity certificates."))
$CertificateStorePathList.Add('Cert:\CurrentUser\Root')
$CertificateStorePathList.Add('Cert:\CurrentUser\CA')
}
}
}
Default
{
#No user session info available, use current process identity
$CertificateStorePathList.Add('Cert:\CurrentUser\Root')
$CertificateStorePathList.Add('Cert:\CurrentUser\CA')
}
}
$CACertificates = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]'
#Add certificates from LocalMachine stores
$LocalMachineCerts = Get-ChildItem -Path $CertificateStorePathList -ErrorAction SilentlyContinue | Where-Object {($_.NotAfter -gt $CertificateExpirationThreshold) -and ($_.Extensions | Where-Object {($_.Oid.FriendlyName -iin @('Basic Constraints')) -and ($_.CertificateAuthority -eq $True)})}
Switch ($Null -ine $LocalMachineCerts)
{
{($_ -eq $True)}
{
$CACertificates.AddRange([System.Security.Cryptography.X509Certificates.X509Certificate2[]]$LocalMachineCerts)
}
}
#Add user certificates (already filtered by store type)
Switch ($UserCertificates.Count -gt 0)
{
{($_ -eq $True)}
{
$FilteredUserCerts = $UserCertificates | Where-Object {($_.NotAfter -gt $CertificateExpirationThreshold) -and ($_.Extensions | Where-Object {($_.Oid.FriendlyName -iin @('Basic Constraints')) -and ($_.CertificateAuthority -eq $True)})}
Switch ($Null -ine $FilteredUserCerts)
{
{($_ -eq $True)}
{
$CACertificates.AddRange([System.Security.Cryptography.X509Certificates.X509Certificate2[]]$FilteredUserCerts)
}
}
}
}
#Dedupe by thumbprint
$CACertificates = $CACertificates | Sort-Object -Property @('Thumbprint') -Unique
#region Apply CA Inclusion Filter
Switch (([System.String]::IsNullOrEmpty($CAInclusionExpression) -eq $False) -and ([System.String]::IsNullOrWhiteSpace($CAInclusionExpression) -eq $False))