Analyzers/Test-Esc11.ps1
|
function Test-Esc11 { <# .SYNOPSIS ESC11 - Relay to ICertPassage (ICPR) RPC when request encryption is not enforced. .DESCRIPTION Read-only analyzer over $Context.CaConfigs. A CA is vulnerable when IF_ENFORCEENCRYPTICERTREQUEST (0x00000200) is NOT set in InterfaceFlags, i.e. EnforceEncryptRequest == $false. An unauthenticated attacker can then relay NTLM to the ICertPassage RPC interface to obtain certificates. Unreachable CAs -> ManualReview. .PARAMETER Context AssessmentContext pscustomobject. .PARAMETER ExtraLowPrivSid Unused for ESC11 (kept for signature uniformity). .OUTPUTS Finding[] #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject] $Context, [Parameter(Mandatory = $false)] [string[]] $ExtraLowPrivSid = @() ) $reference = 'https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/' $findings = @() if ($null -eq $Context.CaConfigs -or @($Context.CaConfigs).Count -eq 0) { return @([pscustomobject]@{ Id = 'ESC11'; Title = 'ESC11 CA configuration data unavailable'; Severity = 'Critical'; Status = 'ManualReview'; AffectedObject = 'Certificate Authorities'; Evidence = [pscustomobject]@{ Reason = 'Context.CaConfigs was null/empty; CA InterfaceFlags not collected.' }; Principals = @(); Exploitability = 'Theoretical'; RiskScore = 0; Remediation = 'Collect CA\InterfaceFlags via certutil -getreg CA\InterfaceFlags.'; Reference = $reference }) } $anyReachable = $false foreach ($ca in $Context.CaConfigs) { $caName = $ca.Name if ($ca.Reachable -eq $false) { $findings += [pscustomobject]@{ Id = 'ESC11'; Title = "CA '$caName' unreachable - encryption enforcement unknown"; Severity = 'Critical'; Status = 'ManualReview'; AffectedObject = $caName; Evidence = [pscustomobject]@{ Ca = $caName; Reachable = $false; Reason = 'certutil / registry read failed.' }; Principals = @(); Exploitability = 'Theoretical'; RiskScore = 0; Remediation = 'Manually verify IF_ENFORCEENCRYPTICERTREQUEST on this CA.'; Reference = $reference } continue } $anyReachable = $true $enforce = $null if ($null -ne $ca.EnforceEncryptRequest) { $enforce = [bool]$ca.EnforceEncryptRequest } elseif ($null -ne $ca.InterfaceFlags) { $enforce = (([int]$ca.InterfaceFlags) -band 0x200) -ne 0 } if ($null -eq $enforce) { $findings += [pscustomobject]@{ Id = 'ESC11'; Title = "CA '$caName' InterfaceFlags not available"; Severity = 'Critical'; Status = 'ManualReview'; AffectedObject = $caName; Evidence = [pscustomobject]@{ Ca = $caName; InterfaceFlags = $null; Reason = 'Neither EnforceEncryptRequest nor InterfaceFlags populated.' }; Principals = @(); Exploitability = 'Theoretical'; RiskScore = 0; Remediation = 'Manually verify IF_ENFORCEENCRYPTICERTREQUEST on this CA.'; Reference = $reference } continue } if (-not $enforce) { $remoteClosed = $false if ($null -ne $ca.InterfaceFlags) { $remoteClosed = (([int]$ca.InterfaceFlags) -band 0x2) -ne 0 } if ($remoteClosed) { $exploit = 'Low' } else { $exploit = 'High' } $findings += [pscustomobject]@{ Id = 'ESC11' Title = "CA '$caName' does not enforce request encryption (ESC11)" Severity = 'Critical' Status = 'Vulnerable' AffectedObject = $caName Evidence = [pscustomobject]@{ Ca = $caName DnsHostName = $ca.DnsHostName InterfaceFlags = $ca.InterfaceFlags EnforceEncryptRequest = $false IF_ENFORCEENCRYPTICERTREQUEST = '0x200 unset' RemoteIcertRequestDisabled = $remoteClosed Meaning = 'ICertPassage RPC accepts unencrypted requests - NTLM relay to ICPR possible.' } Principals = @() Exploitability = $exploit RiskScore = 0 Remediation = 'Set IF_ENFORCEENCRYPTICERTREQUEST (certutil -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST) and enable EPA/require SMB signing; restart CertSvc.' Reference = $reference } } } if ($findings.Count -eq 0) { $status = 'NotVulnerable'; $sev = 'Info' if (-not $anyReachable) { $status = 'ManualReview'; $sev = 'Critical' } return @([pscustomobject]@{ Id = 'ESC11'; Title = 'All CAs enforce request encryption (no ESC11)'; Severity = $sev; Status = $status; AffectedObject = 'Certificate Authorities'; Evidence = [pscustomobject]@{ CasChecked = @($Context.CaConfigs).Count; AnyReachable = $anyReachable }; Principals = @(); Exploitability = 'Theoretical'; RiskScore = 0; Remediation = 'None required.'; Reference = $reference }) } return $findings } |