Первая публично опубликованная реализация эксплойта для CVE-2026-33439 (RCE до аутентификации в OpenAM через десериализацию jato.clientSession).
Анализ человеком + помощь ИИ + reverse engineering + advisory → эксплойт
Первая публично опубликованная реализация эксплойта для CVE-2026-33439
Неаутентифицированная уязвимость десериализации Java в ForgeRock OpenAM, позволяющая выполнить полный удалённый код через специально созданные объекты сеансов JATO. Та же река течёт дважды: они исправили jato.pageSession (CVE-2021-35464) и забыли про jato.clientSession (CVE-2026-33439). Цепочка гаджетов десериализации не спрашивает учётные данные.
CVE-2026-33439 — это уязвимость удалённого выполнения кода (RCE) до аутентификации в OpenIdentityPlatform OpenAM (версии до 16.0.6). Уязвимость возникает из-за небезопасной десериализации Java HTTP-параметра jato.clientSession внутри ClientSession.deserializeAttributes(), который вызывает Encoder.deserialize() → ApplicationObjectInputStream.readObject() без применения белого списка классов.
Неаутентифицированный злоумышленник отправляет специально сформированный HTTP GET или POST запрос, содержащий сериализованный Java-объект, на любую конечную точку JATO ViewBean, чей JSP отображает теги <jato:form>. Получив запрос, сервер десериализует объект без проверки, запускает цепочку гаджетов, собранную целиком из классов, входящих в WAR-файл OpenAM — внешние библиотеки не требуются — и выполняет произвольные команды ОС от имени пользователя процесса приложения.
Вектор CVSS 4.0: AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N → 9.3 Critical
Вектор CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H → 9.8 Critical
Эта уязвимость — прямой регресс, вызванный неполным исправлением, применённым после CVE-2021-35464.
CVE-2021-35464 (ForgeRock AM / OpenAM): RCE до аутентификации через небезопасную десериализацию параметра jato.pageSession. Широко эксплуатировалась в реальных атаках; включена в список CISA KEV. Исправление ввело WhitelistObjectInputStream внутри ConsoleViewBeanBase.deserializePageAttributes() — подкласс ObjectInputStream, который проверяет имя каждого класса по жёстко заданному списку разрешённых ~40 безопасных классов перед созданием экземпляра.
CVE-2026-33439 (OpenAM ≤ 16.0.5): Исправление было применено только к jato.pageSession. Параметр jato.clientSession, обрабатываемый совершенно отдельным путём кода в ClientSession.deserializeAttributes(), не был пропатчен и по-прежнему использует нефильтрованный Encoder.deserialize() → ApplicationObjectInputStream, который вызывает ObjectInputStream.readObject() без белого списка классов.
Примитив атаки тот же. Сток десериализации другой. Изменилось только имя параметра.
JATO сериализует состояние представления UI в HTTP-параметры с именами jato.pageSession и jato.clientSession. Когда приходит запрос, OpenAM десериализует эти параметры, чтобы восстановить состояние интерфейса перед формированием ответа. Эти два параметра проходят по совершенно разным путям кода.
Исправленный путь кода (после CVE-2021-35464) для jato.pageSession:```java // PATCHED - ConsoleViewBeanBase.deserializePageAttributes() ObjectInputStream ois = new WhitelistObjectInputStream(new ByteArrayInputStream(decoded)); // class whitelist enforced - gadget chains blocked Object obj = ois.readObject();
Неисправленный путь кода для jato.clientSession (уязвимый):```java
// ClientSession.java
protected ClientSession(RequestContext context) {
this.encodedSessionString =
context.getRequest().getParameter("jato.clientSession");
}
protected void deserializeAttributes() {
if (this.encodedSessionString != null
&& this.encodedSessionString.trim().length() > 0) {
this.setAttributes(
(Map) Encoder.deserialize(
// VULNERABLE - URL-safe base64 decode then plain ObjectInputStream
Encoder.decodeHttp64(this.encodedSessionString), false)
);
}
}
Encoder.deserialize() создает обычный ApplicationObjectInputStream — подкласс ObjectInputStream без фильтрации классов. Любой класс в classpath JVM может быть инстанцирован. Десериализация запускается во время рендеринга JSP при каждом рендеринге тега < jato:form >:``` getClientSession() → hasAttributes() → getEncodedString() → isValid() → ensureAttributes() → deserializeAttributes()
---
<div id="vulnerability_affected"/>
### ***Затронутые версии***
| Продукт | Уязвимые | Исправлено |
|-----------------------------|-------------------------------------------------|--------|
| OpenIdentityPlatform OpenAM | ≤ 16.0.5 | 16.0.6 |
| ForgeRock AM (downstream) | Потенциально затронуты в зависимости от линейки патчей | - |
---
<div id="vulnerability_attacksurface"/>
### ***Поверхность атаки***
Любая конечная точка JATO ViewBean, JSP которой содержит тег *< jato:form >*, эксплуатируется без предварительной аутентификации:
| Конечная точка | Назначение |
|---------------------------|--------------------------------------|
| /ui/PWResetUserValidation | Сброс пароля - ввод идентификатора пользователя |
| /ui/PWResetQuestion | Сброс пароля - контрольные вопросы |
Конечные точки сброса пароля являются основной целью: они общедоступны по замыслу и гарантированно отображают теги *< jato:form >*.
---
---
---
<div id="gadgetchain"/>
## ***⚙️ Цепочка гаджетов***
<div id="gadgetchain_deserialization101"/>
### ***Java-десериализация 101***