Eleven privileged accounts received certificates they never requested. Three in the first wave, eight about ninety minutes later, every one of them issued by the victim organization's own certificate authority. The attacker arrived through a Microsoft Teams message that read like an internal help-desk ticket. Microsoft published both intrusions on October 30, and the useful part sits at the end of the timeline, where containment ran and one excluded account carried the data out anyway.
This one reaches you if you run Active Directory Certificate Services on premises, with templates that issue authentication certificates. That describes nearly every enterprise CA in service. It reaches you harder if the same CA publishes the web enrollment pages under /certsrv, because the second intrusion needed no misconfigured template at all. If your identity estate is entirely Entra ID with no on-prem CA, the certificate half of this is not yours: read the first section for the Teams and Quick Assist entry, then stop. If you have a CA that somebody stood up years ago to issue Wi-Fi or VPN certificates, and nobody has opened the template list since, read all of it. Cisco Talos put phishing at the top of its Q3 2026 incident-response engagements at 37 percent, with missing or insufficient authentication controls present in 33 percent. Those two numbers describe this intrusion between them.
How a help-desk message reached the certificate authority
Both intrusions opened the same way. The attacker messaged and called employees from outside Microsoft 365 tenants with support-sounding names, impersonating the company's own IT staff. No Teams vulnerability was involved. The objective of the call was narrow: get the user to launch Quick Assist, the remote-help tool already present in Windows, and read the connection code aloud. That hands over an interactive session with the user's own rights, through a signed Microsoft binary, with no malware yet on disk.
What followed was quiet. The attacker dropped an archive into the user's Downloads folder, created a staging directory with a KB-prefixed name under the user profile so it would pass a glance as a Windows update, and extracted the archive there. Execution ran through a portable interpreter: Python, Bun for JavaScript, or a Java runtime launching a .java source file. One sample was a renamed Bun executable that still carried Bun's original filename in its version metadata.
That detail is the one to take into your detections. The file name on disk was chosen by the attacker, so matching on it buys nothing. ProcessVersionInfoOriginalFileName survives the rename. Microsoft also notes that attack surface reduction rules aimed at Windows Script Host do not cover Bun JavaScript or a Java source file, so a control you believe blocks script execution may have no opinion about either.
Discovery was three commands: the Windows version out of the registry, ipconfig /all, and tasklist. Then the workstation reached domain infrastructure over LDAPS and SMB, the attacker enumerated certificate-based authentication paths, and the two cases diverged.
ESC1: the template that lets the requester name someone else
A certificate template carries a flag, CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT, that lets whoever asks for the certificate state which account it represents. On its own that is a convenience for offline enrollment. Combine it with an extended key usage that permits client authentication, no manager approval on issuance, and enrollment rights held by a broad group such as Domain Users, and any account in the domain can ask the CA for a certificate that authenticates as a domain administrator. The CA will issue it, because every box the template told it to check was checked. SpecterOps named this path ESC1 in Certified Pre-Owned in 2021.
In the first intrusion the attacker used an ESC1-vulnerable template to obtain certificates for three highly privileged accounts. Microsoft Defender attack disruption responded, restricting remote logons and SMB access for those identities and disconnecting their sessions. Roughly ninety minutes after that first session was cut, a larger phishing wave hit sixteen users, compromised a second workstation, and produced certificates for eight more privileged accounts. More than a thousand later file-access and logon attempts were blocked. Within seconds of getting one of those certificates, the attacker authenticated to a domain controller and began DCSync to replicate password material; containment landed partway through the operation.
The four conditions that make a template dangerous are all readable from AD. This pass reports the templates that satisfy the first three, which is the shortlist worth reviewing by hand.
# Find authentication-capable templates that let the requester supply the subject
# and do not hold requests for manager approval. Run as any domain user.
# Flags: CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT = 0x1 (msPKI-Certificate-Name-Flag)
# CT_FLAG_PEND_ALL_REQUESTS = 0x2 (msPKI-Enrollment-Flag)
Import-Module ActiveDirectory
$cfg = (Get-ADRootDSE).configurationNamingContext
$base = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$cfg"
# Client Authentication, PKINIT Client Auth, Smart Card Logon, Any Purpose
$authEku = '1.3.6.1.5.5.7.3.2|1.3.6.1.5.2.3.4|1.3.6.1.4.1.311.20.2.2|2.5.29.37.0'
Get-ADObject -SearchBase $base -LDAPFilter '(objectClass=pKICertificateTemplate)' `
-Properties displayName,'msPKI-Certificate-Name-Flag','msPKI-Enrollment-Flag',pKIExtendedKeyUsage |
Where-Object {
($_.'msPKI-Certificate-Name-Flag' -band 0x1) -and
-not ($_.'msPKI-Enrollment-Flag' -band 0x2) -and
($_.pKIExtendedKeyUsage -join ',') -match $authEku
} |
ForEach-Object {
$enroll = (Get-Acl "AD:$($_.DistinguishedName)").Access |
Where-Object { $_.ObjectType -eq '0e10c968-78fb-11d2-90d4-00c04f79dc55' -and
$_.AccessControlType -eq 'Allow' } |
Select-Object -ExpandProperty IdentityReference -Unique
[pscustomobject]@{ Template = $_.displayName; EnrollRights = ($enroll -join '; ') }
} | Format-List
Read the EnrollRights column first. Authenticated Users, Domain Users, or Domain Computers against a template on this list is the finding. Microsoft's own guidance is to remove requester-supplied subject information from authentication templates, trim enrollment rights to the accounts that need them, and require approval where the template has to stay as it is. Defender for Identity ships posture assessments that flag the same exposure if you already have the license.
ESC8 needs no misconfigured template
The second intrusion skipped templates. The attacker ran PetitPotam over EFSRPC to make a domain controller authenticate to an attacker-controlled host using its machine account, then relayed that NTLM authentication to the CA's web enrollment pages and requested a certificate from the stock Domain Controller template. No password was involved at any point. With that certificate and PKINIT, the attacker obtained a Kerberos ticket-granting ticket for the domain controller itself, converting a single relayed logon into an identity it could keep using. Defender raised ESC8 alerts, the customer isolated the workstation, and Microsoft observed no further progression.
Web enrollment accepting NTLM over cleartext HTTP is the whole prerequisite. Microsoft's KB5005413 has carried the mitigation since 2021: require HTTPS, enable Extended Protection for Authentication, and turn off NTLM on the enrollment endpoints where Kerberos-only authentication validates cleanly. EPA is on by default for AD CS web enrollment in Windows Server 2025, which means every CA you built before that is a server you have to check yourself. Start by finding out whether the endpoint exists at all, because plenty of organizations enabled the role once and never removed it.
# 1. Which hosts run the CA role, per AD rather than per memory.
$cfg = (Get-ADRootDSE).configurationNamingContext
Get-ADObject -SearchBase "CN=Enrollment Services,CN=Public Key Services,CN=Services,$cfg" `
-LDAPFilter '(objectClass=pKIEnrollmentService)' -Properties dNSHostName,name |
Select-Object name,dNSHostName
# 2. Is web enrollment answering over plain HTTP? 200 or 401 both mean yes.
'ca01.corp.example','ca02.corp.example' | ForEach-Object {
$code = try { (Invoke-WebRequest "http://$_/certsrv/" -UseBasicParsing `
-TimeoutSec 5 -ErrorAction Stop).StatusCode }
catch { $_.Exception.Response.StatusCode.value__ }
"{0,-24} http://certsrv -> {1}" -f $_, $code
}
# 3. On each CA: is Extended Protection enforced on the enrollment app?
Import-Module WebAdministration
Get-WebConfigurationProperty -PSPath 'IIS:\Sites\Default Web Site\CertSrv' `
-Filter '/system.webServer/security/authentication/windowsAuthentication' `
-Name 'extendedProtection.tokenChecking' # want Require, not None
What revocation does not undo
Here is the part that should change how you write your containment steps. A certificate is credential material with a validity period of its own, granted by your CA and honored by your domain controllers. Disabling the account does not shorten it. Resetting the password does not touch it. Reimaging the workstation it was requested from leaves it working. The three actions at the top of most incident-response checklists all operate on things the certificate does not depend on.
Revoking it is the right move and still leaves a gap. A revoked certificate stops being usable for new authentications once relying systems fetch the updated revocation list, but it does not invalidate Kerberos tickets already issued from it. A ticket-granting ticket lives ten hours by default and renews for seven days. That clock runs on its own, and clearing it is a separate action on a separate system.
The first intrusion shows what that costs when one account falls outside the automation. Attack disruption restricted the compromised identities and blocked over a thousand subsequent attempts, which is the control working. One privileged account had been excluded from automated response, stayed usable for network and remote-interactive logons, and reached a file server. There the attacker ran Rclone, renamed to SearchApp.exe, with twenty concurrent transfers and a filter selecting files up to three years old, and copied data to an external SFTP destination. Microsoft's own summary is that partial identity containment reduced the activity while leaving a viable privileged route.
Treat that as the direction of travel rather than one customer's unlucky configuration. Identity compromise increasingly hands the attacker material with an independent lifetime: issued certificates, refresh tokens, Kerberos tickets, device-bound keys, application secrets. Every one of them outlives a password reset. Containment written as account state, disable and reset and reimage, keeps getting a little further behind what it is containing. An exclusion from automated response is an incident decision that needs a named manual action attached to it, not a checkbox somebody set during a tuning exercise last year.
The audit trail you have to switch on first
Most of the detections for this story depend on logs that a default CA does not write. Enable the Certification Services advanced audit subcategory for success and failure, then set the CA's own audit filter for request and issuance events. Without both, the events below do not exist to query.
Once they do, the correlation that matters is cheap: a certificate issued to one requester, followed within seconds by a certificate-backed Kerberos ticket for a different and more privileged account.
# On the issuing CA: certificates requested (4886) and issued (4887).
Get-WinEvent -FilterHashtable @{ LogName='Security'; Id=4886,4887;
StartTime=(Get-Date).AddDays(-7) } |
Select-Object TimeCreated,Id,
@{n='Requester';e={$_.Properties[3].Value}},
@{n='Template'; e={$_.Properties[6].Value}},
@{n='Serial'; e={$_.Properties[2].Value}} |
Sort-Object TimeCreated
# On every domain controller: TGT requests that were satisfied by a certificate.
# PKINIT populates the certificate fields; password logons leave them empty.
Get-WinEvent -ComputerName dc01 -FilterHashtable @{ LogName='Security'; Id=4768;
StartTime=(Get-Date).AddDays(-7) } |
Where-Object { $_.Message -match 'Certificate Thumbprint:\s*\S' } |
Select-Object TimeCreated,
@{n='Account'; e={$_.Properties[0].Value}},
@{n='ClientIP'; e={$_.Properties[9].Value}},
@{n='CertIssuer';e={($_.Message -split 'Certificate Issuer Name:\s*')[1] -split "`n" | Select-Object -First 1}}
What a true positive looks like
- A 4887 naming a template from the ESC1 shortlist, requested by an ordinary user account.
- A 4768 carrying a certificate thumbprint for an account that was never enrolled for smart card logon.
- A machine account presenting a certificate from the Domain Controller template at a client address that is not a domain controller. That is ESC8.
- Any certificate issuance inside a session that started with Quick Assist or an inbound Teams chat from an external tenant.
Add a certificate step to your containment checklist
Write the step down before you need it, because nobody reconstructs this at 2 a.m. When an identity is compromised in a domain that runs AD CS: pull every certificate issued to or on behalf of that account from the CA database, record each serial number and thumbprint, revoke them, publish an updated revocation list, and confirm the relying systems actually retrieve it. Then go look at Kerberos separately, because the revocation did not reach the tickets. In the same hour, check whether the account was on an exclusion list, and if it was, run by hand what the automation was told to skip. Meanwhile the entry point stays boring and cheap to close: restrict which external tenants can message your people in Teams, allow one remote-support tool and alert on the rest, and tell your staff that a support request arriving unsolicited gets verified through a channel they chose.
We assess Active Directory and AD CS deployments for exactly this class of exposure, the template that was convenient in 2019 and is a domain-admin path now. If you want someone to read your template list and your enrollment endpoints with you, that is a short engagement with a concrete deliverable.
Need help hardening your identity infrastructure?
We assess Active Directory and Entra ID environments for the misconfigurations attackers actually exploit. Book a session to discuss your environment.
