
Воспроизведение CVE-2026-40859 — небезопасная десериализация тел HTTP-ответов на стороне производителя в Apache Camel camel-netty-http / camel-vertx-http (RCE)
Этот проект демонстрирует уязвимость десериализации Java в компонентах camel-netty-http и camel-vertx-http Apache Camel, отслеживаемую как CVE-2026-40859. Когда конечная точка продюсера настроена с transferException=true (или на уровне компонента allowJavaSerializedObject=true), HTTP-ответ от бэкенда с статусом ошибки и Content-Type: application/x-java-serialized-object десериализуется с помощью чистого java.io.ObjectInputStream без ObjectInputFilter. Злоумышленник, контролирующий бэкенд, с которым взаимодействует Camel продюсер — скомпрометированный сервис или атакующий «человек посередине» на незащищённом HTTP-соединении — может вернуть специально сформированный сериализованный объект и, если на пути классов присутствует цепочка гаджетов, добиться на хосте Camel.
Консультация: https://camel.apache.org/security/CVE-2026-40859.html
| Свойство | Значение |
|---|---|
| Компоненты | camel-netty-http, camel-vertx-http (сторона продюсера) |
| Затрагиваемый класс | org.apache.camel.component.netty.http.NettyHttpHelper#deserializeJavaObjectFromStream (и VertxHttpHelper#deserializeJavaObjectFromStream) |
| CWE | CWE-502: Десериализация недоверенных данных |
| Влияние | Удалённое выполнение кода (RCE) |
| Предварительное условие | transferException=true (или allowJavaSerializedObject=true) + throwExceptionOnFailure=true (по умолчанию) + контролируемый злоумышленником бэкенд |
| Затрагиваемые версии | Начиная с 4.0.0 до 4.14.8, с 4.15.0 до 4.18.3, с 4.19.0 до 4.20.0 |
| Исправленные версии | 4.14.8, 4.18.3, 4.20.0 |
| JIRA | CAMEL-23324 |
| Докладчик | Venkatraman Kumar (Securin) |
Не эксплуатируется в конфигурации по умолчанию —
transferExceptionпо умолчанию равенfalse. PoC её включает, как приложение, которому требуется распространение удалённых исключений.
При ответе, не являющемся 2xx, продюсер netty-http (с throwExceptionOnFailure=true, по умолчанию) формирует исключение из ответа через populateNettyHttpOperationFailedException. Если transferException включён и ответ содержит тип контента сериализованного объекта, он десериализует тело:
// NettyHttpHelper.populateNettyHttpOperationFailedException(...) - уязвимая версия
if (transferException) {
String contentType = response.headers().get(NettyHttpConstants.CONTENT_TYPE);
if (NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) { // application/x-java-serialized-object
InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, response);
if (is != null) {
Object body = deserializeJavaObjectFromStream(is); // <-- сток
if (body instanceof Exception) {
return (Exception) body;
}
}
}
}
// NettyHttpHelper.deserializeJavaObjectFromStream(InputStream) - уязвимая версия
ObjectInputStream ois = new ObjectInputStream(is); // НЕТ ObjectInputFilter
answer = ois.readObject(); // гаджет срабатывает здесь
Гаджет выполняется внутри readObject(), до проверки instanceof Exception — то есть полезная нагрузка не обязательно должна быть исключением. camel-vertx-http имеет идентичный сток в VertxHttpHelper.deserializeJavaObjectFromStream.
from("direct:call")
.to("netty-http://backend-host:PORT/path?transferException=true");
// throwExceptionOnFailure по умолчанию true
Любой вызов продюсера, у которого бэкенд отвечает 5xx + application/x-java-serialized-object, запускает сток.
Жертва — это продюсер Camel (он выполняет десериализацию). Злоумышленник контролирует бэкенд, к которому он обращается. В этом самодостаточном PoC обе роли выполняются в одной JVM/контейнере: встроенный HTTP-сервер с необработанными сокетами (MaliciousBackend) играет роль контролируемого злоумышленником бэкенда, а маршрут Camel (VictimRoute) является жертвой.
CVE-2026-40859/
├── pom.xml # camel-netty-http 4.18.2 + commons-collections 3.2.1 (гаджет)
├── Dockerfile # запускает приложение (с --add-opens, необходимо только для сборки гаджета)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # жертва: продюсер netty-http, transferException=true
│ ├── MaliciousBackend.java # бэкенд злоумышленника: 500 + тело сериализованного объекта на :9999
│ ├── Gadget.java # Гаджет CommonsCollections6, срабатывает во время readObject()
│ └── ExploitController.java # /exploit/attack запускает вызов продюсера
└── resources/
└── application.properties
В реальной атаке сериализованные байты создаются злоумышленником офлайн (например, с помощью ysoserial); только жертве нужна цепочка гаджетов на пути классов. Этот PoC строит гаджет в процессе для удобства, поэтому JVM запускается с
--add-opens java.base/java.util=ALL-UNNAMED— этот флаг относится к конструкции гаджета, не связан с уязвимостью.
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> producer threw ...NettyHttpOperationFailedException (ожидаемо)
#
# >>> Доказательство RCE — /tmp/pwned существует: true
docker exec cve-2026-40859 ls -la /tmp/pwned
docker compose down
Любой продюсер camel-netty-http / camel-vertx-http, настроенный с transferException=true (или allowJavaSerializedObject=true), который общается с бэкендом, контролируемым или перехватываемым злоумышленником:
http://) соединении продюсера подменяет ответ.transferException=true (или компонент allowJavaSerializedObject=true).throwExceptionOnFailure=true (по умолчанию).5xx + application/x-java-serialized-object.commons-collections:3.2.1).Обновление до 4.14.8 / 4.18.3 / 4.20.0. Исправление ограничивает оба хелпера стандартным белым списком ObjectInputFilter (java.**;javax.**;org.apache.camel.**;!*), настраиваемым через новую опцию конечной точки deserializationFilter или JVM-wide параметр -Djdk.serialFilter.
До обновления:
transferException=true / allowJavaSerializedObject=true на продюсерах, общающихся с недоверенными или сетевыми бэкендами.https) для соединений продюсера, чтобы ответы нельзя было подменить при передаче.-Djdk.serialFilter=java.**;org.apache.camel.**;!*.Этот воспроизводитель предоставлен для исследований безопасности и авторизованного тестирования, для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.