Private/Set/Set-AuthorizedSignatureRequired.ps1

function Set-AuthorizedSignatureRequired {
    <#
        .SYNOPSIS
        Adds an AuthorizedSignatureRequired property to AD CS certificate template objects.
 
        .DESCRIPTION
        Examines the msPKI-RA-Signature attribute of Active Directory Certificate Services
        certificate template objects to determine if authorized signatures are required for enrollment.
         
        The function checks the msPKI-RA-Signature attribute value. When this value is 1 or greater,
        certificate requests based on this template require one or more authorized signatures
        (from a Registration Authority or authorized enrollment agent) before the certificate is issued.
         
        Authorized signature requirements are a strong security control that helps prevent abuse
        of certificate templates. When required, certificates can only be issued if the request
        is signed by an authorized principal, providing defense against unauthorized enrollment.
         
        Templates without authorized signature requirements combined with other risky settings
        (like allowing SANs or dangerous enrollees) can lead to privilege escalation vulnerabilities.
         
        The function adds a boolean AuthorizedSignatureRequired property to each input object
        indicating whether the template requires authorized signatures for enrollment.
 
        .PARAMETER AdcsObject
        One or more DirectoryEntry objects representing AD CS certificate templates.
        These objects must contain the msPKI-RA-Signature attribute.
 
        .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 AuthorizedSignatureRequired boolean property.
 
        .EXAMPLE
        $templates = Get-AdcsObject -RootDSE $rootDSE | Where-Object { $_.objectClass -contains 'pKICertificateTemplate' }
        $templates | Set-AuthorizedSignatureRequired
        Processes all certificate templates and adds the AuthorizedSignatureRequired property to each.
 
        .EXAMPLE
        Get-AdcsObject -RootDSE $rootDSE | Set-AuthorizedSignatureRequired | Where-Object { -not $_.AuthorizedSignatureRequired }
        Retrieves all AD CS objects, adds AuthorizedSignatureRequired property, and filters to only those NOT requiring signatures.
 
        .EXAMPLE
        $template = Get-AdcsObject -RootDSE $rootDSE | Where-Object Name -eq 'WebServer'
        $template | Set-AuthorizedSignatureRequired
        if (-not $template.AuthorizedSignatureRequired) {
            Write-Host "Template does not require authorized signatures - potential security risk"
        }
        Checks a specific template for authorized signature requirement.
 
        .NOTES
        The msPKI-RA-Signature attribute specifies the number of authorized signatures required:
        - 0 or absent: No authorized signatures required
        - 1 or greater: Number of authorized signatures required
         
        When authorized signatures are NOT required, users can obtain certificates directly
        upon enrollment. Combined with other misconfigurations (like allowing SANs or
        overly permissive enrollees), this can enable privilege escalation attacks.
         
        Templates requiring authorized signatures provide a strong defense-in-depth control
        by ensuring that only authorized principals can approve certificate issuance.
 
        .LINK
        https://posts.specterops.io/certified-pre-owned-d95910965cd2
    #>

    [CmdletBinding()]
    [OutputType([System.DirectoryServices.DirectoryEntry[]])]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.DirectoryServices.DirectoryEntry[]]$AdcsObject
    )

    #requires -Version 5.1

    begin {
        Write-Verbose "Identifying templates that require authorized signatures for enrollment..."
    }

    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"
                
                $authorizedSignatureRequired = $true
                
                # Check if the msPKI-RA-Signature attribute exists and is >= 1
                if ($_.Properties.'msPKI-RA-Signature'.Count -gt 0) {
                    [int]$raSignature = $_.'msPKI-RA-Signature'[0]
                    Write-Verbose "msPKI-RA-Signature value: $raSignature"
                    
                    # REVERSED LOGIC: Property is true when signature is NOT required (vulnerable)
                    if ($raSignature -ge 1) {
                        $authorizedSignatureRequired = $false
                        Write-Verbose "Authorized signature is required ($raSignature signature(s) needed) - NOT vulnerable"
                    } else {
                        Write-Verbose "Authorized signature is NOT required (value is 0) - VULNERABLE"
                    }
                } else {
                    Write-Verbose "msPKI-RA-Signature attribute not found on object - assuming NOT required (vulnerable)"
                }
                
                # Update the AdcsObjectStore with the AuthorizedSignatureRequired property
                $dn = $_.Properties.distinguishedName[0]
                if ($script:AdcsObjectStore.ContainsKey($dn)) {
                    $script:AdcsObjectStore[$dn] | Add-Member -NotePropertyName AuthorizedSignatureRequired -NotePropertyValue $authorizedSignatureRequired -Force
                    Write-Verbose "Updated AD CS Object Store for $dn with AuthorizedSignatureRequired = $authorizedSignatureRequired"
                }
                
                # Also add to the pipeline object for backward compatibility
                $_ | Add-Member -NotePropertyName AuthorizedSignatureRequired -NotePropertyValue $authorizedSignatureRequired -Force
                
                # Return the modified object
                $_
                
            } catch {
                $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                    $_.Exception,
                    'AuthorizedSignatureProcessingFailed',
                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                    $_
                )
                $PSCmdlet.WriteError($errorRecord)
                
                # Still return the object even if processing failed
                $_
            }
        }
    }

    end {
        Write-Verbose "Done identifying templates that require authorized signatures for enrollment."
    }
}