Apache ZooKeeper Security Testing: Unauthenticated Access, ACL Bypass, and Four-Letter Command Abuse

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.

Table of Contents

  1. ZooKeeper Exposure and Discovery
  2. Four-Letter Word Commands
  3. Unauthenticated ZNode Access
  4. ACL World:Anyone Bypass
  5. Kafka Credential Extraction from ZooKeeper
  6. Malicious ZNode Write Operations
  7. ZooKeeper Security Hardening

ZooKeeper Exposure and Discovery

# 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

Four-Letter Word Commands

# 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 Credential Extraction from ZooKeeper

# 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

ZooKeeper Security Hardening

ZooKeeper Security Hardening Checklist:
Security TestMethodRisk
Unauthenticated client port accessecho "ruok" | nc -w3 zk:2181 returns "imok"Critical
world:anyone ZNode read/writezkCli get/set on root ZNodes without authHigh
Four-letter commands expose internalsecho "envi"/"conf"/"dump" | nc -w3 zk:2181High
Kafka broker endpoint enumerationzkCli get /brokers/ids/0 — reveals all broker IPsHigh
AdminServer HTTP API accessiblecurl :8080/commands/conf returns full configHigh
Application credentials in ZNodesEnumerate /app-*, /config, /credentials pathsHigh

Automate ZooKeeper Security Testing

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