Private/Set/Set-EnrollmentAgentEKUExist.ps1

function Set-EnrollmentAgentEKUExist {
    <#
        .SYNOPSIS
        Adds an EnrollmentAgentEKUExist property to AD CS certificate template objects.
 
        .DESCRIPTION
        Examines the pKIExtendedKeyUsage attribute of Active Directory Certificate Services
        certificate template objects to determine if they include the Certificate Request Agent
        (Enrollment Agent) Extended Key Usage.
         
        The function checks for the presence of the Enrollment Agent EKU (OID 1.3.6.1.4.1.311.20.2.1).
        Templates with this EKU can be used to request certificates on behalf of other principals,
        which can be abused in ESC3 Condition 1 attacks when combined with other misconfigurations.
         
        The function adds a boolean EnrollmentAgentEKUExist property to each input object
        indicating whether the template includes the Enrollment Agent EKU.
 
        .PARAMETER AdcsObject
        One or more DirectoryEntry objects representing AD CS certificate templates.
        These objects must contain the pKIExtendedKeyUsage attribute.
 
        .PARAMETER EnrollmentAgentEKU
        Optional. Array of OID strings representing the Enrollment Agent EKU.
        Default is '1.3.6.1.4.1.311.20.2.1' (Certificate Request Agent).
 
        .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 EnrollmentAgentEKUExist boolean property.
 
        .EXAMPLE
        $templates = Get-AdcsObject -RootDSE $rootDSE | Where-Object { $_.objectClass -contains 'pKICertificateTemplate' }
        $templates | Set-EnrollmentAgentEKUExist
        Processes all certificate templates and adds the EnrollmentAgentEKUExist property to each.
 
        .EXAMPLE
        Get-AdcsObject -RootDSE $rootDSE | Set-EnrollmentAgentEKUExist | Where-Object EnrollmentAgentEKUExist
        Retrieves all AD CS objects, adds EnrollmentAgentEKUExist property, and filters to only enrollment agent templates.
 
        .NOTES
        The Certificate Request Agent (Enrollment Agent) EKU allows certificates to be requested
        on behalf of other users. This is commonly used in restricted enrollment scenarios but
        can be dangerous when combined with:
        - No manager approval requirement (msPKI-Enrollment-Flag not set to 2)
        - No authorized signature requirement (msPKI-RA-Signature = 0 or null)
        - Enrollment permissions granted to low-privilege or dangerous principals
 
        .LINK
        https://posts.specterops.io/certified-pre-owned-d95910965cd2
    #>

    [CmdletBinding()]
    [OutputType([System.DirectoryServices.DirectoryEntry[]])]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.DirectoryServices.DirectoryEntry[]]$AdcsObject,
        
        [Parameter()]
        [string[]]$EnrollmentAgentEKU = @(
            '1.3.6.1.4.1.311.20.2.1'  # Certificate Request Agent
        )
    )

    #requires -Version 5.1

    begin {
        Write-Verbose "Identifying templates that create Enrollment Agent certificates..."
    }

    process {
        $AdcsObject | Where-Object SchemaClassName -eq pKICertificateTemplate | ForEach-Object {
            try {
                $objectName = if ($_.Properties.displayName.Count -gt 0) {
                    $_.Properties.displayName[0] 
                } elseif ($_.Properties.name.Count -gt 0) {
                    $_.Properties.name[0]
                } else {
                    $_.Properties.distinguishedName[0]
                }
                Write-Verbose "Processing template: $objectName"
                
                $enrollmentAgentEKUExist = $false
                
                # Check if pKIExtendedKeyUsage attribute exists and has values
                if ($_.Properties.pKIExtendedKeyUsage.Count -gt 0) {
                    $ekuList = $_.Properties.pKIExtendedKeyUsage
                    Write-Verbose "pKIExtendedKeyUsage contains $($ekuList.Count) EKU(s): $($ekuList -join ', ')"
                    
                    # Check if any of the Enrollment Agent EKUs are present
                    foreach ($eku in $ekuList) {
                        if ($eku -in $EnrollmentAgentEKU) {
                            $enrollmentAgentEKUExist = $true
                            Write-Verbose "Enrollment Agent EKU found: $eku"
                            break
                        }
                    }
                    
                    if (-not $enrollmentAgentEKUExist) {
                        Write-Verbose "No Enrollment Agent EKUs found in template"
                    }
                } else {
                    Write-Verbose "pKIExtendedKeyUsage is empty or not present"
                }
                
                # Update the AdcsObjectStore with the EnrollmentAgentEKUExist property
                $dn = $_.Properties.distinguishedName[0]
                if ($script:AdcsObjectStore.ContainsKey($dn)) {
                    $script:AdcsObjectStore[$dn] | Add-Member -NotePropertyName EnrollmentAgentEKUExist -NotePropertyValue $enrollmentAgentEKUExist -Force
                    Write-Verbose "Updated AD CS Object Store for $dn with EnrollmentAgentEKUExist = $enrollmentAgentEKUExist"
                }
                
                # Also add to the pipeline object for backward compatibility
                $_ | Add-Member -NotePropertyName EnrollmentAgentEKUExist -NotePropertyValue $enrollmentAgentEKUExist -Force
                
                # Return the modified object
                $_
            }
            catch {
                Write-Error "Error processing template $($_.Properties.distinguishedName[0]): $_"
            }
        }
    }

    end {
        Write-Verbose "Finished identifying templates with Enrollment Agent EKU"
    }
}