Private/Set/Set-RequiresEnrollmentAgentSignature.ps1

function Set-RequiresEnrollmentAgentSignature {
    <#
        .SYNOPSIS
        Adds a RequiresEnrollmentAgentSignature property to AD CS certificate template objects.

        .DESCRIPTION
        Examines the msPKI-RA-Signature and msPKI-RA-Application-Policies attributes of Active Directory
        Certificate Services certificate template objects to determine if they require enrollment agent
        signatures for certificate requests.
        
        The function checks for:
        - msPKI-RA-Signature = 1 (requires authorized signature)
        - msPKI-RA-Application-Policies contains '1.3.6.1.4.1.311.20.2.1' (Certificate Request Agent)
        
        Templates with these settings are vulnerable to ESC3 Condition 2 attacks, where holders of
        enrollment agent certificates can request certificates on behalf of other principals.
        
        The function adds a boolean RequiresEnrollmentAgentSignature property to each input object
        indicating whether the template requires enrollment agent signatures.

        .PARAMETER AdcsObject
        One or more DirectoryEntry objects representing AD CS certificate templates.
        These objects must contain the msPKI-RA-Signature and msPKI-RA-Application-Policies attributes.

        .INPUTS
        System.DirectoryServices.DirectoryEntry[]
        You can pipe certificate template DirectoryEntry objects to this function.

        .OUTPUTS
        System.DirectoryServices.DirectoryEntry[]
        Returns the input objects with an added RequiresEnrollmentAgentSignature boolean property.

        .EXAMPLE
        $templates = Get-AdcsObject -RootDSE $rootDSE | Where-Object { $_.objectClass -contains 'pKICertificateTemplate' }
        $templates | Set-RequiresEnrollmentAgentSignature
        Processes all certificate templates and adds the RequiresEnrollmentAgentSignature property to each.

        .EXAMPLE
        Get-AdcsObject -RootDSE $rootDSE | Set-RequiresEnrollmentAgentSignature | Where-Object RequiresEnrollmentAgentSignature
        Retrieves all AD CS objects, adds RequiresEnrollmentAgentSignature property, and filters to vulnerable templates.

        .NOTES
        Templates requiring enrollment agent signatures (ESC3 Condition 2) are vulnerable when:
        - msPKI-RA-Signature = 1 (requires authorized signature)
        - msPKI-RA-Application-Policies contains Certificate Request Agent EKU
        - Template includes Client Authentication EKU
        - Enrollment permissions granted to low-privilege or dangerous principals
        
        An attacker with an enrollment agent certificate can use these templates to request
        certificates on behalf of other principals and authenticate as them.

        .LINK
        https://posts.specterops.io/certified-pre-owned-d95910965cd2
    #>

    [CmdletBinding()]
    [OutputType([LS2AdcsObject[]])]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [LS2AdcsObject[]]$AdcsObject
    )

    #requires -Version 5.1

    begin {
        Write-Verbose "Identifying templates that require enrollment agent signatures..."
        $enrollmentAgentEKU = '1.3.6.1.4.1.311.20.2.1'
    }

    process {
        $AdcsObject | Where-Object SchemaClassName -EQ pKICertificateTemplate | ForEach-Object {
            try {
                $objectName = $_.GetFriendlyName()
                Write-Verbose "Processing template: $objectName"
                
                $requiresEnrollmentAgentSignature = $false
                
                # Check if RASignature = 1 (requires authorized signature)
                if ($null -ne $_.RASignature) {
                    [int]$raSignature = $_.RASignature
                    Write-Verbose "msPKI-RA-Signature value: $raSignature"
                    
                    # Check if RAApplicationPolicies contains enrollment agent EKU
                    if ($raSignature -eq 1 -and $_.RAApplicationPolicies.Count -gt 0) {
                        $raPolicies = $_.RAApplicationPolicies
                        Write-Verbose "msPKI-RA-Application-Policies contains $($raPolicies.Count) policy/ies: $($raPolicies -join ', ')"
                        
                        if ($enrollmentAgentEKU -in $raPolicies) {
                            $requiresEnrollmentAgentSignature = $true
                            Write-Verbose "Template requires enrollment agent signature"
                        } else {
                            Write-Verbose "Template requires signature but not from enrollment agent"
                        }
                    } else {
                        Write-Verbose "Template does not require enrollment agent signature (RA-Signature: $raSignature)"
                    }
                } else {
                    Write-Verbose "RASignature not present or is 0 - no signature required"
                }
                
                # Set the property directly on the LS2AdcsObject (same reference as store)
                $_.RequiresEnrollmentAgentSignature = $requiresEnrollmentAgentSignature
                Write-Verbose "Updated $($_.distinguishedName) with RequiresEnrollmentAgentSignature = $requiresEnrollmentAgentSignature"
                
                # Return the modified object
                $_
            } catch {
                Write-Error "Error processing template $($_.distinguishedName): $_"
            }
        }
    }

    end {
        Write-Verbose "Finished identifying templates requiring enrollment agent signatures"
    }
}