Apache ZooKeeper provides distributed coordination for systems like Kafka (legacy mode), HBase, Storm, and Hadoop. By default it listens on port 2181 with no authentication, exposes internal state via four-letter word commands (stat, dump, envi, ruok), and uses an ACL model where world:anyone permission is frequently misconfigured. ZooKeeper nodes store Kafka broker configurations, Hive metastore pointers, HDFS NameNode election state, and application-specific coordination data that often contains credentials and topology information. This guide covers systematic ZooKeeper security assessment.
# ZooKeeper default ports:
# 2181 — client port (main API)
# 2888 — peer/follower port (inter-ensemble)
# 3888 — leader election port (inter-ensemble)
# 8080 — AdminServer HTTP API (ZooKeeper 3.5+)
# Scan for exposed ZooKeeper
nmap -sV -p 2181,2888,3888,8080 --open TARGET-NETWORK/24 2>/dev/null | grep -A3 "open"
# Quick connectivity test using netcat
echo "ruok" | nc -w 3 zookeeper.example.com 2181
# "imok" = ZooKeeper is running and responding without auth
# AdminServer HTTP API (ZooKeeper 3.5+)
curl -s http://zookeeper.example.com:8080/commands/stat 2>/dev/null | python3 -m json.tool | head -20
curl -s http://zookeeper.example.com:8080/commands/conf 2>/dev/null | python3 -m json.tool
# Exposes full ZooKeeper configuration including auth settings
# ZooKeeper four-letter word commands expose internal state
# Must be whitelisted in zoo.cfg: 4lw.commands.whitelist=*
# Default: all enabled in older versions; most disabled in newer
# Check cluster health and member count
echo "stat" | nc -w 3 zookeeper.example.com 2181 2>/dev/null
# Returns: mode (leader/follower), connections, latency, ZNode count
# Dump ephemeral nodes and session info
echo "dump" | nc -w 3 zookeeper.example.com 2181 2>/dev/null
# Lists all ephemeral nodes and associated session IDs
# Kafka brokers register as ephemeral nodes — reveals all broker IPs
# Get server configuration including auth settings
echo "envi" | nc -w 3 zookeeper.example.com 2181 2>/dev/null
# Returns: JVM info, classpath, ZooKeeper version, Java properties
echo "conf" | nc -w 3 zookeeper.example.com 2181 2>/dev/null
# Returns: clientPort, dataDir, tickTime, maxClientCnxns
# List all connections
echo "cons" | nc -w 3 zookeeper.example.com 2181 2>/dev/null
# Lists each connected client with IP, latency, packet counts
# Monitor command (live stats)
echo "mntr" | nc -w 3 zookeeper.example.com 2181 2>/dev/null | head -20
# Kafka (legacy mode) stores broker config, topic data, and ACLs in ZooKeeper
# ZooKeeper ACLs for Kafka ZNodes are often world:anyone or weakly configured
# Connect to ZooKeeper CLI
zkCli.sh -server zookeeper.example.com:2181 2>/dev/null
# List Kafka brokers (includes IP:port and broker ID)
ls /brokers/ids
get /brokers/ids/0
# Returns: {"listener_security_protocol_map":...,"endpoints":["PLAINTEXT://10.0.1.5:9092"]}
# Get Kafka cluster ID and controller
get /cluster/id
get /controller
# List Kafka topics
ls /brokers/topics
# Get topic partition/replica assignments
get /brokers/topics/payments
# Reveals partition count, replica assignment, ISR state
# Kafka ACLs stored in ZooKeeper (if not using kraft mode)
ls /kafka-acl/Topic
ls /kafka-acl/Cluster
# Reading these reveals who has access to which topics
# Check for credentials in application-specific ZNodes
ls /
# Look for app-specific paths: /hive, /hbase, /storm, /hadoop-ha, /app-config etc.
ls /app-config 2>/dev/null
get /app-config/database 2>/dev/null # May contain DB credentials
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider4lw.commands.whitelist=ruok,mntr — disable stat/dump/envi/conf in productionadmin.enableServer=false or admin.serverAddress=127.0.0.1world:anyone ACL for ZNodes containing configuration or credentialssecureClientPort and ssl.* configuration| Security Test | Method | Risk |
|---|---|---|
| Unauthenticated client port access | echo "ruok" | nc -w3 zk:2181 returns "imok" | Critical |
| world:anyone ZNode read/write | zkCli get/set on root ZNodes without auth | High |
| Four-letter commands expose internals | echo "envi"/"conf"/"dump" | nc -w3 zk:2181 | High |
| Kafka broker endpoint enumeration | zkCli get /brokers/ids/0 — reveals all broker IPs | High |
| AdminServer HTTP API accessible | curl :8080/commands/conf returns full config | High |
| Application credentials in ZNodes | Enumerate /app-*, /config, /credentials paths | High |
Ironimo tests Apache ZooKeeper deployments for unauthenticated client API access, ACL world:anyone misconfigurations, four-letter command information disclosure, AdminServer exposure, Kafka ZNode credential extraction, and TLS misconfiguration across the complete ZooKeeper attack surface.
Start free scan