Описание
MQTT 5.0: inapplicable PUBLISH property disconnects matching subscribers
Summary
RabbitMQ's MQTT 5 property parser accepts properties without checking whether
they are valid for the enclosing packet type. An authenticated publisher can
include Request-Problem-Information (MQTT property 0x17) in a PUBLISH —
a property that the MQTT 5 specification restricts to CONNECT — and the
broker will store and route it.
When a matching subscriber's reader later serializes the outbound PUBLISH,
serialise_prop/2 has no clause for Request-Problem-Information, raising
error:function_clause. That exception is not contained at the victim
queue-event boundary, so the victim's entire MQTT connection is closed.
The publisher's connection and the broker remain healthy.
Preconditions
- MQTT (and optionally Web MQTT) is enabled.
- Attacker is an authenticated MQTT 5 client with write permission for a topic.
- Victim is a separately authenticated MQTT 5 (or Web MQTT) client subscribed to that topic (or a matching filter).
Root cause
1. Ingress accepts the property on any packet
There is no packet-type applicability check around parse_prop/2.
2. Message container preserves the property
mc_mqtt carries MQTT properties through the broker's message container into
delivery for matching subscribers (after publisher exchange/topic authorization).
3. Egress has no serializer clause
serialise_prop/2 (same module, ~550–611) defines clauses for PUBLISH-applicable
properties (Content-Type, Correlation-Data, …) but not for
Request-Problem-Information. Serializing the preserved map therefore raises
function_clause in the victim reader.
4. Victim connection is not isolated from serializer failure
rabbit_mqtt_reader does not convert that exception into a controlled protocol
error for the delivery path, so the victim process terminates and the socket
closes.
Native MQTT and Web MQTT share this codec path; triage sweeps against
rabbit_web_mqtt_app.erl describe the same sink.
Reproduction
Self-contained against a stock Docker image. Two MQTT 5 clients on raw sockets:
a victim that subscribes to topic t, and an attacker that publishes control then
attack frames.
Verified on rabbitmq:4.1-management (broker 4.1.8) with this exact sequence.
1. Start RabbitMQ with MQTT enabled
Default MQTT credentials: guest / guest.
2. Control and attack frames
Control — QoS 0 PUBLISH to t with applicable Content-Type = "a" (victim must
survive):
| Bytes | Meaning |
|---|---|
30 | PUBLISH, QoS 0 |
09 | remaining length |
00 01 74 | topic t |
04 | property length |
03 00 01 61 | Content-Type (0x03), value a |
78 | payload x |
Attack — same PUBLISH but with Request-Problem-Information = 1 (property 0x17,
valid only on CONNECT per MQTT 5, not on PUBLISH):
| Bytes | Meaning |
|---|---|
30 | PUBLISH, QoS 0 |
07 | remaining length |
00 01 74 | topic t |
02 | property length |
17 01 | Request-Problem-Information = 1 |
78 | payload x |
3. End-to-end script (victim + control + attack)
4. Expected result
| Check | Control (Content-Type) | Attack (Request-Problem-Information) |
|---|---|---|
| Victim receives message | yes (30 09 … 78) | no (connection dies during outbound serialize) |
| Victim TCP socket | stays open | closed by broker |
| Attacker connection | survives | survives |
| Broker | healthy | healthy (rabbitmq-diagnostics ping succeeds) |
Observed on 4.1.8: control delivered and victim stayed up; after the attack frame the victim socket closed, the attacker stayed up, and the broker remained healthy. Broker log:
Impact
- Cross-principal: one authenticated publisher can disconnect another client's MQTT session if they share a matching subscription.
- One-shot QoS 0 disconnect in the current proof; no demonstrated queued replay, retained-message persistence, reconnect poisoning, or broker-wide DoS.
- Publisher and broker remain up.
Recommended remediation
- Validate property applicability (and multiplicity) per MQTT packet type at ingress.
- Filter outbound PUBLISH properties through an explicit PUBLISH allowlist.
- Convert serializer failures into a controlled protocol error without crashing an unrelated subscriber connection.
- Add two-principal raw-packet regression coverage for native and Web MQTT.
Пакеты
rabbitmq
>= 3.13.0, < 3.13.19
3.13.19
rabbitmq
>= 4.0.0, < 4.0.24
4.0.24
rabbitmq
>= 4.1.0, < 4.1.15
4.1.15
rabbitmq
>= 4.2.0, < 4.2.10
4.2.10
rabbitmq
>= 4.3.0, < 4.3.5
4.3.5
2.3 Low
CVSS4
CVE ID
2.3 Low
CVSS4