
Una sola chiamata di funzione mancante nella registrazione delle route è bastata a trasformare l'interfaccia MCP in un gateway RCE non autenticato.
Strumentazione di rilevamento non distruttiva per il bypass di autenticazione MCP di nginx-ui noto pubblicamente come MCPwn. Consente l'acquisizione non autenticata di qualsiasi istanza nginx-ui che esegua una versione vulnerabile, tramite due sole richieste HTTP.
nginx-ui espone un'interfaccia Model Context Protocol (MCP) che consente a un operatore autenticato di pilotare strumenti distruttivi come la modifica della configurazione di nginx, comandi di riavvio e operazioni di backup tramite JSON-RPC.
L'endpoint /mcp è protetto dal middleware AuthRequired(), mentre il
suo endpoint gemello /mcp_message, che riceve effettivamente le
invocazioni degli strumenti, è stato distribuito senza il middleware.
Qualsiasi client in grado di raggiungere l'interfaccia tramite rete può:
/mcp e ricevere un
nuovo sessionID senza presentare alcuna credenziale.sessionID per invocare qualsiasi strumento MCP
registrato inviando una POST a /mcp_message, sempre senza
autenticazione.L'attaccante ottiene il controllo completo del processo nginx: può modificare i server block per reindirizzare il traffico, estrarre le chiavi private TLS tramite letture di percorsi, ricaricare o arrestare nginx e impiantare backdoor persistenti.
// vulnerabile (pre-2.3.4)
r.GET("/mcp", AuthRequired(), mcpHandler)
r.POST("/mcp_message", mcpMessageHandler) // middleware mancante
// corretto in 2.3.4
r.GET("/mcp", AuthRequired(), mcpHandler)
r.POST("/mcp_message", AuthRequired(), mcpMessageHandler)
Una singola chiamata di funzione mancante nella registrazione delle route è stata sufficiente a trasformare l'interfaccia MCP in un gateway RCE non autenticato.
Attaccante nginx-ui (<2.3.4)
| 1) GET /mcp (senza auth) |
| --------------------------------------> |
| 2) event: endpoint data: /mcp_message?sessionID=XYZ
| <-------------------------------------- |
| 3) POST /mcp_message?sessionID=XYZ |
| body: JSON-RPC call_tool "nginx_reload" o
| "edit_config {...}" |
| --------------------------------------> |
| 4) 200 OK; strumento eseguito con pieni privilegi
| <-------------------------------------- |
Questo repository evita intenzionalmente qualsiasi azione distruttiva.
Il rilevatore utilizza solo metodi MCP di sola lettura (tools/list).
La logica:
> Passo 1 Identificare nginx-ui tramite
> GET / (titolo HTML, bundle JS)
> GET /api/settings (JSON che fa riferimento a chiavi nginx-ui)
> Estrarre la versione tramite header / regex sul body
> Passo 2 Aprire lo stream SSE su /mcp
> Estrarre il primo sessionID dall'evento "endpoint"
> Passo 3 POST /mcp_message?sessionID=<id>
> Body: {"jsonrpc":"2.0","method":"tools/list","params":{}}
> Nessun header Authorization
> Passo 4 Vulnerabile se status 200 e il body contiene un manifest degli strumenti
> Corretto se status 401 / 403 / 404
> Inconcludente altrimenti
Il metodo JSON-RPC tools/list è di sola lettura. Enumera quali
strumenti conosce il server MCP ma non ne invoca nessuno. Lo script
rifiuta di inviare POST con qualsiasi altro metodo e non costruisce mai
payload per strumenti distruttivi.
git clone https://github.com/your-org/CVE-2026-33032-detector.git
cd CVE-2026-33032-detector
python3 --version # 3.9 o successiva
# Non sono richiesti pacchetti di terze parti.
Per il componente Nmap NSE, copia nginx-ui-mcpwn.nse nella tua
directory locale degli script e aggiorna il database degli script:
cp nginx-ui-mcpwn.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb
# Singolo target
python3 detect_nginx_ui_mcpwn.py --target https://nginx-ui.internal
# Scansione di massa da file
python3 detect_nginx_ui_mcpwn.py --targets targets.txt --workers 20
# Output JSON (NDJSON) adatto per il piping a jq
python3 detect_nginx_ui_mcpwn.py --target 10.0.0.5:9000 --json | jq .
Riferimento della riga di comando:
nmap -p 80,443,9000 --script nginx-ui-mcpwn 10.0.0.0/24
nmap -p 443 --script nginx-ui-mcpwn --script-args "nginx-ui-mcpwn.timeout=8" host.example.com
_ _ _ _ _ ___ __ __ ____ ____
| \ | | __ _(_)_ __ __ __ | | | ||_ _| | \/ |/ ___| _ \__ ___ __
| \| |/ _` | | '_ \\ \/ /_____| | | | | | | |\/| | | | |_) \ \ /\ / / '_ \
| |\ | (_| | | | | |> <|_____| |__| | | | | | | | |___| __/ \ V V /| | | |
|_| \_|\__, |_|_| |_/_/\_\ |_____|_||___| |_| |_|\____|_| \_/\_/ |_| |_|
|___/
CVE-2026-33032 Rilevatore MCPwn nginx-ui > non distruttivo
[!] VULNERABILE https://nginx-ui.internal versione=2.3.2 evidenza=status=200; body_preview={"jsonrpc":"2.0","id":"...","result":{"tools":[{"name":"edit_config",...
[+] corretto https://nginx-ui-patched:9000 versione=2.3.4 evidenza=status=401; body_preview={"error":"unauthorized"}
[.] non nginx-ui https://example.com evidenza=fingerprint negativo
Riepilogo: 1/3 target segnalati come vulnerabili
{"target":"https://nginx-ui.internal","reachable":true,"is_nginx_ui":true,"mcp_endpoint_present":true,"session_id_obtained":true,"mcp_message_unauthenticated":true,"vulnerable":true,"nginx_ui_version":"2.3.2","evidence":"status=200; body_preview=...","error":null}
PORT STATE SERVICE
9000/tcp open http
| nginx-ui-mcpwn:
| status: VULNERABILE
| version: 2.3.2
| session_id: abc123
|_ evidence: tools/list accettato senza credenziali
CVE-2026-27944 (il download non autenticato di /api/backup che
perde la chiave AES nell'header X-Backup-Security) si combina
perfettamente con MCPwn: l'archivio di backup espone il node_secret,
che può essere utilizzato per autenticarsi su /mcp anche dopo
l'applicazione della correzione per 33032, finché gli operatori non
ruotano il segreto.
Il rilevatore complementare per 27944 si trova in una directory sorella di questo progetto di ricerca.
node_secret, gli hash delle password amministratore e
qualsiasi chiave privata TLS accessibile al processo nginx-ui./mcp_message sia raggiungibile.Questi strumenti sono pubblicati per aiutare i difensori a identificare istanze non aggiornate all'interno di ambienti che sono autorizzati a testare. Non utilizzarli contro sistemi di cui non sei proprietario o per i quali non hai esplicita autorizzazione alla valutazione. Gli autori declinano ogni responsabilità per un uso improprio.
Rilasciato sotto la Licenza MIT. Consulta le intestazioni dei singoli script per le note specifiche per file.
| Campo | Valore |
|---|
| ID CVE | CVE-2026-33032 |
| Alias | MCPwn |
| CVSS 3.1 | 9.8 / Critico (AV:N / AC:L / PR:N / UI:N / S:U / C:H/I:H/A:H) |
| CWE | CWE-306 Mancanza di autenticazione per funzioni critiche |
| Prodotto interessato | nginx-ui (github.com/0xjacky/nginx-ui) |
| Versioni interessate | Tutte le versioni precedenti alla 2.3.4 |
| Versione corretta | 2.3.4 |
| Stato dello sfruttamento | Attivo in natura (Picus Security, Recorded Future) |
| Esposizione su Shodan | ~2.689 istanze esposte su Internet |
| Data di pubblicazione | 2026-04-15 |
| Strumento MCP | Effetto sul server nginx |
|---|
edit_config | Riscrive server block arbitrari, inserisce upstream dell'attaccante |
reload_nginx | Applica la configurazione dell'attaccante senza azione manuale |
stop_nginx | Denial of service |
read_file | Esfiltra chiavi private TLS, credenziali da percorsi montati |
create_cert | Rilascia certificati TLS sotto il controllo dell'attaccante |
list_backups / download | Scarica l'intero backup di nginx-ui inclusi node_secret e hash |
| Flag | Scopo |
|---|
--target | Singolo URL o host[:porta] |
--targets | File di target separati da nuova riga |
--timeout | Timeout HTTP, default 10 secondi |
--workers | Worker concorrenti per scansioni di massa, default 10 |
--verify-tls | Applica la verifica del certificato TLS (disattivata di default) |
--json | Emette NDJSON, un record per target |
--no-banner | Sopprime il banner ASCII |