Автономная лаборатория Docker, демонстрирующая обход каталогов CVE-2007-4559 (TarSlip) через модуль tarfile Python. Включает уязвимые и исправленные API, генерацию полезной нагрузки и интерактивный демонстрационный скрипт для обучения безопасности.
Только для образовательных целей. Эта лаборатория намеренно эксплуатирует уязвимости файловой системы в изолированных Docker-контейнерах. Не запускайте в системах с конфиденциальными данными или в производственных средах.
Автономная Docker-лаборатория, демонстрирующая CVE-2007-4559 — печально известную уязвимость «TarSlip» в модуле Python tarfile — через полную цепочку атак «от начала до конца»:
extractall() слепо записывает запись tar с именем ../../../etc/passwd за пределами каталога распаковки, перезаписывая реальный системный файл./admin.tarfile.extractall() в Python добросовестно воспроизводит каждую запись в архиве tar, включая записи, имена которых содержат последовательности обхода каталогов ../. Она никогда не задумывалась как граница безопасности.
имя записи tar : ../../../etc/passwd
каталог извлечения : /shared/uploads/a1b2c3d4/
разрешённый путь : /shared/uploads/a1b2c3d4/../../../etc/passwd
= /etc/passwd ← системный файл перезаписан
| Хронология | |
|---|---|
| 2007 | Ошибка сообщена группе безопасности Python |
| 2007 – 2022 | Отмечено как «не проблема безопасности» — tarfile «работает как задумано» |
| 2022 | Исследователи Trellix сканируют GitHub и находят более 350 000 репозиториев, вызывающих extractall() для непроверенных входных данных |
| 2022 | Публичное раскрытие. CVE-2007-4559 всплывает снова. Паника в индустрии. |
| 2023 | PEP 706 включает filter='data' в Python 3.12 — исправление в одном аргументе |
Демонстрация проходит в три этапа, каждый из которых требует нажатия клавиши для продолжения.
GET /admin → 401. Конечная точка admin существует и защищена. Злоумышленник не знает пароль.innocent.tar.gz → файлы попадают в каталог песочницы. Всё выглядит нормально.Злоумышленник создаёт tarslip_passwd.tar.gz
└─ запись: "../../../etc/passwd"
содержимое: admin:hacked:1001:... ← внедрённый пароль
│
▼
POST /upload (загрузка multipart-файла)
│
▼
extractall("/shared/uploads/{uuid}/")
разрешает "../../../etc/passwd" → /etc/passwd ← CVE-2007-4559
│
▼
GET /admin Authorization: Basic admin:hacked
│
▼
HTTP 200 — «Welcome, admin! You have full admin access.»
флаг: CVE-2007-4559{tarslip_passwd_overwrite_to_admin_rce}
Один HTTP POST. Никакой оболочки. Никакой RCE-нагрузки. Просто tar-файл.
Тот же tarball загружается в исправленный API, который передаёт filter='data' в extractall(). Python вызывает tarfile.OutsideDestinationError — обход блокируется, /etc/passwd не тронут, а /admin остаётся закрытым.
# Уязвимый — по умолчанию до Python 3.14
tar.extractall(extraction_dir)
# Исправленный — PEP 706 (Python 3.12+)
tar.extractall(extraction_dir, filter='data')
Один аргумент. Пятнадцать лет на внедрение.
Четыре сервиса в изолированной сети Docker bridge (tarslip-net). Ничего не выходит в интернет.
┌─────────────────────────────────────────────────────────┐
│ tarslip-net (bridge) │
│ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ vulnerable-api │ │ file-server │ │
│ │ python:3.11.3 │ │ nginx:alpine │ │
│ │ порт 8000 │ │ порт 8080 (хост) │ │
│ │ │ │ │ │
│ │ POST /upload │ │ Обслуживает /shared по │ │
│ │ GET /admin │ │ HTTP — визуальный про- │ │
│ │ GET /health │ │ смотр извлечённых │ │
│ └────────┬────────┘ └────────────┬─────────────┘ │
│ │ том shared-storage │ │
│ └────────────────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ attacker │ │
│ │ python:3.12 │ (нет порта хоста — только внутренний)│
│ │ │ │
│ │ craft_malicious.py — генерирует tarball'ы │
│ │ demo.py — управляет демонстрацией │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Сервис | Образ | Роль | Порт хоста |
|---|---|---|---|
vulnerable-api | python:3.11.3-slim | Flask API загрузки + /admin, защищённый аутентификацией через /etc/passwd | 8000 |
fixed-api | python:3.12-slim | Тот же код + USE_SAFE_EXTRACTION=true | 8000 |
file-server | nginx:alpine | Список каталогов извлечённых файлов | 8080 |
attacker | python:3.12-slim | Генератор нагрузок + драйвер демонстрации | — |
Уязвимый и исправленный API используют идентичный исходный код. Единственное отличие — переменная окружения USE_SAFE_EXTRACTION=true в исправленном контейнере, которая включает единственный аргумент filter='data'.
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 compose version)bashgit clone https://github.com/your-username/CVE-2007-4559-lab.git
cd CVE-2007-4559-lab
bash run_demo.sh
Скрипт полностью интерактивен. Он печатает пояснения перед каждым шагом и ждёт нажатия Enter для продолжения. Для понимания не требуется предварительных знаний Docker.
| Пауза | Показываемое описание | Действие по Enter |
|---|---|---|
| 1 | Хронология CVE, описание трёх этапов | Сборка уязвимого стека |
| 2 | Роли контейнеров, внедрённый пароль администратора | Генерация нагрузок |
| 3 | Что внутри каждого tarball'а | Этап 1 — базовый уровень |
| 4 | Почему /admin возвращает 401, как выглядит обычная распаковка | Этап 2 — эксплойт |
| 5 | Точные вычисления обхода, что перезаписывается | Переключение на исправленный стек |
| 6 | Что такое filter='data' и почему это работает | Этап 3 — проверка |
| 7 | Ключевые выводы + более общий паттерн ZipSlip | Остановка |
Если вы хотите пройти шаги вручную:
# Уязвимый стек
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