JMX

JMX (Java Management Extensions) Java管理扩展

JMX经常被称为“Java 版本”的SNMP(Simple Network Management Protocol)。SNMP主要用于监控如交换机或路由器等网络组件。类似地,JMX用于检测Java程序,如应用程序的堆内存使用量、线程数、VM概要等。

image-20230904150434925
层次
描述

Instrumentation

主要包括了一系列的接口定义和描述如何开发MBean的规范。在JMXMBean代表一个被管理的资源实例,通过MBean中暴露的方法和属性,外界可以获取被管理的资源的状态和操纵MBean的行为

Agent

用来管理相应的资源,并且为远端用户提供访问的接口。该层的核心是MBeanServer,所有的MBean都要向它注册,才能被管理。注册在MBeanServer上的MBean并不直接和远程应用程序进行通信,他们通过协议适配器(Adapter)和连接器(Connector)进行通信。

Distributed

定义了一系列用来访问Agent的接口和组件,包括AdapterConnector的描述。注意,AdapterConnector的区别在于:Adapter是使用某种Internet协议来与 Agent获得联系,Agent端会有一个对象 (Adapter)来处理有关协议的细节。比如SNMP AdapterHTTP Adapter。而Connector则是使用类似RPC的方式来访问Agent,在Agent端和客户端都必须有这样一个对象来处理相应的请求与应答。比如RMI Connector

MBeans

JMX除了检测程序的运行情况,实际上提供了更强大的功能 —— MBeans(Managed Beans)

MBean代表一个被管理的资源实例,通过MBean暴露的方法和属性,外界可以获取被管理的资源的状态和操作MBean的行为。MBean遵循JXM标准的设计标准,允许使用者像管理Bean那样来管理资源。

MBean对象的创建,跟POJO一样

  • 实现一个接口

  • 提供默认的无参构造器

  • 实现属性的getter/setter

MBean Server

MBean Server是用于管理MBean,并代理外界对它们的访问。

可以在MBean Server注册MBean,需要遵循特定的命名规则。

默认每个Java进程都有一个MBean Server服务在运行,通过ManagementFactory.getPlatformMBeanServer();可以获取

image-20230904151914018

每个MBean都对应唯一一个ObjectName

ObjectName的格式为domain:type=MBean_type,name=MBean_name

(虽然命名格式是这样,但好像都可以随便写)

Register MBean

Export Service

将JMX服务对外暴露

设置身份验证:

或者打jar包后,添加启动参数

这种方式需要让程序暂停,如在程序末尾添加sleep或等待用户输入

JMX Connector

远程客户端可以使用JMX Connector来连接,底层基于RMI

JMX Adaptor

另外一个连接方式是JMX Adaptor,不同于JMX Connector的RMI-RPC连接方式,Adaptor可能使用HTTP进行连接,通过HTML或JSON进行通信。通常在客户端不是Java程序,不支持Java RMI,才使用这种连接方式。缺点是由于通过HTML或JSON传输,JMX Adaptor可能不支持一些类的序列化。

Jconsole

Jconsole是JDK自带的JMX服务连接工具,可以连接到本地或远程的Java进程。

image-20230904161434433
image-20230904161505925

查看属性能够调用对应属性的getter,修改属性调用对应setter

image-20230904182545447
image-20230904182615911

Way To Attack

看到这如何利用MBean也很显然了,即调用恶意MBean的方法/getter/setter

StandardMBean

javax.management.StandardMBean

看看官方的描述

An MBean whose management interface is determined by reflection on a Java interface.

By making a DynamicMBean out of an MBean, this class makes it possible to select any interface implemented by the MBean as its management interface, provided that it complies with JMX patterns (i.e., attributes defined by getter/setter etc...).

StandardMBean可以用于创建MBean,通过反射获取给定接口类的属性和方法。

因此我们可以把任意类当成MBean来创建,并调用他们实现接口中定义的方法(当然类需要实现Serializable接口)

StandardMBean的构造器调用了construct来创建DynamicBean

image-20230904185327069

需要传进一个实现类的实例和其接口

TemplatesImpl实现的接口Templates中定义的两个方法刚好可以利用

newTransformergetOutputProperties

同时getOutputProperties也满足MBean属性的getter方法

RequiredModelBean

javax.management.modelmbean.RequiredModelMBean

看一下官方的描述

Java resources wishing to be manageable instantiate the RequiredModelMBean using the MBeanServer's createMBean method.

The resource then sets the MBeanInfo and Descriptors for the RequiredModelMBean instance. The attributes and operations exposed via the ModelMBeanInfo for the ModelMBean are accessible from MBeans, connectors/adaptors like other MBeans.Through the Descriptors, values and methods in the managed application can be defined and mapped to attributes and operations of the ModelMBean. This mapping can be defined in an XML formatted file or dynamically and programmatically at runtime.

相对于StandardMBean,ModelMBean更加灵活,可以修改管理的资源为已有的Java类。RequiredModelMBean允许我们通过提供ModelMBeanInfo来指定MBean的属性和操作。这意味着我们可以定义不符合MBean的设计模式的方法,即就算其接口类没有该方法,我们也可以调用。

Invoking Arbitrary Instance Methods

java.io.File#listFiles为例

Invoking Arbitrary Static Methods

JavaUtils为例

MLet

javax.management.loading.MLet是一个MBean,其实现了MLetMBean接口

看一下这个类的描述

Allows you to instantiate and register one or several MBeans in the MBean server coming from a remote URL. M-let is a shortcut for management applet. The m-let service does this by loading an m-let text file, which specifies information on the MBeans to be obtained. The information on each MBean is specified in a single instance of a tag, called the MLET tag. The location of the m-let text file is specified by a URL

支持远程加载MBean

连接到目标JMX服务,创建MLet实例并调用其getMBeansFromURL,JMX服务会下载MLet文件中引用的JAR文件,并注册JAR中的MBean

mlet.txt

制作Evil.jar

mlet.txtEvil.jar放在web服务目录,python -m http.server 4141开启服务

缺点:需要设置jmx.remote.x.mlet.allow.getMBeansFromURL=true才能调用getMBeansFromURL

RMI Deserial

由于JMX Connector是基于RMI的,因此对于RMI的攻击同样适用于这里。

远程调用MBean方法时,方法参数在服务端经过MarshalledObject.readObject()反序列化

JMX对参数类型的验证并不严格,传入MBeanServerConnection.invoke的两个参数分别是方法参数和参数类型,只需要参数类型校验成功即可。

ysoserial中集成了这种攻击方法的payload

ysoserial.exploit.JMXInvokeMBean

Tools

https://github.com/qtc-de/beanshooter

Last updated

Was this helpful?