Analyzers/Test-Esc3.ps1
|
function Test-Esc3 { <# .SYNOPSIS ESC3 - Enrollment Agent (Certificate-Request-Agent EKU) template open to low-priv enrollment. .DESCRIPTION Flags templates carrying the Certificate-Request-Agent EKU (1.3.6.1.4.1.311.20.2.1) that a low-privileged principal can enroll in without manager approval or RA signatures. An enrollment-agent certificate lets the holder request certificates ON BEHALF OF other principals. Combined with a companion template that accepts enrollment-agent signatures (RaSignaturesRequired >= 1 and RaApplicationPolicies contains 1.3.6.1.4.1.311.20.2.1) and has a client-auth EKU, this yields authentication as an arbitrary user. Agent template Vulnerable = EKU/AppPolicy contains 1.3.6.1.4.1.311.20.2.1 AND low-priv principal holds Enroll/AutoEnroll AND ManagerApprovalRequired == $false AND RaSignaturesRequired -lt 1 AND published. The companion (target) template condition is reported in Evidence. .PARAMETER Context AssessmentContext pscustomobject. Reads $Context.Templates. .PARAMETER ExtraLowPrivSid Extra SID strings to treat as low-privileged. .OUTPUTS Finding[] #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject] $Context, [Parameter(Mandatory = $false)] [string[]] $ExtraLowPrivSid = @() ) $reference = 'SpecterOps "Certified Pre-Owned" (ESC3) / Certipy' $ENROLLMENT_AGENT_OID = '1.3.6.1.4.1.311.20.2.1' $findings = @() $newFinding = { param($Title, $Severity, $Status, $Affected, $Evidence, $Principals, $Exploit, $Remediation) [pscustomobject]@{ Id = 'ESC3' Title = $Title Severity = $Severity Status = $Status AffectedObject = $Affected Evidence = $Evidence Principals = @($Principals) Exploitability = $Exploit RiskScore = 0 Remediation = $Remediation Reference = $reference } } $templates = @() if ($null -ne $Context -and $null -ne $Context.Templates) { $templates = @($Context.Templates) } if ($templates.Count -eq 0) { return @(& $newFinding 'ESC3 - no certificate templates available' 'Critical' 'ManualReview' 'N/A' ` ([pscustomobject]@{ Error = 'Context.Templates is empty or unavailable; could not evaluate ESC3.' }) ` @() 'Theoretical' 'Collect certificate templates and re-run the assessment.') } $companionTargets = @($templates | Where-Object { ([int]$_.RaSignaturesRequired -ge 1) -and (@($_.RaApplicationPolicies) -contains $ENROLLMENT_AGENT_OID) -and (Test-EscEkuAllowsAuth -EkuList $_.EkuList -ApplicationPolicies $_.ApplicationPolicies) }) $companionNames = @($companionTargets | ForEach-Object { $_.Name }) foreach ($tpl in $templates) { $eku = @($tpl.EkuList) $appPol = @($tpl.ApplicationPolicies) if (-not (($eku -contains $ENROLLMENT_AGENT_OID) -or ($appPol -contains $ENROLLMENT_AGENT_OID))) { continue } if ($tpl.ManagerApprovalRequired) { continue } if ([int]$tpl.RaSignaturesRequired -ge 1) { continue } $lowPrivEnrollers = @($tpl.EnrollPrincipals | Where-Object { $_.AceType -eq 'Allow' -and $_.IsLowPriv -and ( ($_.Rights -contains 'Enroll') -or ($_.Rights -contains 'GenericAll') ) }) if ($lowPrivEnrollers.Count -eq 0) { continue } $published = @($tpl.PublishedOnCAs) if ($published.Count -eq 0) { continue } $principalNames = @($lowPrivEnrollers | ForEach-Object { if ($_.PrincipalName) { $_.PrincipalName } else { $_.PrincipalSid } } | Select-Object -Unique) if ($companionNames.Count -gt 0) { $exploit = 'High' } else { $exploit = 'Medium' } $evidence = [pscustomobject]@{ CertificateRequestAgentEku = $ENROLLMENT_AGENT_OID EkuList = $eku ApplicationPolicies = $appPol ManagerApprovalRequired = $false RaSignaturesRequired = [int]$tpl.RaSignaturesRequired PublishedOnCAs = $published LowPrivEnrollRights = @($lowPrivEnrollers | ForEach-Object { '{0}:{1}' -f $_.PrincipalName, ($_.Rights -join '|') }) CompanionTargetTemplates = $companionNames CompanionCondition = 'A target template with RaSignaturesRequired>=1, RaApplicationPolicies containing 1.3.6.1.4.1.311.20.2.1, and a client-auth EKU completes the on-behalf-of chain.' } $findings += & $newFinding ` ("ESC3 - enrollment-agent template '{0}' open to low-priv enrollment" -f $tpl.Name) ` 'Critical' 'Vulnerable' $tpl.Name $evidence $principalNames $exploit ` 'Restrict enrollment on Certificate-Request-Agent templates, require manager approval, and limit which templates accept enrollment-agent signatures via issuance requirements.' } if ($findings.Count -eq 0) { return @(& $newFinding 'ESC3 - no enrollment-agent templates open to low-priv enrollment' 'Critical' 'NotVulnerable' 'N/A' ` ([pscustomobject]@{ TemplatesEvaluated = $templates.Count; CompanionTargetsPresent = $companionNames }) @() 'Theoretical' ` 'No action required for ESC3.') } return $findings } |