Fix: Read session user certs from registry, not process identity

- Cert:\CurrentUser resolves to PROCESS identity, not session user
- Now reads directly from HKEY_USERS\{SID}\Software\Microsoft\SystemCertificates\
- Parses certificate blobs from Root and CA store registry keys
- Only attempts if CurrentUserSession is available and hive is loaded
- Skips invalid certificate blobs gracefully
This commit is contained in:
GraceSolutions
2026-05-04 10:52:17 -04:00
parent 903d87acf4
commit 30baf5e70e
+41 -30
View File
@@ -482,7 +482,9 @@ Switch (Test-ProcessElevationStatus)
$CertificateStorePathList.Add('Cert:\LocalMachine\Root') $CertificateStorePathList.Add('Cert:\LocalMachine\Root')
$CertificateStorePathList.Add('Cert:\LocalMachine\CA') $CertificateStorePathList.Add('Cert:\LocalMachine\CA')
#Include CurrentUser CA stores (use logged-in user's store if running as SYSTEM) #Include CurrentUser CA stores from session user (not process user)
#Note: Cert:\CurrentUser resolves to PROCESS identity, not session user
#To access session user's certs, we read directly from HKEY_USERS\{SID}
$UserCertificates = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]' $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)) Switch (($Null -ine $CurrentUserSession) -and ([System.String]::IsNullOrEmpty($CurrentUserSession.SID) -eq $False))
@@ -490,51 +492,60 @@ Switch (Test-ProcessElevationStatus)
{($_ -eq $True)} {($_ -eq $True)}
{ {
#Check if user's registry hive is loaded under HKEY_USERS #Check if user's registry hive is loaded under HKEY_USERS
$UserRegistryPath = "Registry::HKEY_USERS\$($CurrentUserSession.SID)" $UserRegistryBasePath = "Registry::HKEY_USERS\$($CurrentUserSession.SID)"
Switch (Test-Path -Path $UserRegistryPath -ErrorAction SilentlyContinue) Switch (Test-Path -Path $UserRegistryBasePath -ErrorAction SilentlyContinue)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$WriteLogMessage.Invoke(0, @("Accessing certificate store for user: $($CurrentUserSession.NTAccount) [SID: $($CurrentUserSession.SID)]")) $WriteLogMessage.Invoke(0, @("Accessing certificate store for session user: $($CurrentUserSession.NTAccount) [SID: $($CurrentUserSession.SID)]"))
#Open user's Root and CA stores via X509Store #Read certificates directly from user's registry hive
$UserStoreLocations = @( $UserCertStoreNames = @('Root', 'CA')
@{Name = 'Root'; Location = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser}
@{Name = 'CA'; Location = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser}
)
ForEach ($StoreInfo In $UserStoreLocations) ForEach ($StoreName In $UserCertStoreNames)
{ {
Try $UserCertRegistryPath = "$($UserRegistryBasePath)\Software\Microsoft\SystemCertificates\$($StoreName)\Certificates"
Switch (Test-Path -Path $UserCertRegistryPath -ErrorAction SilentlyContinue)
{ {
$UserCertStore = New-Object -TypeName 'System.Security.Cryptography.X509Certificates.X509Store' -ArgumentList @($StoreInfo.Name, $StoreInfo.Location) {($_ -eq $True)}
$UserCertStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly -bor [System.Security.Cryptography.X509Certificates.OpenFlags]::OpenExistingOnly) {
$UserCertificates.AddRange($UserCertStore.Certificates) $CertSubKeys = Get-ChildItem -Path $UserCertRegistryPath -ErrorAction SilentlyContinue
$UserCertStore.Close()
} ForEach ($CertSubKey In $CertSubKeys)
Catch {
{ Try
$WriteLogMessage.Invoke(1, @("Unable to access user certificate store `"$($StoreInfo.Name)`": $($_.Exception.Message)")) {
$CertBlob = Get-ItemProperty -Path $CertSubKey.PSPath -Name 'Blob' -ErrorAction SilentlyContinue
Switch ($Null -ine $CertBlob.Blob)
{
{($_ -eq $True)}
{
$X509Cert = New-Object -TypeName 'System.Security.Cryptography.X509Certificates.X509Certificate2' -ArgumentList @(,[System.Byte[]]$CertBlob.Blob)
$UserCertificates.Add($X509Cert)
}
}
}
Catch
{
#Skip invalid certificate blobs
}
}
}
} }
} }
$WriteLogMessage.Invoke(0, @("Found $($UserCertificates.Count) certificate(s) in session user's store."))
} }
Default Default
{ {
$WriteLogMessage.Invoke(1, @("User registry hive not loaded for SID: $($CurrentUserSession.SID). Using current process identity certificates.")) $WriteLogMessage.Invoke(1, @("User registry hive not loaded for SID: $($CurrentUserSession.SID). Skipping user 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]' $CACertificates = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]'
@@ -550,7 +561,7 @@ Switch (Test-ProcessElevationStatus)
} }
} }
#Add user certificates (already filtered by store type) #Add user certificates (filter for CA certs)
Switch ($UserCertificates.Count -gt 0) Switch ($UserCertificates.Count -gt 0)
{ {
{($_ -eq $True)} {($_ -eq $True)}