Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2025-59059-Misattributed-RCE-in-Apache-Ranger-Static-Analysis-Correction — CVE-2025-59059 : Correction d'analyse statique pour une RCE mal attribuée dans Apache Ranger | Kitploit
Outils/GitHubGitHub/pl4tyz/cve-2025-59059-misattributed-rce-in-apache-ranger-static-analysis-correction
Analyse StatiqueAnalyse des VulnérabilitésAnalyse de CodeExploitationSécurité WebApprentissage et Éducation
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 : Correction d'analyse statique pour une RCE mal attribuée dans Apache Ranger

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
Voir le dépôt
il y a 4 moisPas encore vérifié

CVE-2025-59059 : RCE mal attribuée dans Apache Ranger — une correction

CVE : CVE-2025-59059
Versions affectées : Apache Ranger <= 2.7.0
Corrigé dans : Apache Ranger 2.8.0
CVSS (officiel) : 9.8 Critique
Sévérité réelle (argumentée) : ~6.0 Moyen — voir analyse ci-dessous


Préface

Ce billet ne parle pas d'un nouvel exploit ni d'un PoC fonctionnel. Le but ici est de corriger ce qui cloche dans la divulgation publique de CVE-2025-59059, plus précisément deux choses : la mauvaise classe a été désignée comme composant vulnérable, et le score CVSS ne reflète pas les contraintes réelles d'exploitabilité. Tout ceci repose sur une analyse statique du code source d'Apache Ranger 2.7.0 et sur le diff du correctif intégré dans 2.8.0.


Ce que dit l'avis

L'avis officiel indique :

« Remote Code Execution Vulnerability in NashornScriptEngineCreator is reported in Apache Ranger versions <= 2.7.0. »

C'est faux, ou du moins trompeur. NashornScriptEngineCreator n'est pas la classe vulnérable. Si quoi que ce soit, c'est la mieux durcie des deux composants liés à Nashorn dans le codebase — comme nous allons le voir.


Contexte : Nashorn dans Apache Ranger

Apache Ranger utilise des expressions JavaScript pour évaluer les politiques de filtrage au niveau des lignes. Ce sont des règles qui déterminent si un utilisateur donné peut accéder à un enregistrement spécifique dans un jeu de données. Pour exécuter ces expressions sur la JVM, Ranger embarque un moteur JavaScript. Dans les versions <= 2.7.0, ce moteur est Nashorn, le moteur JS intégré d'Oracle livré avec les JDK 8 à 14.

Une chose que l'avis omet complètement — et qui compte beaucoup pour évaluer le périmètre d'impact — est que jdk.nashorn.api.scripting.NashornScriptEngineFactory ne fait pas du tout partie du code source de Ranger. C'est un composant intégré au JDK. Il a été inclus dans JDK 8, déprécié dans JDK 11 et totalement supprimé dans JDK 15. Cette vulnérabilité n'est donc exploitable que si vous exécutez Ranger sur un JDK 8 à 14. Tout ce qui tourne sur JDK 15+ n'est pas concerné, car Nashorn n'y existe tout simplement pas, et ScriptEngineUtil retombe silencieusement sur GraalJS ou JavaScriptEngineCreator.

Deux classes de Ranger utilisent Nashorn. Elles le traitent de manière très différente.


Les deux classes liées à Nashorn

1. NashornScriptEngineCreator — la classe nommée mais la plus sûre

située à :

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;
        }
    }
}

Cette classe fait en réalité trois choses pour durcir le moteur :

  • --no-java — coupe l'accès direct à l'espace de noms java.* depuis les scripts
  • --no-syntax-extensions — désactive la syntaxe Nashorn non standard
  • RangerClassFilter — bloque tout accès aux classes Java au niveau du ClassFilter, renvoyant false pour tout

Est-ce infaillible ? Non. Des contournements du ClassFilter de Nashorn existent via des chaînes de réflexion et des astuces java.lang.invoke. Mais c'est nettement plus verrouillé que ce que l'on trouve dans l'autre classe.


2. RecordFilterJavaScript — la classe réellement vulnérable

située à :

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);
        ...
    }
}

Comparez cela avec NashornScriptEngineCreator et la différence est assez évidente :

  • pas d'option --no-java : l'espace de noms java.* est entièrement ouvert aux scripts
  • pas de --no-syntax-extensions
  • la seule « sécurité » est une vérification de chaîne : filterExpr.contains("this.engine")
  • filterExpr est concaténée directement dans le script que Nashorn évalue

Étant donné que --no-java n'est pas passé, l'espace de noms java.* est entièrement accessible. Aucune technique de contournement n'est nécessaire :

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

Aucun this.engine là-dedans. La liste noire est totalement hors de propos pour ce vecteur d'attaque.

Ce qui est intéressant, c'est que les développeurs connaissaient visiblement au moins un schéma de contournement. Le fichier de test TestRecordFilterJavaScript.java contient ceci :

root@kitploit:~
RecordFilterJavaScript.filterRow("user",
    "this.engine.factory.scriptEngine.eval('java.lang.Runtime.getRuntime().exec(\"/Applications/Spotify.app/Contents/MacOS/Spotify\")')",
    ...);

Ce test existe pour confirmer que this.engine est bloqué. Ce qui n'a pas été bloqué, c'est le chemin direct java.*, qui n'a pas du tout besoin de this.engine.


Le point d'entrée

RecordFilterJavaScript.filterRow() n'est appelé qu'à un seul endroit :

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 provient de result.getFilterExpr(). C'est l'expression JavaScript stockée dans une politique de filtre de lignes Ranger. Un attaquant disposant des privilèges d'administrateur de politiques peut définir cette expression comme il le souhaite. Lorsqu'un utilisateur accède ensuite à une ressource régie par cette politique, hasAccessToRecord() se déclenche, récupère filterExpr depuis le stockage de politiques et filterRow() le transmet à Nashorn sans véritable sandbox.

chaîne d'attaque :

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

Le diff du correctif

Le correctif est référencé sous RANGER-4076: Remove Nashorn Script Engine, commité le 8 décembre 2025 par Kishor Gollapalliwar. Il provient des archives de commits de la liste de diffusion Apache. Trois fichiers modifiés, 27 insertions, 81 suppressions.

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(-)

Fichier 1 : NashornScriptEngineCreator.java entièrement supprimé

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;
-        }
-    }
-}

Fichier 2 : ScriptEngineUtil.java — Nashorn retiré de la chaîne de créateurs de moteurs

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;

Fichier 3 : RecordFilterJavaScript.java — le vrai correctif

C'est là qu'intervient le véritable changement de sécurité. L'appel direct à NashornScriptEngineFactory est remplacé par GraalJS, et SecurityFilter perd entièrement son rôle de ClassFilter, étant relégué à une simple classe avec seulement la vérification de chaîne.

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");
         }
     }

Quelques points à signaler dans ce diff :

  • SecurityFilter n'est plus un ClassFilter : il perd son accroche au niveau du moteur et devient une simple classe à laquelle il ne reste que la vérification de chaîne.
  • Les imports Nashorn ont disparu, remplacés par ScriptEngineManager.
  • GraalJS fonctionne en mode nashorn-compat pour la compatibilité ascendante avec les expressions de politiques existantes.
  • polyglot.js.allowHostAccess est défini sur true. C'est un compromis pour la compatibilité ascendante, qui s'appuie sur le sandbox propre à GraalJS plutôt que sur un ClassFilter. À surveiller si la qualité du correctif vous importe.

Le patch montre clairement que RecordFilterJavaScript était la véritable cible de sécurité. La suppression de NashornScriptEngineCreator était du nettoyage, pas le correctif.


Pourquoi le CVE a nommé la mauvaise classe

Honnêtement, il n'est pas très difficile de voir comment c'est arrivé. NashornScriptEngineCreator se trouve directement dans agents-common, c'est la classe de tout le codebase dont le nom évoque le plus Nashorn, et un simple grep sur Nashorn la ferait remonter immédiatement. RecordFilterJavaScript, en revanche, vit dans plugin-nestedstructure, un sous-module séparé, et rien dans le nom de la classe n'évoque Nashorn. Si quelqu'un faisait un triage rapide sans suivre réellement le chemin d'exécution, il tomberait probablement sur NashornScriptEngineCreator et s'arrêterait là.

C'est apparemment ce qui s'est passé ici. La classe vulnérable et la classe nommée dans l'avis sont deux choses différentes.


Pourquoi le CVSS 9.8 ne tient pas

Un 9.8 implique une accessibilité réseau, aucune authentification requise, aucune interaction utilisateur nécessaire. La réalité est bien différente :

FacteurRéalité
Authentificationnécessite des privilèges d'administrateur de politiques dans Ranger
Plugin requisplugin-nestedstructure n'est pas activé par défaut

Rien de tout cela n'est reflété dans l'avis. Pour exploiter réellement cette vulnérabilité, vous avez besoin d'un accès administrateur de politiques, ce qui constitue un niveau de privilège significatif dans un déploiement Ranger. Ce n'est pas une RCE sans authentification. En tenant compte de l'exigence d'authentification et du plugin non activé par défaut, un score dans la plage 6.0–7.0 serait plus honnête.


Résumé

La vulnérabilité est réelle et la mise à niveau vers 2.8.0 est la bonne décision. Mais l'avis se trompe de classe et le score de sévérité ne reflète pas ce qui est réellement nécessaire pour exploiter cette vulnérabilité.


Références

  • Version Apache Ranger 2.8.0 : https://ranger.apache.org/download.html
  • Commit du correctif (RANGER-4076) : https://gitbox.apache.org/repos/asf/ranger.git
  • Entrée CVE : https://www.cve.org/CVERecord?id=CVE-2025-59059
  • Fil de discussion de la liste Apache : https://lists.apache.org/thread/z47q86rho80390lf2qcmoc2josvs0gtv
Télécharger l’outil
Contrainte JDK
exploitable uniquement sur JDK 8–14, JDK 15+ n'est pas concerné
Exposition réseauL'empreinte FOFA a renvoyé environ 35 instances Ranger exposées publiquement
Allégation de l'avisConstat réel
Classe vulnérableNashornScriptEngineCreatorRecordFilterJavaScript
Type d'attaqueRCE sans authentificationRCE authentifiée (admin de politiques requis)
JDK concernéNon préciséJDK 8–14 uniquement
Plugin requisNon préciséplugin-nestedstructure (non par défaut)
CVSS9.8 Critique~6.0 Moyen (argumenté)
Exposition InternetNon précisée~35 instances (FOFA)