Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2025-59059-Misattributed-RCE-in-Apache-Ranger-Static-Analysis-Correction — CVE-2025-59059: تصحيح التحليل الساكن لثغرة RCE المنسوبة بشكل خاطئ في Apache Ranger | Kitploit
أدوات/GitHubGitHub/pl4tyz/cve-2025-59059-misattributed-rce-in-apache-ranger-static-analysis-correction
التحليل الثابتتحليل الثغرات الأمنيةتحليل الكودالاستغلالأمن الويبالتعلم والتعليم
GitHubpl4tyz/cve-2025-59059-misattributed-rce-in-apache-ranger-static-analysis-correction

CVE-2025-59059-Misattributed-RCE-in-Apache-Ranger-Static-Analysis-Correction

CVE-2025-59059: تصحيح التحليل الساكن لثغرة RCE المنسوبة بشكل خاطئ في Apache Ranger

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
عرض المستودع
15منذ 5 أشهرلم تتم المراجعة بعد
مشاركة

CVE-2025-59059: RCE منسوبة بشكل خاطئ إلى Apache Ranger تصحيح

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 المصدرية وفرق التصحيح (patch diff) الذي دخل في الإصدار 2.8.0.


ما تقوله النشرة الأمنية

النشرة الأمنية الرسمية تقول:

"تم الإبلاغ عن ثغرة تنفيذ الأكواد عن بُعد في NashornScriptEngineCreator في Apache Ranger الإصدارات <= 2.7.0."

هذا خطأ، أو على الأقل مضلل. NashornScriptEngineCreator ليست الفئة المعرّضة للثغرة. إن وُجد شيء، فهي الأكثر تحصينًا بين المكوّنين المرتبطين بـ Nashorn في قاعدة الشيفرة — وسنصل إلى ذلك.


خلفية: Nashorn في Apache Ranger

يستخدم Apache Ranger تعبيرات JavaScript لتقييم سياسات تصفية الصفوف (row-level filter policies). وهي قواعد تحدّد ما إذا كان مستخدم معيّن سيحصل على حق الوصول إلى سجلّ محدّد داخل مجموعة بيانات. لتشغيل تلك التعبيرات فعليًا على JVM، يضمّن Ranger محرّك JavaScript. في الإصدارات <= 2.7.0 يكون هذا المحرك هو Nashorn، محرّك JS المدمج من Oracle والذي جاء مع JDK 8 حتى 14.

أمر واحد تحذفه النشرة تمامًا — وهو أمر مهم جدًا لتحديد نطاق الأثر — هو أن jdk.nashorn.api.scripting.NashornScriptEngineFactory ليس جزءًا من شيفرة Ranger المصدرية إطلاقًا. إنه مكوّن مدمج في JDK. فقد كان مشمولًا في JDK 8، وأصبح مهملًا (deprecated) في JDK 11، وأُزيل كليًا في JDK 15. لذلك لا يمكن الوصول إلى هذه الثغرة إلا إذا كنت تشغّل Ranger على JDK 8 حتى 14. أي شيء يعمل على JDK 15+ غير متأثر لأن Nashorn ببساطة غير موجود هناك، وScriptEngineUtil يمرّر بصمت إلى GraalJS أو JavaScriptEngineCreator.

هناك فئتان في Ranger تستخدمان Nashorn، وتتعاملان معه بطريقة مختلفة جدًا.


الفئتان المرتبطتان بـ Nashorn

1. NashornScriptEngineCreator — الفئة المذكورة لكنها الأكثر أمانًا

تقع في:

root@kitploit:~
agents-common/src/main/java/org/apache/ranger/plugin/util/NashornScriptEngineCreator.java
root@kitploit:~
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 لكل شيء

هل هي منيعة تمامًا؟ لا. توجد طرق لتجاوز ClassFilter في Nashorn عبر سلاسل reflection وحيل java.lang.invoke. لكنها أكثر تقييدًا بشكل ملموس مما نجده في الفئة الأخرى.


2. RecordFilterJavaScript — الفئة المعرّضة للثغرة فعليًا

تقع في:

root@kitploit:~
plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
root@kitploit:~
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.* يمكن الوصول إليه بالكامل. لا تحتاج إلى أي تقنية تجاوز إطلاقًا:

root@kitploit:~
var runtime = java.lang.Runtime.getRuntime();
runtime.exec("id");

لا يوجد this.engine في أي مكان هنا. والقائمة السوداء غير ذات صلة إطلاقًا بمسار الهجوم هذا.

المثير للاهتمام أن المطوّرين كانوا يعرفون بوضوح نمط تجاوز واحدًا على الأقل. ملف الاختبار TestRecordFilterJavaScript.java يحتوي على هذا:

root@kitploit:~
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() تُستدعى من مكان واحد فقط:

root@kitploit:~
plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/NestedStructureAuthorizer.java
root@kitploit:~
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. يمكن للمهاجم الذي يملك صلاحيات إدارة السياسات (policy admin) ضبط هذا التعبير على ما يشاء. عندما يصل أي مستخدم إلى مورد محكوم بتلك السياسة، يتم تشغيل hasAccessToRecord()، وتسحب filterExpr من مخزن السياسات، وتسلمها filterRow() إلى Nashorn دون أي عزل فعلي تقريبًا.

سلسلة الهجوم:

root@kitploit:~
Policy admin access
       |
       v
Create/modify a row filter policy on a nestedstructure resource
       |
       v
filterExpr set to: java.lang.Runtime.getRuntime().exec("...")
       |
       v
Any user accesses the resource → hasAccessToRecord() triggered
       |
       v
filterExpr flows into filterRow() → Nashorn evaluates it → RCE

فرق التصحيح

يُتتبَّع الإصلاح باسم RANGER-4076: Remove Nashorn Script Engine، وتم تنفيذه في 8 ديسمبر 2025 بواسطة Kishor Gollapalliwar. سُحب من أرشيف رسائل الالتزامات في القائمة البريدية لـ Apache. ثلاثة ملفات تغيّرت، 27 إضافة، 81 حذفًا.

root@kitploit:~
commit 923a8473de2985cd389d45062cd4717d5ca13235
Author: Kishor Gollapalliwar
AuthorDate: Mon Dec 8 14:55:56 2025 +0530

    RANGER-4076: Remove Nashorn Script Engine

 .../plugin/util/NashornScriptEngineCreator.java    | 67 ----------------------
 .../ranger/plugin/util/ScriptEngineUtil.java       |  7 +--
 .../authorizer/RecordFilterJavaScript.java         | 34 ++++++++---
 3 files changed, 27 insertions(+), 81 deletions(-)

الملف 1: NashornScriptEngineCreator.java — حُذف بالكامل

root@kitploit:~
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/NashornScriptEngineCreator.java
deleted file mode 100644
index b890fe85d..000000000
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/NashornScriptEngineCreator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.apache.ranger.plugin.util;
-
-import jdk.nashorn.api.scripting.ClassFilter;
-import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
-
-public class NashornScriptEngineCreator implements ScriptEngineCreator {
-
-    private static final String[] SCRIPT_ENGINE_ARGS = new String[] {
-        "--no-java", "--no-syntax-extensions"
-    };
-    private static final String ENGINE_NAME = "NashornScriptEngine";
-
-    @Override
-    public ScriptEngine getScriptEngine(ClassLoader clsLoader) {
-        ScriptEngine ret = null;
-        if (clsLoader == null) {
-            clsLoader = getDefaultClassLoader();
-        }
-        try {
-            NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
-            ret = factory.getScriptEngine(SCRIPT_ENGINE_ARGS, clsLoader, RangerClassFilter.INSTANCE);
-        } catch (Throwable t) {
-            LOG.debug("NashornScriptEngineCreator.getScriptEngine(): failed to create engine type {}", ENGINE_NAME, t);
-        }
-        return ret;
-    }
-
-    private static class RangerClassFilter implements ClassFilter {
-        static final RangerClassFilter INSTANCE = new RangerClassFilter();
-
-        @Override
-        public boolean exposeToScripts(String className) {
-            LOG.warn("script blocked: attempt to use Java class {}", className);
-            return false;
-        }
-    }
-}

الملف 2: ScriptEngineUtil.java — إزالة Nashorn من سلسلة منشئي المحركات

root@kitploit:~
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
@@ -28,10 +28,9 @@
 public class ScriptEngineUtil {

-    private static final String   SCRIPT_ENGINE_CREATOR_NASHHORN =
-        "org.apache.ranger.plugin.util.NashornScriptEngineCreator";
     private static final String   SCRIPT_ENGINE_CREATOR_GRAAL    =
         "org.apache.ranger.plugin.util.GraalScriptEngineCreator";
     private static final String   SCRIPT_ENGINE_CREATOR_JS       =
         "org.apache.ranger.plugin.util.JavaScriptEngineCreator";
-    private static final String[] SCRIPT_ENGINE_CREATORS = new String[] {
-        SCRIPT_ENGINE_CREATOR_NASHHORN,
-        SCRIPT_ENGINE_CREATOR_GRAAL,
-        SCRIPT_ENGINE_CREATOR_JS
-    };
+    private static final String[] SCRIPT_ENGINE_CREATORS = new String[] {
+        SCRIPT_ENGINE_CREATOR_GRAAL,
+        SCRIPT_ENGINE_CREATOR_JS
+    };

@@ -108,9 +107,7 @@ private static void initScriptEngineCreator(String serviceType) {
         } catch (Throwable t) {
             boolean logWarn;

-            if (creatorClsName.equals(SCRIPT_ENGINE_CREATOR_NASHHORN)) {
-                logWarn = JVM_MAJOR_CLASS_VERSION < JVM_MAJOR_CLASS_VERSION_JDK15;
-            } else if (creatorClsName.equals(SCRIPT_ENGINE_CREATOR_GRAAL)) {
+            if (creatorClsName.equals(SCRIPT_ENGINE_CREATOR_GRAAL)) {
                 logWarn = JVM_MAJOR_CLASS_VERSION >= JVM_MAJOR_CLASS_VERSION_JDK15;
             } else {
                 logWarn = true;

الملف 3: RecordFilterJavaScript.java — الإصلاح الفعلي

هنا يكمن التغيير الأمني الفعلي. استدعاء NashornScriptEngineFactory المباشر يُستبدل بـ GraalJS، وSecurityFilter تفقد دورها كـ ClassFilter تمامًا وتُخفَّض إلى فئة عادية لا تملك سوى فحص النص.

root@kitploit:~
diff --git a/plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
--- a/plugin-nestedstructure/.../RecordFilterJavaScript.java
+++ b/plugin-nestedstructure/.../RecordFilterJavaScript.java
@@ -18,13 +18,16 @@
-import jdk.nashorn.api.scripting.ClassFilter;
-import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngineManager;
+import java.util.HashMap;
+import java.util.Map;

@@ -54,8 +57,25 @@
         if (securityFilter.containsMalware(filterExpr)) {
             throw new MaskingException("cannot process filter expression...");
         }

-        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
-        ScriptEngine engine = factory.getScriptEngine(securityFilter);
+        ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
+        ScriptEngineManager mgr = new ScriptEngineManager(clsLoader);
+        ScriptEngine engine = mgr.getEngineByName("graal.js");
+
+        if (engine != null) {
+            try {
+                Map<String, Boolean> graalVmConfigs = new HashMap<>();
+                graalVmConfigs.put("polyglot.js.allowHostAccess", Boolean.TRUE);
+                graalVmConfigs.put("polyglot.js.nashorn-compat", Boolean.TRUE);
+
+                Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+                bindings.putAll(graalVmConfigs);
+                engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+            } catch (Throwable t) {
+                logger.debug("RecordFilterJavaScript.filterRow(): failed to create engine type {}", "graal.js", t);
+            }
+        }

@@ -83,12 +103,8 @@
-    static class SecurityFilter implements ClassFilter {
-        @Override
-        public boolean exposeToScripts(String s) {
-            return false;
-        }
-
+    static class SecurityFilter {
         boolean containsMalware(String filterExpr) {
             return filterExpr.contains("this.engine");
         }
     }

بعض الأمور الجديرة بالذكر من هذا الفرق:

  • SecurityFilter لم تعد ClassFilter، فقدت خطافها على مستوى المحرك وأصبحت مجرد فئة عادية بقيت فيها فقط فحص النص
  • استيرادات Nashorn اختفت، واستُبدلت بـ ScriptEngineManager
  • يعمل GraalJS في وضع nashorn-compat من أجل التوافق العكسي مع تعبيرات السياسات الحالية
  • polyglot.js.allowHostAccess مضبوط على true — هذه مقايضة من أجل التوافق العكسي، وتعتمد على صندوق الرمل الخاص بـ GraalJS بدلاً من ClassFilter. يجدر مراقبتها إذا كنت تهتم بجودة الإصلاح

يجعل التصحيح من الواضح أن RecordFilterJavaScript هي الهدف الأمني الفعلي. حذف NashornScriptEngineCreator كان تنظيفًا، وليس الإصلاح.


لماذا سمّى CVE الفئة الخاطئة

بصراحة، ليس من الصعب فهم كيف حدث ذلك. NashornScriptEngineCreator موجودة مباشرة في agents-common، وهي الفئة الأكثر وضوحًا من حيث الاسم المرتبط بـ Nashorn في قاعدة الشيفرة بأكملها، وأي بحث grep بسيط عن Nashorn سيُظهرها فورًا. أما RecordFilterJavaScript فهي تعيش في plugin-nestedstructure، وهو وحدة فرعية منفصلة، ولا يوجد في اسمها أي ما يلمّح إلى Nashorn. أي شخص يقوم بفرز سريع دون تتبّع مسار الشيفرة فعليًا سيستقر غالبًا على NashornScriptEngineCreator ويتوقف عندها.

يبدو أن هذا هو ما حدث هنا. الفئة المعرّضة للثغرة والفئة التي ذُكرت في النشرة شيئان مختلفان.


لماذا لا تصمد درجة CVSS 9.8

درجة 9.8 تعني قابلية الوصول عبر الشبكة، دون الحاجة إلى مصادقة، ودون تفاعل من المستخدم. الواقع مختلف تمامًا:

العاملالواقع
المصادقةتتطلب صلاحيات إدارة السياسات في Ranger
اشتراط البرنامج المساعدplugin-nestedstructure ليس مفعّلًا افتراضيًا
قيد JDKقابل للاستغلال فقط على JDK 8–14، وJDK 15+ غير متأثر
التعرض عبر الشبكةبصمة FOFA أرجعَت حوالي 35 مثيل Ranger مكشوفًا علنًا

لا ينعكس أي من ذلك في النشرة. لاستغلال هذا فعليًا تحتاج إلى صلاحيات إدارة السياسات، وهو مستوى امتياز كبير داخل نشر Ranger. هذه ليست RCE بدون مصادقة. عند احتساب شرط المصادقة والبرنامج المساعد غير الافتراضي، فإن درجة في نطاق 6.0–7.0 ستكون أكثر صدقًا.


ملخص

ادعاء النشرةالنتيجة الفعلية
الفئة المعرّضةNashornScriptEngineCreatorRecordFilterJavaScript
نوع الهجومRCE بدون مصادقةRCE بمصادقة (تتطلب صلاحيات إدارة السياسات)
JDK المتأثرغير محددJDK 8–14 فقط
البرنامج المساعد المطلوبغير محددplugin-nestedstructure (غير افتراضي)
CVSS9.8 حرجة~6.0 متوسطة (وفق الحجة)
التعرض للإنترنتغير محددحوالي 35 مثيلًا (FOFA)

الثغرة حقيقية والترقية إلى 2.8.0 هي القرار الصحيح. لكن النشرة تخطئ في تحديد الفئة، ودرجة الخطورة لا تعكس ما هو مطلوب فعليًا لاستغلال هذه الثغرة.


المراجع

  • إصدار Apache Ranger 2.8.0: https://ranger.apache.org/download.html
  • التزام التصحيح (RANGER-4076): https://gitbox.apache.org/repos/asf/ranger.git
  • سجل CVE: https://www.cve.org/CVERecord?id=CVE-2025-59059
  • سلسلة القائمة البريدية لـ Apache: https://lists.apache.org/thread/z47q86rho80390lf2qcmoc2josvs0gtv
تنزيل الأداة