xiaoxiong's blog Thinking and Action

JMX-RMI反序列化中的小研究

2021-07-12

简述

RMI 数据传输基于反序列化,如果服务中实现了 RMI 的调用且具有 Object 类型参数,那么就会造成反序列化(实际攻击中需要反序列化链)

JMX 服务是基于 RMI 实现,且将凭证对象作为Object 参数传入,如果使用恶意构造的对象替代凭证传入,是否能攻击需要凭证认证的 JMX 服务了。

针对 JMX 的攻击

YSO 中有一个针对JMX的攻击模块,当JMX服务器存在反序列化链时,可以对JMX服务进行攻击

java -cp ysoserial.jar ysoserial.exploit.JMXInvokeMBean 192.168.8.2 1689 CommonsCollections1 gnome-calculator

JMX 服务基于 RMI 实现,在分析其源码时发现,JMX RMIServer 中,存在有 newClient 方法的参数为 Object 对象,存在 RMI 反序列化条件。

且将newClient 参数为 credentials 凭证对象,那么是否可以使用恶意对象替代凭证传入,攻击需要凭证认证的 JMX 服务了。

具有Object 类型参数,会参数进行反序列化

环境搭建

环境配置

启动参数中添加

-Dcom.sun.management.jmxremote.port=2222 -Djava.rmi.server.hostname=192.168.8.1 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true

修改对应 java 版本中 jre 中的 jmx 的用户名密码及 访问权限


/Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/management

1. 复制 模版文件生成 jmxremote.password
2. 添加 用户名及密码 test test
3. 添加对应用户的权限,修改文件 jmxremote.access

monitorRole   readonly
controlRole   readwrite \
              create javax.management.monitor.*,javax.management.timer.* \
              unregister
test readwrite	\
	create javax.management.monitor.*,javax.management.timer.* \
              unregister

jmx Server

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;


public class JMXServerWithAuth {
    public static void main(String[] args) throws Exception {

        // Create a new MBean instance from Hello (HelloMBean interface)
        Hello mbean = new Hello();

        // Create an object name,
        ObjectName mbeanName = new ObjectName("de.mogwailabs.MBeans:type=HelloMBean");

        // Connect to the MBean server of the current Java process
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        server.registerMBean(mbean, mbeanName);

        // Keep the application running until user enters something
        System.out.println("Press any key to exit");
        System.in.read();
    }
}

调试细节

需要凭证的 JMX 服务

JDK 版本 8u291

需要凭证认证调试, 在进行反序列化之前进行了类型检查,需要在白名单之类,只能为 String 或者 String字符串类型

调用栈如下

关键函数

不需要凭证的 JMX 服务

调用栈

在 var1 instanceof DeserializationChecker 判断时产生分歧,需要权限的 JMX-Server 是 RMIJRMPServerImpl$ExportedWrapper 类型,进入 unmarshalParameterUnchecked 函数,而在 无需凭证时,进入 checked 函数

回溯

回溯一下 var1 生成

newRMIJRMPServerImpl , 需要 凭证的server env是存储了凭证信息的

2ff437f50145556b9a2a6f4b0cf22074.png

RMIJRMPServerImpl 构造方法,当 types(允许的类型)不为空时,返回 内部类 ExportedWrapper

ae9953b1ceac6db211bac8bf8964146c.png

真相大白,对于开启了凭证认证的 JMX 服务 会使用 exportedWrapper 对 RMIJRMPServerImpl 实例进行包装,而不需要凭证认证的 JMX 服务则直接返回RMIJRMPServerIMPL实例,不会进行类型检查

对比oracle jdk, 在 jdk8u77 之后,8u91 更新了这个补丁 82b6f5682e538100d16e96fb30723159.png

总结

在 JAVA 版本低的情况下(8u77),是可以直接攻击 JMX 服务(存在反序列化链)的;但是当版本高之后,则不可以。

在现行版本(jdk8u291)情况下,对于开启了凭证认证的 JMX 服务 会使用 exportedWrapper 对 RMIJRMPServerImpl 实例进行包装,而不需要凭证认证的 JMX 服务则直接返回RMIJRMPServerIMPL实例,不会进行类型检查。

使用凭证认证基本保证了 JMX 服务的安全性,但是 JAVA 版本低的情况下(8u77)仍然能够使用 RMI 其他的攻击方式。

在 JMX 不需要认证的情况下,只要对应主机有相应攻击链就可以满足攻击条件。


Similar Posts

Comments