Java SignedObject-gated Deserialization and Pre-auth Reachability via Error Paths
Reading time: 7 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:
HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
यह पृष्ठ java.security.SignedObject के इर्द‑गिर्द बने एक सामान्य "guarded" Java deserialization पैटर्न और यह दर्शाता है कि कैसे दिखने में अप्राप्य sinks त्रुटि-हैंडलिंग प्रवाहों के माध्यम से pre-auth पहुँच योग्य बन सकते हैं। यह तकनीक Fortra GoAnywhere MFT (CVE-2025-10035) में देखी गई थी, लेकिन समान डिज़ाइनों पर भी लागू है।
Threat model
- Attacker एक HTTP endpoint तक पहुँच सकता है जो अंततः attacker-supplied byte[] को प्रोसेस करता है, जो कि एक serialized SignedObject के रूप में भेजा गया है।
- कोड एक validating wrapper (e.g., Apache Commons IO ValidatingObjectInputStream या एक custom adapter) का उपयोग करता है ताकि सबसे बाहरी प्रकार को SignedObject (या byte[]) तक सीमित किया जा सके।
- SignedObject.getObject() द्वारा लौटाया गया inner object वह जगह है जहाँ gadget chains ट्रिगर कर सकते हैं (e.g., CommonsBeanutils1), परन्तु यह केवल signature verification gate के बाद होता है।
Typical vulnerable pattern
A simplified example based on com.linoma.license.gen2.BundleWorker.verify:
private static byte[] verify(byte[] payload, KeyConfig keyCfg) throws Exception {
String sigAlg = "SHA1withDSA";
if ("2".equals(keyCfg.getVersion())) {
sigAlg = "SHA512withRSA"; // key version controls algorithm
}
PublicKey pub = getPublicKey(keyCfg);
Signature sig = Signature.getInstance(sigAlg);
// 1) Outer, "guarded" deserialization restricted to SignedObject
SignedObject so = (SignedObject) JavaSerializationUtilities.deserialize(
payload, SignedObject.class, new Class[]{ byte[].class });
if (keyCfg.isServer()) {
// Hardened server path
return ((SignedContainer) JavaSerializationUtilities.deserializeUntrustedSignedObject(
so, SignedContainer.class, new Class[]{ byte[].class }
)).getData();
} else {
// 2) Signature check using a baked-in public key
if (!so.verify(pub, sig)) {
throw new IOException("Unable to verify signature!");
}
// 3) Inner object deserialization (potential gadget execution)
SignedContainer inner = (SignedContainer) so.getObject();
return inner.getData();
}
}
Key observations:
- The validating deserializer at (1) blocks arbitrary top-level gadget classes; only SignedObject (or raw byte[]) is accepted.
- The RCE primitive would be in the inner object materialized by SignedObject.getObject() at (3).
- A signature gate at (2) enforces that the SignedObject must verify against a product-baked public key. Unless the attacker can produce a valid signature, the inner gadget never deserializes.
Exploitation considerations
कोड निष्पादन हासिल करने के लिए, एक हमलावर को एक सही तरीके से साइन किया गया SignedObject पहुंचाना होगा जो अपने inner object के रूप में एक malicious gadget chain को रैप करता है। इसके लिए सामान्यतः निम्न में से एक चाहिए:
- Private key compromise: उत्पाद द्वारा license objects को साइन/वेरिफाई करने के लिए उपयोग किए गए मिलान करने वाले private key को प्राप्त करना।
- Signing oracle: vendor या किसी trusted signing service को बाध्य करना ताकि वे attacker-controlled serialized content पर साइन करें (उदा., यदि कोई license server client input से embedded arbitrary object पर साइन करता है)।
- Alternate reachable path: ऐसा server-side path ढूँढना जो inner object को verify() लागू किए बिना deserialize कर दे, या जो किसी specific mode में signature checks को स्किप कर दे।
इनमें से किसी के अभाव में, signature verification deserialization sink मौजूद होने के बावजूद exploitation को रोकेगा।
Pre-auth reachability via error-handling flows
यहां तक कि जब एक deserialization endpoint लग रहा हो कि वह authentication या एक session-bound token की मांग करता है, error-handling code अनायास ही token को mint करके unauthenticated session से जोड़ सकता है।
Example reachability chain (GoAnywhere MFT):
- Target servlet: /goanywhere/lic/accept/
requires a session-bound license request token. - Error path: hitting /goanywhere/license/Unlicensed.xhtml with trailing junk and invalid JSF state triggers AdminErrorHandlerServlet, which does:
- SessionUtilities.generateLicenseRequestToken(session)
- Redirects to vendor license server with a signed license request in bundle=<...>
- The bundle can be decrypted offline (hard-coded keys) to recover the GUID. Keep the same session cookie and POST to /goanywhere/lic/accept/
with attacker-controlled bundle bytes, reaching the SignedObject sink pre-auth.
Proof-of-reachability (impact-less) probe:
GET /goanywhere/license/Unlicensed.xhtml/x?javax.faces.ViewState=x&GARequestAction=activate HTTP/1.1
Host: <target>
- अनपैच्ड: 302 Location header to https://my.goanywhere.com/lic/request?bundle=... and Set-Cookie: ASESSIONID=...
- पैच्ड: redirect without bundle (no token generation).
ब्लू-टीम डिटेक्शन
stack traces/logs में मौजूद संकेत स्पष्ट रूप से SignedObject-gated sink को हिट करने के प्रयासों का सुझाव देते हैं:
java.io.ObjectInputStream.readObject
java.security.SignedObject.getObject
com.linoma.license.gen2.BundleWorker.verify
com.linoma.license.gen2.BundleWorker.unbundle
com.linoma.license.gen2.LicenseController.getResponse
com.linoma.license.gen2.LicenseAPI.getResponse
com.linoma.ga.ui.admin.servlet.LicenseResponseServlet.doPost
हार्डनिंग मार्गदर्शन
- किसी भी getObject() कॉल से पहले सिग्नेचर सत्यापन बनाए रखें और सुनिश्चित करें कि सत्यापन इच्छित public key/algorithm का उपयोग कर रहा है।
- प्रत्यक्ष SignedObject.getObject() कॉल्स को एक हार्डन्ड wrapper से बदलें जो inner stream पर फ़िल्टरिंग को दोबारा लागू करे (उदा., deserializeUntrustedSignedObject using ValidatingObjectInputStream/ObjectInputFilter allow-lists)।
- ऐसे error-handler flows हटाएँ जो अप्रमाणित उपयोगकर्ताओं के लिए session-bound tokens जारी करते हैं। error paths को attack surface के रूप में मानें।
- बाहरी और आंतरिक दोनों deserializations के लिए कठोर allow-lists के साथ Java serialization filters (JEP 290) को प्राथमिकता दें। उदाहरण:
ObjectInputFilter filter = info -> {
Class<?> c = info.serialClass();
if (c == null) return ObjectInputFilter.Status.UNDECIDED;
if (c == java.security.SignedObject.class || c == byte[].class) return ObjectInputFilter.Status.ALLOWED;
return ObjectInputFilter.Status.REJECTED; // outer layer
};
ObjectInputFilter.Config.setSerialFilter(filter);
// For the inner object, apply a separate strict DTO allow-list
उदाहरण हमला चेन सारांश (CVE-2025-10035)
- Pre-auth token minting via error handler:
GET /goanywhere/license/Unlicensed.xhtml/watchTowr?javax.faces.ViewState=watchTowr&GARequestAction=activate
302 प्राप्त करें जिसमें bundle=... और ASESSIONID=...; bundle को offline में decrypt करके GUID पुनर्प्राप्त करें।
- वही cookie के साथ pre-auth में sink तक पहुँचें:
POST /goanywhere/lic/accept/<GUID> HTTP/1.1
Cookie: ASESSIONID=<value>
Content-Type: application/x-www-form-urlencoded
bundle=<attacker-controlled-bytes>
- RCE के लिए सही तरह से साइन किया गया SignedObject होना आवश्यक है जो एक gadget chain को wrap करता है। शोधकर्ताओं द्वारा signature verification को bypass नहीं किया जा सका; exploit करने के लिए matching private key या signing oracle तक पहुँच अनिवार्य है।
फिक्स किए गए संस्करण और व्यवहार में बदलाव
- GoAnywhere MFT 7.8.4 and Sustain Release 7.6.3:
- Inner deserialization को सख्त करें by replacing SignedObject.getObject() with a wrapper (deserializeUntrustedSignedObject).
- error-handler token generation को हटाएँ, जिससे pre-auth reachability बंद हो जाती है।
JSF/ViewState पर नोट्स
यह reachability trick एक JSF पेज (.xhtml) और invalid javax.faces.ViewState का उपयोग करके privileged error handler में रूट करती है। जबकि यह JSF deserialization समस्या नहीं है, यह एक दोहराने वाला pre-auth पैटर्न है: ऐसे error handlers में तोड़ फोड़ करना जो privileged actions करते हैं और security-relevant session attributes सेट करते हैं।
References
- watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035
- Fortra advisory FI-2025-012 – Deserialization Vulnerability in GoAnywhere MFT's License Servlet
tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:
HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
HackTricks