logo
    • Accueil
    • Catégories
    • A propos
  • fr-languageFrançais
SécuritéPar Pierre Colart

Injection de modèles côté serveur

Contexte

L'injection de modèles côté serveur se produit lorsqu'un attaquant est capable d'utiliser la syntaxe de modèle native pour injecter une charge malveillante dans un modèle, qui est ensuite exécuté côté serveur. Les moteurs de template sont conçus pour générer des pages web en combinant des modèles fixes avec des données volatiles. Les attaques d'injection de modèles côté serveur peuvent se produire lorsque les entrées de l'utilisateur sont directement concaténées dans un modèle, plutôt que d'être transmises en tant que données. Cela permet aux attaquants d'injecter des directives de modèle arbitraires pour manipuler le moteur de template, leur permettant souvent de prendre le contrôle total du serveur. Comme son nom l'indique, les charges utiles d'injection de modèles côté serveur sont livrées et évaluées côté serveur, ce qui les rend potentiellement beaucoup plus dangereuses qu'une injection de modèle côté client typique.

Les vulnérabilités d'injection de modèles côté serveur peuvent exposer les sites web à diverses attaques selon le moteur de template en question et la façon dont l'application l'utilise. Dans certaines circonstances rares, ces vulnérabilités ne posent aucun risque réel pour la sécurité. Cependant, la plupart du temps, l'impact de l'injection de modèles côté serveur peut être catastrophique.

À l'extrémité la plus grave de l'échelle, un attaquant peut potentiellement réaliser une exécution de code à distance, prendre le contrôle total du serveur principal et l'utiliser pour mener des attaques supplémentaires sur l'infrastructure interne. Même dans les cas où une exécution de code à distance complète n'est pas possible, un attaquant peut souvent utiliser l'injection de modèles côté serveur comme base pour de nombreuses autres attaques, potentiellement en obtenant un accès en lecture aux données sensibles et aux fichiers arbitraires sur le serveur.

Comment

Les vulnérabilités liées à l'injection de modèles côté serveur surviennent lorsque les entrées utilisateur sont concaténées avec des modèles plutôt que d'être transmises sous forme de données. Les modèles statiques, qui fournissent simplement des espaces réservés pour afficher du contenu dynamique, ne sont généralement pas vulnérables à ce type d'attaque. Par exemple, un e-mail qui accueille chaque utilisateur par son nom, tel que celui-ci extrait d'un modèle Twig:

 $output = $twig->render("Hello {first_name},", array("first_name" => $user.first_name) );

Injection de modèles côté serveur

Dans cette section, nous discuterons de ce qu'est l'injection de modèle côté serveur et décrirons la méthodologie de base pour exploiter les vulnérabilités d'injection de modèle côté serveur. Nous suggérerons également des moyens de garantir que votre propre utilisation de modèles ne vous expose pas à l'injection de modèle côté serveur.

Laboratoires Si vous comprenez déjà les concepts de base des vulnérabilités d'injection de modèle côté serveur et que vous voulez simplement pratiquer leur exploitation sur des cibles réalistes et délibérément vulnérables, vous pouvez accéder à tous les laboratoires de cette section à partir du lien ci-dessous.

Voir tous les laboratoires d'injection de modèle côté serveur Cette technique a été documentée pour la première fois par PortSwigger dans notre article de recherche de 2015 sur le sujet. Si vous souhaitez savoir comment nous avons pu exploiter certaines de ces vulnérabilités sur des sites web en direct, un compte complet est disponible sur notre page de recherche.

Recherche d'injection de modèle côté serveur Qu'est-ce que l'injection de modèle côté serveur ? L'injection de modèle côté serveur se produit lorsqu'un attaquant est capable d'utiliser la syntaxe de modèle native pour injecter une charge malveillante dans un modèle, qui est ensuite exécuté côté serveur.

Les moteurs de template sont conçus pour générer des pages web en combinant des modèles fixes avec des données volatiles. Les attaques d'injection de modèle côté serveur peuvent se produire lorsque les entrées de l'utilisateur sont directement concaténées dans un modèle, plutôt que d'être transmises en tant que données. Cela permet aux attaquants d'injecter des directives de modèle arbitraires pour manipuler le moteur de template, leur permettant souvent de prendre le contrôle total du serveur. Comme son nom l'indique, les charges utiles d'injection de modèle côté serveur sont livrées et évaluées côté serveur, ce qui les rend potentiellement beaucoup plus dangereuses qu'une injection de modèle côté client typique.

Quel est l'impact de l'injection de modèle côté serveur ? Les vulnérabilités d'injection de modèle côté serveur peuvent exposer les sites web à diverses attaques selon le moteur de template en question et la façon exacte dont l'application l'utilise. Dans certaines circonstances rares, ces vulnérabilités ne posent aucun risque réel pour la sécurité. Cependant, la plupart du temps, l'impact de l'injection de modèle côté serveur peut être catastrophique.

À l'extrémité la plus grave de l'échelle, un attaquant peut potentiellement réaliser une exécution de code à distance, prendre le contrôle total du serveur principal et l'utiliser pour mener des attaques supplémentaires sur l'infrastructure interne.

Même dans les cas où une exécution de code à distance complète n'est pas possible, un attaquant peut souvent utiliser l'injection de modèle côté serveur comme base pour de nombreuses autres attaques, potentiellement en obtenant un accès en lecture aux données sensibles et aux fichiers arbitraires sur le serveur.

Comment se produisent les vulnérabilités d'injection de modèle côté serveur ? Les vulnérabilités d'injection de modèle côté serveur se produisent lorsque les entrées de l'utilisateur sont concaténées dans des modèles plutôt que d'être transmises en tant que données.

Les modèles statiques qui fournissent simplement des espaces réservés dans lesquels le contenu dynamique est rendu ne sont généralement pas vulnérables à l'injection de modèle côté serveur. L'exemple classique est un e-mail qui salue chaque utilisateur par son nom, comme l'extrait de modèle Twig suivant :

 $output = $twig->render("Hello{first_name},", array("first_name" => $user.first_name));

Cela n'est pas vulnérable à l'injection de modèle côté serveur car le prénom de l'utilisateur est simplement transmis au modèle en tant que données.

Cependant, comme les modèles sont simplement des chaînes de caractères, les développeurs web concatènent parfois directement les entrées de l'utilisateur dans les modèles avant de les rendre. Prenons un exemple similaire à celui ci-dessus, mais cette fois-ci, les utilisateurs peuvent personnaliser certaines parties de l'e-mail avant de l'envoyer. Par exemple, ils peuvent choisir le nom utilisé :

 $output = $twig->render("Hello$name,", array("name" => $_GET["name"]));

Dans cet exemple, si un attaquant peut contrôler la valeur de l'entrée "name", il peut injecter une directive de modèle malveillante qui sera interprétée et exécutée côté serveur.

Comment prévenir l'injection de modèle côté serveur ? La manière la plus simple de prévenir l'injection de modèle côté serveur est de ne jamais concaténer directement les entrées de l'utilisateur dans des modèles. Au lieu de cela, les entrées de l'utilisateur doivent être traitées en tant que données et passées au moteur de template sous forme de variables.

Les variables doivent être soigneusement validées avant d'être passées au moteur de template pour éviter toute injection de modèle malveillante. Les frameworks de développement modernes offrent souvent des fonctions de filtrage et de validation des entrées pour simplifier cette tâche.

Si l'utilisation de l'opération de concaténation est inévitable, des caractères spéciaux tels que les guillemets doivent être correctement échappés pour éviter toute injection de modèle. Le moteur de template doit également être configuré pour désactiver les directives de modèle dangereuses telles que les fonctions d'exécution de système d'exploitation.

En suivant ces bonnes pratiques de développement, les développeurs peuvent réduire considérablement les risques d'injection de modèle côté serveur et rendre leurs applications web plus sûres.

 $output = $twig->render("Hello{first_name},", array("first_name" => $user.first_name)); This code is not vulnerable to server-side template injection because the user's first name is simply passed to the template as data. It is not used to construct or modify the template in any way that would allow an attacker to inject malicious code.

Dans cet exemple, au lieu d'une valeur statique transmise au modèle, une partie du modèle lui-même est générée dynamiquement à l'aide du paramètre "name". Comme la syntaxe de modèle est évaluée côté serveur, cela permet potentiellement à un attaquant de placer une charge utile d'injection de modèle côté serveur dans le paramètre "name" comme suit :

 http://website.com/?name={{bad-stuff-here}}

De telles vulnérabilités sont parfois causées par des accidents dus à une mauvaise conception de modèle par des personnes qui ne sont pas familières avec les implications de sécurité. Comme dans l'exemple ci-dessus, vous pouvez voir différents composants, dont certains contiennent des entrées utilisateur, concaténés et intégrés dans un modèle. À certains égards, cela est similaire aux vulnérabilités d'injection SQL qui se produisent dans des déclarations préparées mal écrites.

Cependant, ce comportement est parfois intentionnellement mis en œuvre. Par exemple, certains sites web permettent délibérément à certains utilisateurs privilégiés, tels que les éditeurs de contenu, de modifier ou de soumettre des modèles personnalisés dès le départ. Cela représente clairement un énorme risque de sécurité si un attaquant est capable de compromettre un compte avec de tels privilèges.

Construction d'une attaque d'injection de modèle côté serveur

Identifier les vulnérabilités d'injection de modèle côté serveur et élaborer une attaque réussie implique généralement le processus global suivant.

Détecter

Les vulnérabilités d'injection de modèle côté serveur passent souvent inaperçues, non pas parce qu'elles sont complexes, mais parce qu'elles ne sont vraiment apparentes qu'aux auditeurs qui les cherchent explicitement. Si vous êtes capable de détecter la présence d'une vulnérabilité, il peut être étonnamment facile de l'exploiter. C'est particulièrement vrai dans les environnements sans sandbox.

Comme pour toute vulnérabilité, la première étape vers l'exploitation est de pouvoir la trouver. L'approche initiale la plus simple peut consister à essayer de fuzzing le modèle en injectant une séquence de caractères spéciaux couramment utilisés dans les expressions de modèle, tels que ${{<%[%'"}}%. Si une exception est lancée, cela indique que la syntaxe de modèle injectée est potentiellement interprétée par le serveur d'une certaine manière. C'est un signe qu'une vulnérabilité d'injection de modèle côté serveur peut exister.

Les vulnérabilités d'injection de modèle côté serveur se produisent dans deux contextes distincts, chacun nécessitant sa propre méthode de détection. Indépendamment des résultats de vos tentatives de fuzzing, il est important d'essayer également les approches contextuelles suivantes. Si le fuzzing n'était pas concluant, une vulnérabilité peut encore être révélée en utilisant l'une de ces approches. Même si le fuzzing a suggéré une vulnérabilité d'injection de modèle, vous devez toujours identifier son contexte afin de l'exploiter.

Contexte de texte brut

La plupart des langages de modèle vous permettent d'entrer librement du contenu en utilisant directement des balises HTML ou en utilisant la syntaxe de modèle native, qui sera rendue au format HTML en arrière-plan avant que la réponse HTTP ne soit envoyée.

Cela peut parfois être exploité pour l'injection de XSS et est en fait souvent confondu avec une vulnérabilité XSS simple. Cependant, en définissant des opérations mathématiques comme valeur de paramètre, nous pouvons tester si cela est également un point d'entrée potentiel pour une attaque d'injection de modèle côté serveur.

Prenons l'exemple d'un modèle contenant le code vulnérable suivant :

 render('Hello ' + username)

Au cours de l'audit, nous pouvons tester l'injection de modèle côté serveur en demandant une URL telle que :

 http://website.com/?username=${7*7}

Si la sortie résultante contient "Hello 49", cela indique que l'opération mathématique est évaluée côté serveur. C'est une bonne preuve de concept pour une vulnérabilité d'injection de modèle côté serveur.

Notez que la syntaxe spécifique requise pour évaluer avec succès l'opération mathématique varie en fonction du moteur de modèle utilisé.

Contexte de code

Dans d'autres cas, la vulnérabilité est exposée par une entrée utilisateur placée dans une expression de modèle, comme nous l'avons vu précédemment avec notre exemple d'e-mail. Cela peut prendre la forme d'un nom de variable contrôlé par l'utilisateur placé à l'intérieur d'un paramètre, tel que :

 greeting = getQueryParameter('greeting')
engine.render("Hello {{"+greeting+"}}", data)

Sur le site web, l'URL résultante ressemblerait à :

 http://website.com/?greeting=data.username

Cela serait rendu dans la sortie de Hello Carlos, par exemple.

Ce contexte passe facilement inaperçu lors de l'évaluation, car il n'entraîne pas de XSS évident et est presque impossible à distinguer d'une simple recherche de hashmap. Une méthode de test pour l'injection de modèle côté serveur dans ce contexte consiste à établir d'abord que le paramètre ne contient pas de vulnérabilité XSS directe en injectant du code HTML arbitraire dans la valeur :

 http://website.com/?greeting=data.username<tag>

En l'absence de XSS, cela se traduira généralement par une entrée vide dans la sortie ("Hello" sans nom d'utilisateur), des balises encodées ou un message d'erreur. La prochaine étape consiste à essayer de sortir de l'instruction en utilisant une syntaxe de modèle courante et à tenter d'injecter du code HTML arbitraire après cela :

 http://website.com/?greeting=data.username}}<tag>

Si cela entraîne à nouveau une erreur ou une sortie vide, vous avez soit utilisé la mauvaise syntaxe de langage de modèle, soit, si aucune syntaxe de style de modèle ne semble être valide, l'injection de modèle côté serveur n'est pas possible. Alternativement, si la sortie est rendue correctement, avec le code HTML arbitraire, cela indique clairement la présence d'une vulnérabilité d'injection de modèle côté serveur :

 Hello Carlos<tag>

Identification

Une fois que vous avez détecté le potentiel d'injection de modèle, la prochaine étape consiste à identifier le moteur de modèle.

Bien qu'il existe un grand nombre de langages de modèle, beaucoup d'entre eux utilisent une syntaxe très similaire qui est spécialement choisie pour ne pas entrer en conflit avec les caractères HTML. Par conséquent, il peut être relativement simple de créer des charges utiles de test pour déterminer quel moteur de modèle est utilisé.

Soumettre simplement une syntaxe invalide est souvent suffisant, car le message d'erreur résultant vous indiquera exactement quel moteur de modèle est utilisé, et parfois même quelle version. Par exemple, l'expression invalide <%=foobar%> déclenche la réponse suivante du moteur ERB basé sur Ruby :

 (erb):1:in `<main>': undefined local variable or method `foobar' for main:Object (NameError)
from /usr/lib/ruby/2.5.0/erb.rb:876:in `eval'
from /usr/lib/ruby/2.5.0/erb.rb:876:in `result'
from -e:4:in `<main>'

Il est important de noter que la même charge utile peut parfois renvoyer une réponse positive dans plusieurs langages de modèle. Par exemple, la charge utile {{7*'7'}} renvoie 49 dans Twig et 7777777 dans Jinja2. Par conséquent, il est important de ne pas sauter aux conclusions sur la base d'une seule réponse réussie.

Comment prévenir les vulnérabilités

La meilleure façon de prévenir l'injection de modèle côté serveur est de ne pas permettre à un utilisateur de modifier ou de soumettre de nouveaux modèles. Cependant, cela est parfois inévitable en raison des exigences métier.

L'une des façons les plus simples d'éviter d'introduire des vulnérabilités d'injection de modèle côté serveur est d'utiliser toujours un moteur de modèle "sans logique", tel que Mustache, sauf si cela est absolument nécessaire. Séparer la logique de la présentation autant que possible peut réduire considérablement votre exposition aux attaques les plus dangereuses basées sur le modèle.

Une autre mesure consiste à n'exécuter le code utilisateur que dans un environnement sandbox où les modules et fonctions potentiellement dangereux ont été complètement supprimés. Malheureusement, le sandboxing de code peu fiable est intrinsèquement difficile et sujet à la contournement.

Enfin, une autre approche complémentaire consiste à accepter que l'exécution de code arbitraire est presque inévitable et à appliquer votre propre sandboxing en déployant votre environnement de modèle dans un conteneur Docker verrouillé, par exemple.

Pierre Colart

Developpeur et architecte passionné, qui souhaite partagé son univers et ses découvertes afin de rendre les choses plus simple pour chacun

Voir le profil

Les derniers articles

Sequences, Time Series et Prediction

© 2023 Switch case. Made with by Pierre Colart