Laboratorio controllato di ricerca e riproduzione di vulnerabilità per CVE-2020-14343 in PyYAML
Questo progetto dimostra la CVE-2020-14343 in un ambiente Docker controllato e isolato.
Il laboratorio contiene due ambienti:
yaml.safe_load()Il laboratorio dimostra il ciclo di vita completo della vulnerabilità:
Il payload di riproduzione utilizzato in questo laboratorio è intenzionalmente innocuo e stampa solo un marcatore di test.
| Proprietà | Dettagli |
|---|
| CVE | CVE-2020-14343 |
| Prodotto | PyYAML |
| Versioni interessate | Versioni precedenti alla 5.4 |
| Versione corretta | 5.4 |
| Tipo di vulnerabilità | Convalida dell'input non corretta (CWE-20) |
| Gravità | Critica |
| Superficie di attacco | Input YAML elaborato utilizzando funzionalità di caricamento vulnerabili |
La vulnerabilità si verifica quando un input YAML non attendibile viene elaborato utilizzando funzionalità di caricamento PyYAML vulnerabili.
Le versioni di PyYAML precedenti alla 5.4 consentivano tag YAML appositamente creati, inclusi tag specifici di Python come:
!!python/object/new
di raggiungere la funzionalità di costruzione di oggetti quando veniva utilizzato FullLoader.
Un documento YAML malevolo può quindi causare l'esecuzione involontaria di codice Python.
Il problema era correlato a una correzione incompleta di una precedente vulnerabilità di PyYAML.
PyYAML 5.4 ha corretto la CVE-2020-14343 spostando i tag Python arbitrari su UnsafeLoader.
Per le applicazioni che elaborano YAML non attendibile, questo laboratorio utilizza anche yaml.safe_load() come approccio di caricamento sicuro.
Il laboratorio contiene due servizi Docker isolati:
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
| Servizio | Porta Host | Porta Container | PyYAML | Scopo |
|---|---|---|---|---|
| vulnerable | 5000 | 5000 | 5.3.1 | Ambiente vulnerabile |
| patched | 5001 | 5000 | 5.4 | Ambiente corretto |
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
| File/Directory | Scopo |
|---|---|
vulnerable/app.py | Applicazione Flask che utilizza il caricamento YAML vulnerabile |
vulnerable/Dockerfile | Costruisce l'immagine Docker vulnerabile |
vulnerable/requirements.txt | Fissa PyYAML alla versione 5.3.1 |
patched/app.py | Applicazione Flask che utilizza il caricamento YAML sicuro |
patched/Dockerfile | Costruisce l'immagine Docker corretta |
patched/requirements.txt | Fissa PyYAML alla versione 5.4 |
exploit/reproduce.py | Riproduce la vulnerabilità utilizzando un payload controllato |
detection/detect.py | Verifica la versione di PyYAML all'interno di un container Docker |
docker-compose.yml | Costruisce ed esegue entrambi gli ambienti |
È richiesto il seguente software:
Docker Desktop deve essere in esecuzione prima di avviare il laboratorio.
L'applicazione vulnerabile è intenzionalmente esposta solo sulla macchina locale tramite le mappature delle porte di Docker.
Dalla directory principale del progetto, eseguire:
docker compose up --build -d
Eseguire:
docker compose ps
Entrambi i servizi dovrebbero mostrare Up.
Aprire:
http://127.0.0.1:5000
Risposta prevista:
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
Aprire:
http://127.0.0.1:5001
Risposta prevista:
{
"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
L'applicazione vulnerabile espone un endpoint /parse che accetta input YAML.
L'ambiente vulnerabile utilizza:
yaml.FullLoaderLo script di riproduzione si trova in:
exploit/reproduce.py
L'applicazione vulnerabile è disponibile all'indirizzo:
http://127.0.0.1:5000/parse
Eseguire:
python exploit/reproduce.py
Lo script invia un payload YAML controllato contenente un tag YAML specifico di Python.
Nell'ambiente vulnerabile, il payload viene accettato e l'applicazione restituisce una risposta HTTP 200.
Il marcatore di test controllato:
CVE-2020-14343-TEST
viene eseguito all'interno del container dell'applicazione vulnerabile.
L'esecuzione può essere verificata utilizzando:
docker logs cve-vulnerable
L'output previsto del log include:
CVE-2020-14343-TEST
Questo dimostra l'esecuzione di codice attraverso il comportamento di caricamento YAML vulnerabile.
Il payload di riproduzione è intenzionalmente innocuo. Stampa solo un marcatore di test e non modifica il sistema host, non accede a credenziali, non accede a dati sensibili, non interagisce con sistemi esterni e non esegue azioni distruttive.
Lo script di rilevamento si trova in:
detection/detect.py
Lo script verifica la versione di PyYAML installata all'interno del container Docker specificato.
La versione corretta è:
5.4
Eseguire:
python detection/detect.py cve-vulnerable
Risultato previsto:
PyYAML installed version: 5.3.1
Fixed version: 5.4
STATUS: VULNERABLE
Reason: PyYAML version is older than 5.4.
Eseguire:
python detection/detect.py cve-patched
Risultato previsto:
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
Lo script interroga la versione di PyYAML installata dal container di destinazione.
L'ambiente vulnerabile utilizza:
PyYAML==5.3.1
L'ambiente corretto utilizza:
PyYAML==5.4
L'applicazione corretta utilizza anche:
yaml.safe_load(yaml_input)
invece di:
yaml.load(yaml_input, Loader=yaml.FullLoader)
yaml.safe_load() quando l'applicazione richiede solo tipi di dati YAML standard.Lo stesso payload di exploit viene testato contro l'applicazione corretta.
L'applicazione corretta viene eseguita su:
http://127.0.0.1:5001/parse
Eseguire:
python exploit/reproduce.py http://127.0.0.1:5001/parse
Risultato osservato in questo 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"}
Il tag YAML specifico di Python viene rifiutato dall'applicazione corretta.
Il marcatore di test controllato non viene eseguito nell'applicazione corretta.
| Test | Ambiente Vulnerabile | Ambiente Corretto |
|---|---|---|
| Versione PyYAML | 5.3.1 | 5.4 |
| Rilevamento | VULNERABILE | CORRETTO |
| Richiesta di exploit | HTTP 200 | HTTP 400 |
| Tag YAML specifico di Python | Accettato | Rifiutato |
| Esecuzione del marcatore di test | Osservata nei log del container | Non eseguita |
Assicurarsi che Docker Desktop sia in esecuzione e verificare:
docker version
Verificare:
docker ps -a
Rimuovere i vecchi container se necessario:
docker rm cve-vulnerable cve-patched
Poi:
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
docker compose up --build -d
Per una ricostruzione pulita:
docker compose build --no-cache
docker compose up -d
Questo progetto è un laboratorio proof-of-concept controllato e non rappresenta una distribuzione in produzione.
Le limitazioni includono:
Le seguenti prove dovrebbero essere raccolte per la presentazione del progetto:
STATUS: VULNERABLE.CVE-2020-14343-TEST nei log di Docker.STATUS: PATCHED.Gli screenshot possono essere archiviati in:
screenshots/
Tutto il codice di riproduzione e la documentazione in questo repository sono stati sviluppati specificamente per questo laboratorio.
Questo laboratorio dimostra la CVE-2020-14343 dall'identificazione alla correzione.
L'ambiente vulnerabile utilizza PyYAML 5.3.1 e dimostra l'esecuzione controllata di codice attraverso un payload YAML appositamente creato.
Lo script di rilevamento identifica la versione vulnerabile della dipendenza.
L'ambiente corretto aggiorna PyYAML alla versione 5.4 e utilizza yaml.safe_load() per elaborare YAML non attendibile.
Lo stesso payload di riproduzione viene quindi rifiutato dall'applicazione corretta, fornendo prove prima-e-dopo della correzione.
L'intero ambiente può essere riprodotto utilizzando Docker Compose.