
CVE-2025-59059: Apache Ranger स्थैतिक विश्लेषण सुधार में गलत आरोपित RCE
CVE: CVE-2025-59059
प्रभावित संस्करण: Apache Ranger <= 2.7.0
समाधान: Apache Ranger 2.8.0 में
CVSS (आधिकारिक): 9.8 क्रांतिक
वास्तविक गंभीरता (तर्क सहित): ~6.0 मध्यम — नीचे विश्लेषण देखें
यह लेख किसी नए एक्सप्लॉइट या कार्यशील PoC के बारे में नहीं है। यहाँ उद्देश्य CVE-2025-59059 पर सार्वजनिक प्रकटीकरण में जो गलत है उसे सुधारना है — विशेष रूप से दो चीज़ें: गलत क्लास को संवेदनशील घटक के रूप में नामित किया गया, और CVSS स्कोर वास्तविक एक्सप्लॉइटेबिलिटी बाधाओं को प्रतिबिंबित नहीं करता। यहाँ सब कुछ Apache Ranger 2.7.0 स्रोत के स्थैतिक कोड विश्लेषण और 2.8.0 में गए पैच अंतर पर आधारित है।
आधिकारिक एडवाइज़री इस प्रकार है:
"Apache Ranger के संस्करणों <= 2.7.0 में NashornScriptEngineCreator में रिमोट कोड एक्सिक्यूशन भेद्यता की सूचना दी गई है।"
यह गलत है, या कम से कम भ्रामक है। NashornScriptEngineCreator संवेदनशील क्लास नहीं है। यदि कुछ है तो यह कोडबेस में दो Nashorn-संबंधित घटकों में से अधिक सुदृढ़ किया गया है — जिस पर हम आगे बात करेंगे।
Apache Ranger पंक्ति-स्तरीय फ़िल्टर नीतियों का मूल्यांकन करने के लिए JavaScript एक्सप्रेशन का उपयोग करता है। ये ऐसे नियम हैं जो तय करते हैं कि किसी दिए गए उपयोगकर्ता को डेटासेट में किसी विशिष्ट रिकॉर्ड तक पहुंच मिलती है या नहीं। उन एक्सप्रेशन को JVM पर चलाने के लिए, Ranger एक JavaScript इंजन एम्बेड करता है। संस्करणों <= 2.7.0 में वह इंजन Nashorn है — Oracle का बिल्ट-इन JS इंजन जो JDK 8 से 14 के साथ आया था।
एक बात जो एडवाइज़री पूरी तरह से छोड़ देती है — और यह प्रभाव के दायरे के लिए बहुत मायने रखती है — वह यह है कि jdk.nashorn.api.scripting.NashornScriptEngineFactory बिल्कुल भी Ranger के स्रोत कोड का हिस्सा नहीं है। यह एक JDK बिल्ट-इन है। इसे JDK 8 में शामिल किया गया था, JDK 11 में बहिष्कृत (deprecated) किया गया, और JDK 15 में पूरी तरह से हटा दिया गया। इसलिए यह भेद्यता केवल तभी पहुंच योग्य है जब आप JDK 8 से 14 पर Ranger चला रहे हों। JDK 15+ पर कुछ भी प्रभावित नहीं होता क्योंकि वहाँ Nashorn मौजूद ही नहीं है, और ScriptEngineUtil चुपचाप GraalJS या JavaScriptEngineCreator पर पहुँच जाता है।
Ranger में दो क्लासें Nashorn का उपयोग करती हैं। वे इसे बहुत अलग तरह से संभालती हैं।
NashornScriptEngineCreator — नामित लेकिन अधिक सुरक्षित वालास्थित:
agents-common/src/main/java/org/apache/ranger/plugin/util/NashornScriptEngineCreator.java
public class NashornScriptEngineCreator implements ScriptEngineCreator {
private static final String[] SCRIPT_ENGINE_ARGS = new String[] {
"--no-java", "--no-syntax-extensions"
};
@Override
public ScriptEngine getScriptEngine(ClassLoader clsLoader) {
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ret = factory.getScriptEngine(SCRIPT_ENGINE_ARGS, clsLoader, RangerClassFilter.INSTANCE);
...
}
private static class RangerClassFilter implements ClassFilter {
@Override
public boolean exposeToScripts(String className) {
LOG.warn("script blocked: attempt to use Java class {}", className);
return false;
}
}
}
यह क्लास वास्तव में इंजन को सुदृढ़ करने के लिए तीन काम करती है:
--no-java — स्क्रिप्ट के अंदर से java.* नेमस्पेस तक सीधी पहुंच काट देता है--no-syntax-extensions — गैर-मानक Nashorn सिंटैक्स अक्षम करता हैRangerClassFilter — सभी Java क्लास एक्सेस को ClassFilter स्तर पर ब्लॉक करता है, हर चीज़ के लिए false लौटाता हैक्या यह बुलेटप्रूफ है? नहीं। रिफ्लेक्शन चेन और java.lang.invoke ट्रिक्स के माध्यम से Nashorn ClassFilter बायपास मौजूद हैं। लेकिन यह दूसरी क्लास में जो मिलता है उसकी तुलना में अर्थपूर्ण रूप से अधिक लॉक-डाउन है।
RecordFilterJavaScript — वास्तविक संवेदनशील क्लासस्थित:
plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
public class RecordFilterJavaScript {
static class SecurityFilter implements ClassFilter {
@Override
public boolean exposeToScripts(String s) {
return false;
}
boolean containsMalware(String filterExpr) {
// only checks for this one specific string
return filterExpr.contains("this.engine");
}
}
public static boolean filterRow(String user, String filterExpr, String jsonString) {
SecurityFilter securityFilter = new SecurityFilter();
if (securityFilter.containsMalware(filterExpr)) {
throw new MaskingException("cannot process filter expression due to security concern...");
}
// instantiates Nashorn directly — no --no-java, no --no-syntax-extensions
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(securityFilter);
String script = " jsonAttr = JSON.parse(jsonString); " + filterExpr;
Bindings bindings = engine.createBindings();
bindings.put("jsonString", jsonString);
bindings.put("user", user);
boolean hasAccess = (boolean) engine.eval(script, bindings);
...
}
}
इसे NashornScriptEngineCreator से तुलना करें और अंतर बिल्कुल स्पष्ट है:
--no-java फ़्लैग नहीं — java.* नेमस्पेस स्क्रिप्ट के लिए पूरी तरह खुला है--no-syntax-extensions नहींfilterExpr.contains("this.engine")filterExpr सीधे उस स्क्रिप्ट में संयोजित किया जाता है जिसे Nashorn मूल्यांकित करता हैक्योंकि --no-java पास नहीं किया गया है, java.* नेमस्पेस पूरी तरह सुलभ है। आपको किसी भी बायपास तकनीक की बिल्कुल आवश्यकता नहीं है:
var runtime = java.lang.Runtime.getRuntime();
runtime.exec("id");
वहाँ कहीं भी this.engine नहीं है। ब्लैकलिस्ट इस हमले के मार्ग के लिए पूरी तरह अप्रासंगिक है।
दिलचस्प बात यह है कि डेवलपर्स स्पष्ट रूप से कम से कम एक बायपास पैटर्न के बारे में जानते थे। टेस्ट फ़ाइल TestRecordFilterJavaScript.java में यह है:
RecordFilterJavaScript.filterRow("user",
"this.engine.factory.scriptEngine.eval('java.lang.Runtime.getRuntime().exec(\"/Applications/Spotify.app/Contents/MacOS/Spotify\")')",
...);
वह टेस्ट यह पुष्टि करने के लिए मौजूद है कि this.engine ब्लॉक हो जाता है। जो ब्लॉक नहीं हुआ वह सीधा java.* मार्ग है, जिसे this.engine की बिल्कुल आवश्यकता नहीं है।
RecordFilterJavaScript.filterRow() केवल एक स्थान से कॉल होता है:
plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/NestedStructureAuthorizer.java
private boolean hasAccessToRecord(String schema, String user, ..., String jsonString, ...) {
RangerAccessResult result = plugin.evalRowFilterPolicies(request, null);
if (result.isRowFilterEnabled()) {
String filterExpr = result.getFilterExpr();
ret = RecordFilterJavaScript.filterRow(user, filterExpr, jsonString);
}
return ret;
}
filterExpr result.getFilterExpr() से आता है — यह JavaScript एक्सप्रेशन है जो Ranger पंक्ति फ़िल्टर नीति में संग्रहीत होता है। नीति प्रशासक विशेषाधिकार वाला हमलावर उस एक्सप्रेशन को जो चाहे सेट कर सकता है। जब कोई उपयोगकर्ता उस नीति द्वारा शासित किसी संसाधन तक पहुँचता है, तो hasAccessToRecord() सक्रिय होता है, नीति भंडार से filterExpr खींचता है, और filterRow() इसे लगभग बिना किसी सैंडबॉक्सिंग के Nashorn को सौंप देता है।
हमले की श्रृंखला:
नीति प्रशासक पहुँच
|
v
nestedstructure संसाधन पर पंक्ति फ़िल्टर नीति बनाएँ/संशोधित करें
|
v
filterExpr सेट किया गया: java.lang.Runtime.getRuntime().exec("...")
|
v
कोई भी उपयोगकर्ता संसाधन तक पहुँचता है → hasAccessToRecord() ट्रिगर होता है
|
v
filterExpr filterRow() में प्रवाहित होता है → Nashorn मूल्यांकन → RCE