Laboratorio controlado de investigación y reproducción de vulnerabilidades para CVE-2020-14343 en PyYAML
Este proyecto demuestra CVE-2020-14343 en un entorno Docker controlado y aislado.
El laboratorio contiene dos entornos:
yaml.safe_load()El laboratorio demuestra el ciclo de vida completo de la vulnerabilidad:
La carga útil de reproducción utilizada en este laboratorio es intencionadamente inofensiva y solo imprime un marcador de prueba.
| Propiedad | Detalles |
|---|
| CVE | CVE-2020-14343 |
| Producto | PyYAML |
| Versiones afectadas | Versiones anteriores a 5.4 |
| Versión corregida | 5.4 |
| Tipo de vulnerabilidad | Validación de entrada incorrecta (CWE-20) |
| Gravedad | Crítica |
| Superficie de ataque | Entrada YAML procesada mediante funcionalidad de carga vulnerable |
La vulnerabilidad ocurre cuando una entrada YAML no confiable se procesa utilizando funcionalidad de carga vulnerable de PyYAML.
Las versiones de PyYAML anteriores a 5.4 permitían etiquetas YAML especialmente diseñadas, incluidas etiquetas específicas de Python como:
!!python/object/new
llegar a la funcionalidad de construcción de objetos cuando se utilizaba FullLoader.
Un documento YAML malicioso puede por lo tanto provocar la ejecución no intencionada de código Python.
El problema estaba relacionado con una corrección incompleta de una vulnerabilidad anterior de PyYAML.
PyYAML 5.4 corrigió CVE-2020-14343 moviendo las etiquetas Python arbitrarias a UnsafeLoader.
Para las aplicaciones que procesan YAML no confiable, este laboratorio también utiliza yaml.safe_load() como enfoque de carga seguro.
El laboratorio contiene dos servicios Docker aislados:
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
| Servicio | Puerto del host | Puerto del contenedor | PyYAML | Propósito |
|---|---|---|---|---|
| vulnerable | 5000 | 5000 | 5.3.1 | Entorno vulnerable |
| patched | 5001 | 5000 | 5.4 | Entorno remediado |
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
| Archivo/Directorio | Propósito |
|---|---|
vulnerable/app.py | Aplicación Flask que utiliza carga YAML vulnerable |
vulnerable/Dockerfile | Construye la imagen Docker vulnerable |
vulnerable/requirements.txt | Fija PyYAML a 5.3.1 |
patched/app.py | Aplicación Flask que utiliza carga YAML segura |
patched/Dockerfile | Construye la imagen Docker parcheada |
patched/requirements.txt | Fija PyYAML a 5.4 |
exploit/reproduce.py | Reproduce la vulnerabilidad utilizando una carga útil controlada |
detection/detect.py | Comprueba la versión de PyYAML dentro de un contenedor Docker |
docker-compose.yml | Construye y ejecuta ambos entornos |
Se requiere el siguiente software:
Docker Desktop debe estar en ejecución antes de iniciar el laboratorio.
La aplicación vulnerable está expuesta intencionadamente solo en la máquina local a través de los mapeos de puertos de Docker.
Desde el directorio raíz del proyecto, ejecute:
docker compose up --build -d
Ejecute:
docker compose ps
Ambos servicios deberían mostrar Up.
Abra:
http://127.0.0.1:5000
Respuesta esperada:
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
Abra:
http://127.0.0.1:5001
Respuesta esperada:
{
"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
La aplicación vulnerable expone un endpoint /parse que acepta entrada YAML.
El entorno vulnerable utiliza:
yaml.FullLoaderEl script de reproducción se encuentra en:
exploit/reproduce.py
La aplicación vulnerable está disponible en:
http://127.0.0.1:5000/parse
Ejecute:
python exploit/reproduce.py
El script envía una carga útil YAML controlada que contiene una etiqueta YAML específica de Python.
En el entorno vulnerable, la carga útil es aceptada y la aplicación devuelve una respuesta HTTP 200.
El marcador de prueba controlado:
CVE-2020-14343-TEST
se ejecuta dentro del contenedor de la aplicación vulnerable.
La ejecución puede verificarse utilizando:
docker logs cve-vulnerable
La salida esperada del registro incluye:
CVE-2020-14343-TEST
Esto demuestra la ejecución de código a través del comportamiento de carga YAML vulnerable.
La carga útil de reproducción es intencionadamente inofensiva. Solo imprime un marcador de prueba y no modifica el sistema anfitrión, accede a credenciales, accede a datos sensibles, interactúa con sistemas externos ni realiza acciones destructivas.
El script de detección se encuentra en:
detection/detect.py
El script comprueba la versión de PyYAML instalada dentro del contenedor Docker especificado.
La versión corregida es:
5.4
Ejecute:
python detection/detect.py cve-vulnerable
Resultado esperado:
PyYAML installed version: 5.3.1
Fixed version: 5.4
STATUS: VULNERABLE
Reason: PyYAML version is older than 5.4.
Ejecute:
python detection/detect.py cve-patched
Resultado esperado:
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
El script consulta la versión de PyYAML instalada desde el contenedor objetivo.
El entorno vulnerable utiliza:
PyYAML==5.3.1
El entorno parcheado utiliza:
PyYAML==5.4
La aplicación parcheada también utiliza:
yaml.safe_load(yaml_input)
en lugar de:
yaml.load(yaml_input, Loader=yaml.FullLoader)
yaml.safe_load() cuando la aplicación solo requiera tipos de datos YAML estándar.La misma carga útil de exploit se prueba contra la aplicación parcheada.
La aplicación parcheada se ejecuta en:
http://127.0.0.1:5001/parse
Ejecute:
python exploit/reproduce.py http://127.0.0.1:5001/parse
Resultado observado en este laboratorio:
HTTP Status: 400
Server Response:
{"message":"could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/new:tuple' ...","status":"error"}
La etiqueta YAML específica de Python es rechazada por la aplicación parcheada.
El marcador de prueba controlado no se ejecuta en la aplicación parcheada.
| Prueba | Entorno vulnerable | Entorno parcheado |
|---|---|---|
| Versión de PyYAML | 5.3.1 | 5.4 |
| Detección | VULNERABLE | PATCHED |
| Solicitud de exploit | HTTP 200 | HTTP 400 |
| Etiqueta YAML específica de Python | Aceptada | Rechazada |
| Ejecución del marcador de prueba | Observada en los registros del contenedor | No ejecutada |
Asegúrese de que Docker Desktop esté en ejecución y verifique:
docker version
Compruebe:
docker ps -a
Elimine los contenedores antiguos si es necesario:
docker rm cve-vulnerable cve-patched
Luego:
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
docker compose up --build -d
Para una reconstrucción limpia:
docker compose build --no-cache
docker compose up -d
Este proyecto es un laboratorio de prueba de concepto controlado y no representa un despliegue en producción.
Las limitaciones incluyen:
Debe capturarse la siguiente evidencia para la entrega del proyecto:
STATUS: VULNERABLE.CVE-2020-14343-TEST en los registros de Docker.STATUS: PATCHED.Las capturas de pantalla pueden almacenarse en:
screenshots/
Todo el código de reproducción y la documentación de este repositorio se desarrollaron específicamente para este laboratorio.
Este laboratorio demuestra CVE-2020-14343 desde la identificación hasta la remediación.
El entorno vulnerable utiliza PyYAML 5.3.1 y demuestra la ejecución de código controlada a través de una carga útil YAML diseñada.
El script de detección identifica la versión vulnerable de la dependencia.
El entorno remediado actualiza PyYAML a 5.4 y utiliza yaml.safe_load() para procesar YAML no confiable.
La misma carga útil de reproducción es entonces rechazada por la aplicación parcheada, proporcionando evidencia antes y después de la remediación.
Todo el entorno puede reproducirse utilizando Docker Compose.