Laboratório controlado de pesquisa e reprodução de vulnerabilidades para CVE-2020-14343 em PyYAML
Este projeto demonstra a CVE-2020-14343 em um ambiente Docker controlado e isolado.
O laboratório contém dois ambientes:
yaml.safe_load()O laboratório demonstra o ciclo de vida completo da vulnerabilidade:
O payload de reprodução usado neste laboratório é intencionalmente inofensivo e apenas imprime um marcador de teste.
| Propriedade | Detalhes |
|---|
| CVE | CVE-2020-14343 |
| Produto | PyYAML |
| Versões afetadas | Versões anteriores à 5.4 |
| Versão corrigida | 5.4 |
| Tipo de vulnerabilidade | Validação de Entrada Imprópria (CWE-20) |
| Severidade | Crítica |
| Superfície de ataque | Entrada YAML processada usando funcionalidade de carregamento vulnerável |
A vulnerabilidade ocorre quando uma entrada YAML não confiável é processada usando funcionalidade de carregamento vulnerável do PyYAML.
Versões do PyYAML anteriores à 5.4 permitiam tags YAML especialmente construídas, incluindo tags específicas do Python como:
!!python/object/new
alcançarem a funcionalidade de construção de objetos quando FullLoader era usado.
Um documento YAML malicioso pode, portanto, causar execução não intencional de código Python.
O problema estava relacionado a uma correção incompleta de uma vulnerabilidade anterior do PyYAML.
O PyYAML 5.4 corrigiu a CVE-2020-14343 movendo tags Python arbitrárias para UnsafeLoader.
Para aplicações que processam YAML não confiável, este laboratório também usa yaml.safe_load() como abordagem de carregamento segura.
O laboratório contém dois serviços Docker isolados:
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
| Serviço | Porta no Host | Porta no Contêiner | PyYAML | Propósito |
|---|---|---|---|---|
| vulnerable | 5000 | 5000 | 5.3.1 | Ambiente vulnerável |
| patched | 5001 | 5000 | 5.4 | Ambiente corrigido |
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
| Arquivo/Diretório | Propósito |
|---|---|
vulnerable/app.py | Aplicação Flask usando carregamento YAML vulnerável |
vulnerable/Dockerfile | Constrói a imagem Docker vulnerável |
vulnerable/requirements.txt | Fixa o PyYAML na versão 5.3.1 |
patched/app.py | Aplicação Flask usando carregamento YAML seguro |
patched/Dockerfile | Constrói a imagem Docker corrigida |
patched/requirements.txt | Fixa o PyYAML na versão 5.4 |
exploit/reproduce.py | Reproduz a vulnerabilidade usando um payload controlado |
detection/detect.py | Verifica a versão do PyYAML dentro de um contêiner Docker |
docker-compose.yml | Constrói e executa ambos os ambientes |
O seguinte software é necessário:
O Docker Desktop deve estar em execução antes de iniciar o laboratório.
A aplicação vulnerável é intencionalmente exposta apenas na máquina local através dos mapeamentos de porta do Docker.
A partir do diretório raiz do projeto, execute:
docker compose up --build -d
Execute:
docker compose ps
Ambos os serviços devem mostrar Up.
Abra:
http://127.0.0.1:5000
Resposta esperada:
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
Abra:
http://127.0.0.1:5001
Resposta 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
A aplicação vulnerável expõe um endpoint /parse que aceita entrada YAML.
O ambiente vulnerável usa:
yaml.FullLoaderO script de reprodução está localizado em:
exploit/reproduce.py
A aplicação vulnerável está disponível em:
http://127.0.0.1:5000/parse
Execute:
python exploit/reproduce.py
O script envia um payload YAML controlado contendo uma tag YAML específica do Python.
No ambiente vulnerável, o payload é aceito e a aplicação retorna uma resposta HTTP 200.
O marcador de teste controlado:
CVE-2020-14343-TEST
é executado dentro do contêiner da aplicação vulnerável.
A execução pode ser verificada usando:
docker logs cve-vulnerable
A saída esperada do log inclui:
CVE-2020-14343-TEST
Isso demonstra a execução de código através do comportamento vulnerável de carregamento YAML.
O payload de reprodução é intencionalmente inofensivo. Ele apenas imprime um marcador de teste e não modifica o sistema host, acessa credenciais, acessa dados sensíveis, interage com sistemas externos ou realiza ações destrutivas.
O script de detecção está localizado em:
detection/detect.py
O script verifica a versão do PyYAML instalada dentro do contêiner Docker especificado.
A versão corrigida é:
5.4
Execute:
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.
Execute:
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
O script consulta a versão instalada do PyYAML a partir do contêiner alvo.
O ambiente vulnerável usa:
PyYAML==5.3.1
O ambiente corrigido usa:
PyYAML==5.4
A aplicação corrigida também usa:
yaml.safe_load(yaml_input)
em vez de:
yaml.load(yaml_input, Loader=yaml.FullLoader)
yaml.safe_load() quando a aplicação requer apenas tipos de dados YAML padrão.O mesmo payload de exploit é testado contra a aplicação corrigida.
A aplicação corrigida é executada em:
http://127.0.0.1:5001/parse
Execute:
python exploit/reproduce.py http://127.0.0.1:5001/parse
Resultado observado neste laboratório:
HTTP Status: 400
Server Response:
{"message":"could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/new:tuple' ...","status":"error"}
A tag YAML específica do Python é rejeitada pela aplicação corrigida.
O marcador de teste controlado não é executado na aplicação corrigida.
| Teste | Ambiente Vulnerável | Ambiente Corrigido |
|---|---|---|
| Versão do PyYAML | 5.3.1 | 5.4 |
| Detecção | VULNERABLE | PATCHED |
| Requisição de exploit | HTTP 200 | HTTP 400 |
| Tag YAML específica do Python | Aceita | Rejeitada |
| Execução do marcador de teste | Observada nos logs do contêiner | Não executada |
Certifique-se de que o Docker Desktop está em execução e verifique:
docker version
Verifique:
docker ps -a
Remova contêineres antigos, se necessário:
docker rm cve-vulnerable cve-patched
Em seguida:
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
docker compose up --build -d
Para uma reconstrução limpa:
docker compose build --no-cache
docker compose up -d
Este projeto é um laboratório de prova de conceito controlado e não representa uma implantação em produção.
As limitações incluem:
As seguintes evidências devem ser capturadas para a submissão do projeto:
STATUS: VULNERABLE.CVE-2020-14343-TEST nos logs do Docker.STATUS: PATCHED.Capturas de tela podem ser armazenadas em:
screenshots/
Todo o código de reprodução e documentação neste repositório foram desenvolvidos especificamente para este laboratório.
Este laboratório demonstra a CVE-2020-14343 desde a identificação até a correção.
O ambiente vulnerável usa PyYAML 5.3.1 e demonstra execução de código controlada através de um payload YAML construído.
O script de detecção identifica a versão vulnerável da dependência.
O ambiente corrigido atualiza o PyYAML para 5.4 e usa yaml.safe_load() para processar YAML não confiável.
O mesmo payload de reprodução é então rejeitado pela aplicação corrigida, fornecendo evidências de antes e depois da correção.
Todo o ambiente pode ser reproduzido usando Docker Compose.