Контролируемая лаборатория исследования и воспроизведения уязвимости CVE-2020-14343 в PyYAML
Этот проект демонстрирует CVE-2020-14343 в контролируемой и изолированной среде Docker.
Лаборатория содержит две среды:
yaml.safe_load()Лаборатория демонстрирует полный жизненный цикл уязвимости:
Полезная нагрузка для воспроизведения, используемая в этой лаборатории, намеренно безвредна и лишь выводит тестовый маркер.
| Свойство | Детали |
|---|
| CVE | CVE-2020-14343 |
| Продукт | PyYAML |
| Уязвимые версии | Версии до 5.4 |
| Исправленная версия | 5.4 |
| Тип уязвимости | Некорректная проверка входных данных (CWE-20) |
| Критичность | Критическая |
| Поверхность атаки | Входные данные YAML, обрабатываемые с использованием уязвимой функциональности загрузки |
Уязвимость возникает, когда недоверенные входные данные 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
│
├── docker-compose.yml
└── README.md
| Файл/Каталог | Назначение |
|---|---|
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 | Собирает и запускает обе среды |
Требуется следующее программное обеспечение:
Перед запуском лаборатории Docker Desktop должен быть запущен.
Уязвимое приложение намеренно доступно только на локальной машине через сопоставление портов Docker.
Из корневого каталога проекта выполните:
docker compose up --build -d
Выполните:
docker compose ps
Оба сервиса должны отображаться как Up.
Откройте:
http://127.0.0.1:5000
Ожидаемый ответ:
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
Откройте:
http://127.0.0.1:5001
Ожидаемый ответ:
{
"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
Ожидаемый результат:
PyYAML installed version: 5.3.1
Fixed version: 5.4
STATUS: VULNERABLE
Reason: PyYAML version is older than 5.4.
Выполните:
python detection/detect.py cve-patched
Ожидаемый результат:
PyYAML installed version: 5.4
Fixed version: 5.4
STATUS: PATCHED
Reason: PyYAML version is 5.4 or newer.
Docker Container
|
v
docker exec
|
v
Import PyYAML
|
v
Read yaml.__version__
|
v
Compare with 5.4
|
+----------------------+
| |
< 5.4 >= 5.4
| |
v v
VULNERABLE PATCHED
Скрипт запрашивает установленную версию PyYAML из целевого контейнера.
Уязвимая среда использует:
PyYAML==5.3.1
Исправленная среда использует:
PyYAML==5.4
Исправленное приложение также использует:
yaml.safe_load(yaml_input)
вместо:
yaml.load(yaml_input, Loader=yaml.FullLoader)
yaml.safe_load(), когда приложению требуются только стандартные типы данных YAML.Та же полезная нагрузка эксплойта тестируется против исправленного приложения.
Исправленное приложение работает на:
http://127.0.0.1:5001/parse
Выполните:
python exploit/reproduce.py http://127.0.0.1:5001/parse
Наблюдаемый результат в этой лаборатории:
HTTP Status: 400
Server Response:
{"message":"could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/new:tuple' ...","status":"error"}
Специфичный для Python тег YAML отклоняется исправленным приложением.
Контролируемый тестовый маркер не выполняется в исправленном приложении.
| Тест | Уязвимая среда | Исправленная среда |
|---|---|---|
| Версия PyYAML | 5.3.1 | 5.4 |
| Обнаружение | VULNERABLE | PATCHED |
| Запрос эксплойта | HTTP 200 | HTTP 400 |
| Специфичный для Python тег YAML | Принят | Отклонен |
| Выполнение тестового маркера | Наблюдается в логах контейнера | Не выполняется |
Убедитесь, что Docker Desktop запущен, и проверьте:
docker version
Проверьте:
docker ps -a
Удалите старые контейнеры при необходимости:
docker rm cve-vulnerable cve-patched
Затем:
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
docker compose up --build -d
Для чистой пересборки:
docker compose build --no-cache
docker compose up -d
Этот проект представляет собой контролируемую лабораторию proof-of-concept и не является производственным развертыванием.
Ограничения включают:
Для сдачи проекта следует зафиксировать следующие доказательства:
STATUS: VULNERABLE.CVE-2020-14343-TEST в логах Docker.STATUS: PATCHED.Скриншоты можно сохранить в:
screenshots/
Весь код воспроизведения и документация в этом репозитории были разработаны специально для этой лаборатории.
Эта лаборатория демонстрирует CVE-2020-14343 от идентификации до устранения.
Уязвимая среда использует PyYAML 5.3.1 и демонстрирует контролируемое выполнение кода через специально созданную полезную нагрузку YAML.
Скрипт обнаружения идентифицирует уязвимую версию зависимости.
Исправленная среда обновляет PyYAML до 5.4 и использует yaml.safe_load() для обработки недоверенного YAML.
Та же полезная нагрузка для воспроизведения затем отклоняется исправленным приложением, что дает доказательства устранения уязвимости до и после.
Вся среда может быть воспроизведена с помощью Docker Compose.