
CVE-2026-49268 — Analisi e correzione di una vulnerabilità di bypass dell'autenticazione tramite LDAP Injection
| Branch | 1.13-CVE-2026-49268 |
| Autore | Jinwoo Hwang (https://JinwooHwang.com) |
Questo branch (1.13-CVE-2026-49268) contiene una remediation di sicurezza completa di una Vulnerabilità di LDAP Injection Authentication Bypass in Apache Shiro versione 1.13.
Descrizione ufficiale NVD
Un attaccante remoto può iniettare caratteri speciali LDAP nella costruzione del Distinguished Name (DN) nella classe DefaultLdapRealm. L'input del nome utente fornito dall'utente viene concatenato direttamente nel template LDAP DN senza alcun escaping dei caratteri speciali RFC 2253. Ciò consente a un attaccante di manipolare la struttura del DN utilizzata per l'autenticazione bind LDAP, potenzialmente aggirando l'autenticazione o impersonando altri utenti. Questo problema riguarda tutte le versioni di Apache Shiro fino alla 2.2.0, e 3.0.0-alpha-1 quando si utilizza DefaultLdapRealm.
| Campo | Valore |
|---|---|
| CVE | CVE-2026-49268 — Apache Shiro: LDAP DN Injection in DefaultLdapRealm |
| CWE ID | CWE-90 — Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection') |
| CVSS v4.0 | 8.8 HIGH — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N/S:P/AU:Y/R:A/RE:L/U:Red |
| CVSS v3.1 | 9.1 CRITICAL — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| Versioni interessate | org.apache.shiro:shiro-core dalla 0 alla 2.2.0 inclusa; dalla 3.0.0-alpha-0 alla 3.0.0-alpha-1 inclusa |
| Corretto upstream in | 2.2.1 e 3.0.0-alpha-2 |
| Riferimento | https://lists.apache.org/thread/svszql3od8td7hn6conyj2oq70v53b5s |
Apache Shiro può autenticare gli utenti su una directory LDAP. Per farlo, trasforma un
nome utente inviato in un Distinguished Name — l'indirizzo della directory per l'entry di quell'utente
— inserendo il nome utente in un template configurato, ad esempio
uid={0},ou=users,dc=mycompany,dc=com.
Nelle versioni interessate il nome utente viene incollato in quel template come testo grezzo. Alcuni caratteri di punteggiatura — soprattutto la virgola — non sono testo ordinario per un directory server; sono la sintassi che separa una parte di un indirizzo dalla successiva. Un nome utente che contiene quei caratteri smette quindi di comportarsi come un valore all'interno dell'indirizzo e inizia a comportarsi come parte dell'indirizzo stesso.
La conseguenza pratica è che una persona che effettua il login può influenzare quale entry della directory Shiro tenta di autenticare, invece di fornire soltanto il proprio nome. Anziché essere cercata nel container previsto dal deployment, la ricerca può essere reindirizzata altrove nella directory. A seconda di come è strutturata la directory e di cosa permette, ciò può portare ad autenticarsi con l'identità sbagliata, o a un'autenticazione che riesce quando non dovrebbe.
Profilo di rischio. Ciò che aumenta il rischio: non sono richiesti accesso o credenziali precedenti — l'input
arriva al confine di login, che è raggiungibile da chiunque possa raggiungere
l'applicazione; e la classe interessata è il modo standard e documentato per collegare Shiro a LDAP,
quindi non si tratta di una configurazione esotica. Ciò che lo riduce: il deployment deve effettivamente utilizzare
DefaultLdapRealm (o JndiLdapRealm) con un template DN configurato; i deployment che
si autenticano con altri mezzi, o che passano un DN completo o una credenziale non testuale come un
certificato, non sono interessati. Se una ricerca reindirizzata produca un'autenticazione utilizzabile
dipende anche dalla struttura e dalle regole di accesso della directory di destinazione, che variano da sito a sito.
Una seconda conseguenza, non di sicurezza, merita di essere notata per la pianificazione del rilascio: gli utenti i cui
nomi utente legittimi contengono un backslash o iniziano con # attualmente non possono effettuare il login
affatto, perché l'indirizzo costruito per loro non è un nome ben formato e viene rifiutato
direttamente. Altra punteggiatura non fallisce direttamente — cambia silenziosamente a quale entry
si riferisce l'indirizzo, che è il problema di sicurezza di cui sopra. La stessa correzione risolve entrambi.
core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java, getUserDn(String),
righe 227–250 sulla baseline non corretta:```java
protected String getUserDn(String principal) throws IllegalArgumentException, IllegalStateException {
if (!StringUtils.hasText(principal)) {
throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction.");
}
String prefix = getUserDnPrefix();
String suffix = getUserDnSuffix();
if (prefix == null && suffix == null) {
log.debug("userDnTemplate property has not been configured, indicating the submitted "
+ "AuthenticationToken's principal is the same as the User DN. Returning the method argument "
+ "as is.");
return principal;
}
int prefixLength = prefix != null ? prefix.length() : 0;
int suffixLength = suffix != null ? suffix.length() : 0;
StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
if (prefixLength > 0) {
sb.append(prefix);
}
sb.append(principal); // <-- inserted verbatim
if (suffixLength > 0) {
sb.append(suffix);
}
return sb.toString();
}
Il template viene suddiviso una volta, in fase di configurazione, attorno al token `{0}`
(`setUserDnTemplate`, righe 181–200), in un `prefix` e un `suffix`. Al momento dell'autenticazione
il principal viene concatenato tra di essi. **Non viene applicata alcuna codifica in nessun punto.** Non esiste
alcun helper di escaping da nessuna parte in `org/apache/shiro/realm/ldap/`.
### 3.2 L'invariante che era assunto ma mai applicato
Il codice circostante tratta il risultato di `getUserDn` come un Distinguished Name ben formato —
viene passato direttamente a `LdapContextFactory.getLdapContext(...)` e da lì a JNDI come
bind DN. Ciò è corretto solo se il principal sostituito è un *singolo valore di attributo*.
La concatenazione di stringhe non può garantirlo. RFC 2253 (e RFC 4514) riservano
`,` `+` `"` `\` `<` `>` `;` `=`, un `#` iniziale e gli spazi bianchi iniziali/finali come sintassi
strutturale all'interno di un DN. Quando uno qualsiasi di questi caratteri appare nel principal, essi vengono letti dal parser come
struttura, non come contenuto. L'invariante — *"il principal occupa esattamente un valore RDN"* —
era assunto da ogni consumatore a valle e applicato da nessuno.