Контролируемая лаборатория исследования и воспроизведения уязвимости CVE-2020-14343 в PyYAML
Этот проект демонстрирует CVE-2020-14343 в контролируемой и изолированной среде Docker.
Лаборатория содержит две среды:
yaml.safe_load()Лаборатория демонстрирует полный жизненный цикл уязвимости:
Полезная нагрузка для воспроизведения, используемая в этой лаборатории, намеренно безвредна и лишь выводит тестовый маркер.
| Свойство | Детали |
|---|---|
| CVE | CVE-2020-14343 |
| Продукт | PyYAML |
| Уязвимые версии | Версии до 5.4 |
| Исправленная версия | 5.4 |
| Тип уязвимости | Некорректная проверка входных данных (CWE-20) |
| Критичность | Критическая |
| Поверхность атаки | Входные данные YAML, обрабатываемые с использованием уязвимой функциональности загрузки |
| CVSS | 9.3 (CVSS v4, GitHub Advisory) |
Уязвимость возникает, когда недоверенные входные данные YAML обрабатываются с использованием уязвимой функциональности загрузки PyYAML.
Версии PyYAML до 5.4 допускали специально сформированные теги YAML, включая специфичные для Python теги, такие как:
!!python/object/new
для доступа к функциональности конструирования объектов при использовании FullLoader.
Таким образом, вредоносный YAML-документ может вызвать непреднамеренное выполнение Python-кода.
Проблема была связана с неполным исправлением более ранней уязвимости PyYAML.
PyYAML 5.4 исправил CVE-2020-14343, переместив произвольные Python-теги в UnsafeLoader.
Для приложений, обрабатывающих недоверенный YAML, в этой лабораторной работе также используется yaml.safe_load() как безопасный подход к загрузке.
Лабораторная работа содержит два изолированных Docker-сервиса:
Host Machine
|
+------------+------------+
| |
v v
Vulnerable App Patched App
localhost:5000 localhost:5001
| |
PyYAML 5.3.1 PyYAML 5.4
FullLoader SafeLoader
| |
v v
Payload executes Payload rejected
| Сервис | Порт хоста | Порт контейнера | PyYAML | Назначение |
|---|---|---|---|---|
| vulnerable | 5000 | 5000 | 5.3.1 | Уязвимая среда |
| patched | 5001 | 5000 | 5.4 | Исправленная среда |
cve-2020-14343-lab/
├── vulnerable/
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── patched/
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── exploit/
│ └── reproduce.py
├── detection/
│ └── detect.py
├── screenshots/
│ ├── 01-docker-compose-running.png
│ ├── 02-vulnerable-detection.png
│ ├── 03-patched-detection.png
│ ├── 04a-vulnerable-request.png
│ ├── 04b-vulnerable-execution-log.png
│ └── 05-patched-exploit-blocked.png
├── blog/
│ └── CVE-2020-14343-Technical-Blog.pdf
├── docker-compose.yml
├── README.md
└── .gitignore
| Файл/Каталог | Назначение |
|---|---|
vulnerable/app.py | Flask-приложение, использующее уязвимую загрузку YAML |
vulnerable/Dockerfile | Собирает уязвимый Docker-образ |
vulnerable/requirements.txt | Фиксирует PyYAML на версии 5.3.1 |
patched/app.py | Flask-приложение, использующее безопасную загрузку YAML |
patched/Dockerfile | Собирает исправленный Docker-образ |
patched/requirements.txt | Фиксирует PyYAML на версии 5.4 |
exploit/reproduce.py | Воспроизводит уязвимость с использованием контролируемой полезной нагрузки |
detection/detect.py | Проверяет версию PyYAML внутри Docker-контейнера |
docker-compose.yml | Собирает и запускает оба окружения |
screenshots/ | Содержит доказательства, собранные в ходе лабораторной работы |
blog/ | Содержит PDF технического блога объёмом 800–1200 слов |
Требуется следующее программное обеспечение:
Перед началом лабораторной работы Docker Desktop должен быть запущен.
Уязвимое приложение намеренно доступно только на локальной машине через проброс портов Docker.
Из корневого каталога проекта выполните:
docker compose up --build -d
Выполните:
docker compose ps
Оба сервиса должны отображать Up.
Откройте:
http://127.0.0.1:5000
I'm ready to translate chunk 13, but no content was included in your message — the INPUT section is empty.
Please paste the actual Markdown text for chunk 13, and I'll return the Russian translation with all structure, code, and formatting preserved exactly.
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
Откройте:
http://127.0.0.1:5001
I'm ready to translate chunk 13, but no content was included in your message — the INPUT section is empty.
Please paste the actual Markdown text for chunk 13, and I'll return the Russian translation with all structure, code, and formatting preserved exactly.
{
"message": "CVE-2020-14343 patched YAML parser"
}
docker compose up -d
docker compose down
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
Уязвимое приложение предоставляет эндпоинт /parse, который принимает входные данные в формате YAML.
В уязвимой среде используются:
yaml.FullLoaderСкрипт воспроизведения находится по адресу:
exploit/reproduce.py
Уязвимое приложение доступно по адресу:
http://127.0.0.1:5000/parse
Запуск:
python exploit/reproduce.py
Скрипт отправляет контролируемую полезную нагрузку YAML, содержащую специфичный для Python тег YAML.
В уязвимой среде полезная нагрузка принимается, и приложение возвращает HTTP-ответ 200.
Контролируемый тестовый маркер:
CVE-2020-14343-TEST
выполняется внутри контейнера уязвимого приложения.
Выполнение можно проверить с помощью:
docker logs cve-vulnerable
Ожидаемый вывод журнала включает:
CVE-2020-14343-TEST
Это демонстрирует выполнение кода через уязвимое поведение загрузки YAML.
Воспроизводящая полезная нагрузка намеренно безвредна. Она только выводит тестовый маркер и не изменяет хост-систему, не получает доступ к учётным данным, не обращается к конфиденциальным данным, не взаимодействует с внешними системами и не выполняет деструктивных действий.
Скрипт обнаружения расположен по адресу:
detection/detect.py
Скрипт проверяет версию PyYAML, установленную внутри указанного Docker-контейнера.
Исправленная версия:
5.4
Выполните:
python detection/detect.py cve-vulnerable