MQTT Protocol
1.1 Introduction
MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for low-bandwidth, high-latency networks. It provides real-time, reliable messaging services for remote devices with minimal code and bandwidth usage. MQTT operates over TCP and is classified as an application layer protocol.
1.2 Message Format
A fixed header, a variable header, and a payload.Fixed Header | Variable Header | PayloadFixed HeaderAt least two bytes; the first byte contains message type and QoS level flags. The second byte is the remaining length field, which indicates the total length of the variable header and message payload, allowing up to four bytes.The maximum length of a single byte is 127 bytes. Why not 256 bytes? The MQTT protocol specifies that if the eighth bit of a single byte is 1, it indicates that there are more bytes to follow, serving as a “continuation bit”.MQTT allows a maximum of four bytes to represent the remaining length, and the last byte’s maximum value can only be 0x7F, not 0xFF, so the maximum message length is 256MB, not 512MB.Variable HeaderIncludes protocol name, protocol version, connection flags, keep-alive interval, connection return code, topic name, etc.PayloadConsidered the message body.MQTT Message TypesTypes of messages sent by MQTT:
-
CONNECT (Connection)
-
PUBLISH (Publish)
-
SUBSCRIBE (Subscription Confirmation)
-
UNSUBSCRIBE (Unsubscribe)
The first byte of the fixed header contains connection flags, which distinguish the types of MQTT messages.
Reserved | 0 | Prohibited | Reserved |
CONNECT | 1 | Client to Server | Initiate Connection |
CONNACK | 2 | Server to Client | Connection Acknowledgment |
PUBLISH | 3 | Both Directions | Publish Message |
PUBACK | 4 | Both Directions | QoS 1 Message Acknowledgment |
PUBREC | 5 | Both Directions | QoS 2 Message Receipt |
PUBREL | 6 | Both Directions | QoS 2 Message Release |
PUBCOMP | 7 | Both Directions | QoS 2 Message Completion |
SUBSCRIBE | 8 | Client to Server | Subscription Request |
SUBACK | 9 | Server to Client | Subscription Acknowledgment |
UNSUBSCRIBE | 10 | Client to Server | Unsubscribe |
UNSUBACK | 11 | Server to Client | Unsubscribe Acknowledgment |
PINGREQ | 12 | Client to Server | Ping Request |
PINGRESP | 13 | Client to Server | Ping Response |
DISCONNECT | 14 | Client to Server | Disconnect |
Reserved | 15 | Prohibited | Reserved |
Quality of Service (QoS)Three levels:
-
QoS 0
At most once delivery. Message delivery relies entirely on the underlying TCP/IP network, with no acknowledgment or retries defined in the protocol; the message is delivered once.
-
QoS 1
At least once delivery. The server acknowledges message receipt with a PUBACK message. If the communication link or sending device fails, or if acknowledgment is not received within a specified time, the sender will resend the message marked with the DUP flag in the header.
-
QoS 2
Exactly once delivery. This is the highest level of message delivery, where message loss and duplication are unacceptable, and using this QoS level incurs additional overhead.For example, consider a bike lock that periodically uses QoS Level 0 messages to request the server for the bike’s current location. If the server does not receive this message, it does not matter, as it will be sent again later. When the bike is found, a QoS Level 1 message can be used to send the unlock command, ensuring that at least one message reaches the bike to unlock it. After using the bike, the user needs to submit a payment form, which can use QoS Level 2 to ensure that the data is transmitted only once; otherwise, the user may be charged multiple times.Will FlagFlag fields:
-
Will Flag
-
Will QoS
-
Will Retain Flag
When the server and client communicate, if an exception occurs or the client’s heartbeat times out, the MQTT server will publish a Will message on behalf of the client. If the server receives a DISCONNECT message from the client, it will not trigger the sending of the Will message.The Will field can be used in scenarios where a notification is needed when a device goes offline.Keep Alive TimerThe MQTT client can set a keep-alive interval, indicating that a message should be sent within each keep-alive interval. If no business-related messages are sent during this time, the client will send a PINGREQ message, and the server will respond with a PINGRESP message for acknowledgment. If the server does not receive any messages from the client within one and a half keep-alive intervals, it will disconnect from the client. The maximum keep-alive interval can be set to approximately 18 hours, with a value of 0 meaning no disconnection.Asynchronous Publish/Subscribe ImplementationMQTT supports bidirectional communication, allowing the server to control devices. Devices can subscribe to a topic and then receive messages published to that topic, enabling a series of operations upon receiving the message.MQTT SecurityMQTT operates above the TCP layer and transmits in plaintext, similar to HTTP’s plaintext transmission.Risks:
-
Device hijacking
-
Modification of static data between client and server
-
Denial of Service attacks
-
Communication interception, modification, or redirection
-
Injection of virtual control messages
MQTT security is considered from three aspects:
-
Application Layer: MQTT provides client identification along with username and password for device authentication at the application layer.
-
Transport Layer: Similar to HTTPS, MQTT is based on TCP connections and can also add a layer of TLS to prevent man-in-the-middle attacks.
-
Network Layer: Dedicated lines or VPNs can connect devices to the MQTT broker.
AuthenticationTwo levels of authentication:
-
Application Layer: MQTT supports client identification, username, and password.
-
Transport Layer: The transport layer can use TLS, which not only encrypts communication but also uses x509 certificates to authenticate devices.
Client IdentificationGenerally, the MAC address or serial number of the embedded chip can be used.Username and PasswordThe MQTT protocol can send the username and password via the CONNECT message.Since this is transmitted in plaintext, it can be easily captured using packet sniffing tools.Transport Layer AuthenticationThe MQTT broker can continue to send the client’s x509 certificate for device verification after a successful TLS handshake. If the certificate is invalid, the connection can be terminated. The benefit of using x509 authentication is that it can verify the legitimacy of the device at the transport layer, blocking unauthorized devices from connecting before sending the Connect message, thus saving unnecessary resource waste and ensuring message integrity and confidentiality.User Data Format
-
Hexadecimal or binary
Traffic control is very minimal.
-
String
-
JSON
JSON has a clear hierarchical structure, is easy to read and write, and is easy for machines to parse and generate, effectively improving network transmission efficiency.{“String”:”Hello World!”,”Value”:12345} JSON stringXMLThe MQTT protocol only handles the communication part; users can choose their own format.MQTT + JSON is currently the optimal solution.
1.3 MQTT Communication
Multiple nodes communicate with each other by subscribing to the same topic, using tomqtt to specify the sending target and obtain the message source.Tomqtt concept (similar to directory structure):For example, a car lock protocol topic could be remote_control/result/rvs_set_doorlock.One or more topics:Topic level separator: “/”Single-level wildcard: ” + “Multi-level wildcard: ” # “Generally, MQTT brokers will use tomqtt starting with $ for system debugging and information storage purposes.
1.4 Example
mosquitto_subBased on the publish/subscribe model:http://mosquitto.org/download/ MQTT server programSubscribe to messages:
mosquitto_sub -h 127.0.0.1 -t debug (topic)
Publish messages:
mosquitto_pub -h 127.0.0.1 -t debug -m "Hello World" -r (retain the last message on the server)
node-redAdd /test topic:mqtt.fxSubscribe to /test:
Receive messages:
Publish messages:
1.5 Bulk Device Scanning
Fofa search for port 1883 (port=”1883″ && protocol=”mqtt”)Python scanning:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("[+] Connection successful")
client.subscribe('#', qos=1)
client.subscribe('$SYS/#')
def on_message(client, userdata, msg):
print('[+] Tomqtt: %s - Message: %s' % (msg.tomqtt, msg.payload))
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
client = mqtt.Client(client_id="MqttClient")
client.on_connect = on_connect
client.on_message = on_message
client.connect('Scanning Device IP', 1883, 60)
client.loop_forever()
# client.publish('/test', "I am from pycharm client!")
Scanning results:
2. Security Issues
1. MITM Attack
MQTT defaults to port 1883, and since authentication information is transmitted in plaintext by default, it is vulnerable to man-in-the-middle attacks. SSL encryption can be used, with the default port being 8883.
2. Unauthorized Access Issues
MQTT message servers may have configuration errors, allowing unauthorized access due to lack of authentication setup.
-
Using wildcards to subscribe to all Tomqtt
MQTT topics support the wildcards “+” and “#”. For example, if we have two Tomqtts CMD/123/456 and CMD/789/666, we can subscribe to CMD/# to receive all messages under CMD. In an attack, we can first listen to all Tomqtts that do not start with a specific character. For Tomqtts starting with a specific character, we can use $SYS/# to subscribe.https://github.com/mqtt/mqtt.github.io/wiki/SYS-Tomqtts
-
Permission Control Issues
The MQTT server does not manage permissions for regular users, allowing them to use wildcards.Failure to verify user permissions allows them to subscribe to any content and access messages from other members, such as turning on lights or unlocking doors.
3. Password Cracking
-
Anonymous Login Issues
emqttd/etc/emq.conf # Default setting allows anyone to log in, change to false
mqtt.allow_anonymous = true
-
Pay attention to authentication plugins
In EMQ, emq_plugin_template is a template for developing plugins, and enabling it automatically allows any user to connect successfully.
-
Brute Force Attacks
Enable authentication mode:
Enable plugins:
https://github.com/zombiesam/joffreyPassword cracking:
3. Conclusion
As a commonly used protocol in the Internet of Things, MQTT brings technical convenience while also introducing many security issues that developers need to be aware of.