01
MQTT协议简介
MQTT是一种基于发布/订阅模式的轻量级消息传输协议,最初由IBM开发。它采用轻量级的、简单的消息发布和订阅机制,适用于各种网络环境和设备。MQTT协议旨在为物联网(IoT)和机器到机器(M2M)通信提供一种简单、轻量级、可靠的解决方案。以下是MQTT协议的主要特点和工作原理:
(1)MQTT的发布/订阅模式
MQTT采用发布/订阅模式,其中设备可以发布(发送)消息到特定的主题,同时其他设备可以订阅(接收)这些主题的消息。这种模式使得设备之间的通信变得松耦合,设备可以独立于彼此进行通信,而不需要直接相互交互。在通信过程中主要包括三个角色:
· 发布者(Publisher):负责发布消息的设备或应用程序。
· 订阅者(Subscriber):负责订阅感兴趣的主题,并接收相关的消息。
· 代理服务器(Broker):负责接收来自发布者的消息,并将其传递给订阅者。
其中代理服务器是MQTT通信的中间人。在MQTT通信中需要一个中间人(Broker)来协调消息的发布和订阅。客户端向Broker发送消息,并由Broker负责将消息路由给对应的订阅者。具体拓扑图见图1:
图1 MQTT通信拓扑图
(2)MQTT报文类型
MQTT协议通过交换预定义的MQTT控制报文来通信。MQTT控制报文由固定头(Fixed Header)、可变头(Variable Header)和有效载荷(Payload)组成,这使得它易于实现和部署。每个MQTT控制报文都包含一个固定报头,见表1:
表1 固定报头格式
MQTT的报文总共有15种报文类型,对于MQTT的报文类型的定义以及各类报文的功能,见表2:
表2 控制报文类型
对于每一类报文,都有专门的报文结构和属性,由于篇幅原因,不在此过多赘述,具体见MQTT Version 5.0 (oasis-open.org)。
(3)MQTT的连接模式
MQTT的持久连接是指客户端与服务器之间的连接能够保持长期的状态,这种持久连接的特性是MQTT协议的一个重要特点,它为设备之间的通信提供了灵活性和效率。在传统的HTTP通信中,客户端向服务器发送请求后,服务器响应请求后即刻断开连接,这种请求/响应模式在某些场景下效率较低,因为每次通信都需要建立新的连接。而在MQTT中,客户端与服务器通过CONNECT报文连接后,即使在没有数据传输的情况下也能维持连接。为了确保连接的活跃性,客户端和服务器之间会定期交换心跳包。客户端会定期发送心跳包给服务器,告知自己的状态;服务器也会定期向客户端发送心跳包,确保客户端处于活跃状态,如图2。
图2 MQTT持久连接示意图
(4)MQTT的订阅主题
MQTT中客户端向服务器发送SUBSCRIBE报文用于创建一个或多个订阅。SUBSCRIBE报文支持通配符,也为每个订阅指定了最大的QoS等级,服务器根据这些信息分发应用消息给客户端。当服务器收到SUBSCRIBE报文,必须回复SUBACK报文,其中的报文标识符要与原始SUBSCRIBE报文相同。如果收到的主题过滤器与现有订阅相同,则应该替换现有订阅。订阅的主题过滤器必须是UTF-8字符串,服务器应支持通配符过滤器。每个过滤器后面跟着一个字节,表示请求的最大QoS等级,如图3。
图3 MQTT订阅主题
(5)MQTT的发布消息
MQTT定义了三个不同的服务质量等级(QoS):
· QoS 0:最多一次交付,消息发布后不做确认。
· QoS 1:至少一次交付,确保消息至少被接收一次。
· QoS 2:恰好一次交付,确保消息仅被接收一次。
QoS值表示应用消息分发的服务质量等级保证。不同的QoS等级决定了PUBLISH控制报文的处理方式。接收者(服务器或客户端)必须根据PUBLISH报文中的QoS等级发送相应的应答报文。MQTT根据QoS等级分发应用消息。当服务器向多个客户端(订阅者)分发消息时,每个客户端独立处理。消息的服务质量可能因订阅者指定的QoS等级而异。发布者在发布消息时指定了服务质量等级。
发布者必须发送QoS为0,DUP为0的PUBLISH报文。这种报文服务器不发送响应,发布者不重试,发送消息时立即丢弃。消息可能仅送达一次或根本不送达。服务器接收PUBLISH报文后将消息分发给订阅该主题的订阅者。
QoS1的PUBLISH控制报文确保消息至少送达一次,可能被多次处理。可变报头包含报文标识符,需要PUBACK报文确认。发布者必须分配未使用的报文标识符,并等待服务器的PUBACK报文确认。发送的PUBLISH报文必须包含报文标识符,QoS为1,DUP为0。如果收到PUBACK报文,发布者可以重复使用标识符。接收者的PUBACK报文必须包含来自PUBLISH报文的标识符。发送PUBACK后,接收者必须将相同标识符的入站PUBLISH报文视为新消息,忽略其DUP标志。
QoS2的PUBLISH控制报文提供最高服务质量,不容忍消息丢失和重复。消息变量头包含报文标识符。接收者使用两步确认过程来确认消息。发送者分配未使用的标识符,并等待PUBREC确认。收到PUBREC后,发送PUBREL,并等待PUBCOMP确认。发送PUBREL后不能重发PUBLISH。接收者发送PUBREC后可以存储消息并分发给订阅者(方案1),或等待PUBREL后再分发(方案2)。发送PUBCOMP后,可以丢弃标识符(方案1),或分发消息并丢弃(方案2)。接收者发送PUBCOMP后,任何后续PUBLISH报文被视为新的发布。
(6)MQTT取消订阅
客户端发送UNSUBSCRIBE报文给服务器以取消订阅主题。报文固定报头的特定位必须设置为0,0,1,0。有效载荷包含要取消订阅的主题过滤器列表,必须是UTF-8编码字符串。UNSUBSCRIBE报文必须至少包含一个有效载荷,包含已订阅的主题过滤器。服务器删除订阅后不再将该主题的消息发送给客户端,并完成任何QoS1和QoS2消息的分发。服务器必须发送UNSUBACK报文作为响应,包含与UNSUBSCRIBE相同的报文标识符。即使没有删除任何订阅,服务器也必须发送UNSUBACK响应。
图4 MQTT取消订阅
(7)MQTT断开连接
DISCONNECT报文是客户端发给服务端的最后一个控制报文,表示客户端正常断开连接。报文的固定报头保留位必须全为0。客户端发送DISCONNECT后必须关闭网络连接,不能再发送其他控制报文。服务端收到DISCONNECT后,必须丢弃与当前连接关联的未发布的遗嘱消息,并在客户端未关闭网络连接时主动关闭连接。
图5 MQTT断开连接
02
模糊测试技术
模糊测试(Fuzzing Test)是一种通过将随机数据(非预期输入)输入到目标系统以评估是否会出现非预期行为的测试方法,已经在计算机网络安全测试领域获得了广泛应用,在自动化漏洞挖掘方面具备优异表现。在MQTT协议的模糊测试中,我们可以通过向MQTT消息中注入异常数据或者随机生成各种消息格式和内容的数据包,来测试MQTT服务器的稳定性和安全性。
下面介绍一些通过模糊测试挖掘到的MQTT协议的CVE漏洞:
(1)数据包长度检测不当
网络数据包是在网络上传输和接收的格式化数据单元。每个MQTT数据包通常包含四个主要字段:控制头部、数据包长度、可变头部和有效载荷。前两个字段对于每个数据包都是必需的,其他字段是可选的。
图6 MQTT报文包格式[1]
数据包解析是提取和识别数据包字段的过程。然而,由于数据包构建方法的进步,攻击者可以利用协议漏洞来错误解析数据包,尤其是对于将解析视为顺序活动的协议。很多MQTT协议栈实现的漏洞都是由于在解析之前缺少或不正确的长度检查。例如,在CVE-2021-41036中,Eclipse Paho MQTT 客户端未验证收到报文中的剩余长度的大小。类似地,在CVE-2020-10071中,Zephyr MQTT解析代码对已发布消息的长度字段进行不充分的检查,这可能导致缓冲区溢出攻击和远程代码执行。还有其他一些漏洞,例如CVE-2020-10070和CVE-2020-10063,它们也是由于不正确的长度检查而存在。这些漏洞不仅可能导致DoS攻击,还可能导致其他严重威胁,如远程代码执行(RCE)或读取内存内容。
(2)缺乏必要字段检测
缺乏必要字段检查是由于在协议实现过程中忽略了对必需字段的验证而导致的。正如之前所述,在MQTT中,数据包长度和数据包字段随着数据包类型的不同而变化。因此,应该针对数据包类型明确实施必需字段检查的实现。例如,如果一个数据包包含用户名字段,那么相关的密码字段也必须存在,因为缺少这样的密码部分会使实现处于危险之中。在CVE-2019-9749中,Fluent Bit中MQTT输入插件对一个精心制作的数据包的处理导致服务器崩溃。在CVE-2018-11993中,对MQTT连接请求时访问堆栈的不当检查导致缓冲区溢出攻击。此外,在CVE-2018-8531中,Azure IoT Hub设备对MQTT协议内存访问的操作限制不当导致远程代码执行攻击。与不正确的必需字段检查实现缺陷相关的漏洞包括CVE-2016-9877(MQTT代理对具有有效用户名但省略密码部分的连接请求进行身份验证),CVE-2017-2893(MQTT代理在处理没有订阅参数的订阅数据包时崩溃)。
(3)缺少逻辑错误检测
该问题是由于数据包中缺乏逻辑错误检查以及实现中未对其进行识别而引起的。在CVE-2021-42386中,Busybox在运行AWK模式时会导致服务拒绝。在CVE-2019-9749中,Fluent Bit中的MQTT在输入插件处理特意编辑的数据包时会导致服务器崩溃。在CVE-2018-11998中,处理MQTT中的一个特意制作的数据包解码请求时发生了一个ace条件,导致缓冲区溢出攻击。在CVE-2020-13849中,由于缺乏对客户端发送的Keep-Alive值的逻辑检查,MQTT服务器受到了拒绝服务攻击。在CVE-2019-11778中,当处理一个“will delay interval”( 服务器等待再发布遗嘱消息的时间间隔)大于“session expiry interval”( 客户端与服务器之间的会话时间)的数据包时,MQTT服务器会崩溃。
(4)其他错误
还有一些CVE漏洞是由于对内容类型、数据类型、身份验证绕过、无效证书和无效访问的错误处理。由于不正确处理非UTF-8编码字符的客户端ID或主题名称而导致的漏洞CVE-2020-13932,攻击者利用了Apache ActiveMQ Artemis 2.5.0到2.13.0(MQTT服务器)中的一个漏洞,在服务器接受包含非UTF-8编码字符的客户端ID和主题名称的MQTT数据包。通过利用这种漏洞,攻击者可以执行任何易受攻击的脚本或命令来获取对MQTT服务器的访问权限,从而允许他进行恶意活动。类似地还有与数据类型相关的漏洞,由于变量的不正确初始化,如在CVE-2019-5917中,通过利用Microsoft Azure的MQTT客户端服务中的未指定的向量,进行了拒绝服务攻击。
身份验证绕过相关的漏洞,主要利用的是网络上传输的信息未加密和未编码。例如,在CVE-2019-5635中,由于未加密智能桥设备与MQTT代理之间的数据传输,攻击者使用默认用户名和密码攻击了MQTT代理。同样,无效访问相关的漏洞是由于错误的文件和对象权限导致的。例如,在CVE-2018-8531中,报告了Azure IoT Hub设备访问内存中的对象漏洞,这种情况下攻击者可以执行内存损坏的操作。
如果想要自己对MQTT服务器进行模糊测试,可以使用BlitzFuzz工具进行操作。BlitzFuzz(点击查看详情)作为一款专门针对工控网络协议的渗透模糊测试工具,支持CAN、CAN、UDS、SOME/IP、DoIP等汽车常用协议的报文仿真、解析功能,提供相关协议的渗透测试用例包、合规测试用例包以及模糊测试功能。
在BlitzFuzz的模糊测试界面中,可以选择添加MQTT模糊测试用例来对被测件进行模糊测试。针对不同的MQTT报文类型,可以选择不同的MQTT报文类型进行参数配置,选择变异策略进行不同方式的变异策略及模糊数据的生成。同时可以配置多种监控套件对被测件进行监控,查看模糊用例对被测件的影响,如图7。
图7 BlitzFuzz MQTT模糊配置界面
首先将将被测件通过网线连接BlitzFuzz工具。测试人员在BlitzFuzz前端界面配置需要进行模糊的MQTT报文信息及相关配置,包括被测件的基础信息如MAC、IP,以及选择使用的监控套件参数,用于判断被测件发送的模糊数据情况。参数填写完成后选择测试用例并运行,运行结束后即可在界面查看测试报告,如图8。
图8 BlitzFuzz模糊测试示意图
参考文献:
[1] Husnain M, Hayat K, Cambiaso E, et al. Preventing mqtt vulnerabilities using iot-enabled intrusion detection system[J]. Sensors, 2022, 22(2): 567.
[2] Hwang, H. C., Park, J., & Shon, J. G. (2016). Design and implementation of a reliable message transmission system based on MQTT protocol in IoT.
[3] Soni D, Makwana A. A survey on mqtt: a protocol of internet of things (iot)[C]//International conference on telecommunication, power analysis and computing techniques (ICTPACT-2017). 2017, 20: 173-177.
[4] Singh M, Rajan M A, Shivraj V L, et al. Secure mqtt for internet of things (iot)[C]//2015 fifth international conference on communication systems and network technologies. IEEE, 2015: 746-751.
原文始发于微信公众号(鉴源实验室):基于MQTT协议的模糊测试研究