A New Way of Jolokia Remote Code Execution
0x01 Preface
Last week, I saw an interesting case about JDBC attack reported by @JJaaskela in HackerOne. It caught my attention, so I intended to analyse this case.
Here is the link of this report:
https://hackerone.com/reports/1547877
Due to the bug fix, I cannot reproduce the vulnerablity. But I still can obtain some clues according to the description of this report.
Aiven is a next-generation managed cloud database service that hosts your software infrastructure services. It supports diverse kinds of data sources, like Apache Kafka, PostgresSQL, MySQL, Redis, etc. Obviously, JDBC connections exist in these scenarios.
The root causes of this vulnerablity are as follow:
The reporter found the service supported Jolokia service according to the logs in web console, and the HTTP sink connector allowed user to send HTTP request to localhost, Jolokia service was listening on
localhost:6725
as well.JMX exposes the Mbean called
com.sun.management:type=DiagnosticCommand
, it has a special operation namedjvmtiAgentLoad
.The HTTP Sink Connector did not verify the data source target whether or not a local resource, so we can utilized the operation
jvmtiAgentLoad
to load a local jar file. In this case the jar file is the SQLite database file.
Loading class
As we know, we can use different ClassLoaders to load java classes from diverse origins. The main origins as follow:
Loading .class file from local system directly, which is the loading method of most classes.
Loading .class file from archives such as zip, jar, etc.
Loading .class file or data through the network.
Extract .class file from proprietary databases.
Upload the Java source file to the server, dynamically compile it into .class file and perform loading.
So we can create a malicious jar file and then insert the jar file data into the SQLite database as the BLOB data type.
0x02 About Jolokia
First of all , let’s review the Jolokia concept and its historical vulnerablities.
Jolokia is a JMX-HTTP bridge giving an alternative to JSR-160 connectors. It is an agent based approach with support for many platforms. In addition to basic JMX operations it enhances JMX remoting with unique features like bulk requests and fine grained security policies.
In the past days, there are several security researchers have shared their findings about Jolokia.They disclose a lot of weaknesses that exist in the Jolokia component. If you are interested in the vulnerabilities, you could review their write-ups.
https://www.veracode.com/blog/research/exploiting-spring-boot-actuators
https://thinkloveshare.com/hacking/ssrf_to_rce_with_jolokia_and_mbeans/
I’m sure you’re aware Jololia often exposes many Mbeans, many of which are utilized to triger remote code execution vulnerabilities. In this case, we talk about the Mbean named com.sun.management:type=DiagnosticCommand
0x03 JVMTI & Instrument
In this case, Jolokia exposes the com.sun.management:type=DiagnosticCommand
MBean, it has a risky operation named jvmtiAgentLoad
. So what is JVMTI?
JVMTI(JVM Tool Interface) which is the native interface provided by the java virtual machine. JVMTI is just a set of interfaces. If we want to develope JVM tools, we need to write an agent programme to use these interfaces. Agent programme is atually a C or C++ language written dynamic link library. So loading a malicious .so file can lead remote code exection. However, Java introduced Instrumentation
since in JDK 5.
Using Instrumentation interface, we can call the dynamic library of libinstrument through Java code to interact with the JVMTI interface, eliminating the need to develop native dynamic link library files.
The Instrument mechanism includes two integration forms: one is the main method is executed before startup, and the other is the main method is loaded internally through attach.
- premain (Agent mode): Main method is invoked before the target application starting.
1 | java -javaagent:/path/to/javaagent.jar -jar application.jar |
The argument -javaagent
needs to be in front of -jar
. Otherwise, it will not take effect.
1 | public static void premain(String agentArgs, Instrumentation inst); |
The premain method is relatively simple. It’s a jar file of the java agent. After adding this jar to the startup command, the premain method will be run before the main method is started. It should be noted that to make the jar file know which premain method to start, we also need to define it in the manifest file. There are also two ways to define a menifast. One is to write a menifast file directly, and the other is to use Maven’s plug-in to write it.
agentmain(Attach mode): In addition to the target application, use an attach application to inject javaagent.jar into the target application.
1
2public static void agentmain(String agentArgs, Instrumentation inst);
public static void agentmain(String agentArgs);
The attach method is relatively troublesome. You need to set up a separate application (or use a different thread), find all running VirtualMachineDescriptors through VirturalMachine. list(), match them to the target application, and then inject javaagent.jar into the target application.
If you have known the above knowledge, it is not difficult to realize using the jvmtiAgentLoad
operation of com.sun.management:type=DiagnosticCommand
mbean,we can inject malicious java agent into the application by attach mode without restarting target application.
0x04 Create malicious Jar file
Firstly, the JDK provides two static methods, premain
and agentmain
, which can be used directly. Here I use the agentmain
method.
If you create MANIFEST.MF
manually, you need to specify the Agent-Class, and finally build the jar file.
It should be noted here that if a standard so file supported by JVMTI is called, there will be an error.
"Agent_OnAttach is not available in /tmp/ext.so "
The reason is that the JVMTI is invoked through the Agent_ OnAttach
as the entry function, and then execute the following process to load the Java agent.
Get
JNIEnv
to ensure that it has been successfully attached to the Java process.Create and initialize
JPLISAgent
, then makeVMInit
monitoring (it will not be triggered), and the logic is the same asOnLoad
.Read Agent-Class and load it.
Read the META-INFO related configuration and set the
mRetransformEnvironment ClassFileLoadHook
listening. The logic is the same asOnLoad
.Create an
InstrumentationImpl
instance.Set the
mNormaltransformEnvironment ClassFileLoadHook
listeningExecute AgentMain method
The Java agent code as follow:
1 | public class JavaAgent { |
Inject malicious jar file stream into database file
Just use the JDBC Sink Connector feature.When establishing the SQLite JDBC connecting , a SQLite database file is created automatically, then insert the malicious jar file data into the database table.
According the Oracle official document definition:
We can clearly know that the jar file is a kind of archives, like zip, tar,etc. It has no restriction about the file name.Consequently we can embed the jar files in other files just like zip files, without affecting their normal usage.
Eventually,when the SQLite database file exists in the local disk, using jvmtiAgentLoad
operation to load the specified jar file.
Final Inllustration
Owing to the vulnerability being fixed, I set up a local environment to reproduce it.
Inject malicious Java agent into SQLite database file
During JDBC connection, if the database file does not exist ever, a SQLite database file
foo.jar
will be automatically created through thegetConnection
method ofDriverManager
and then create a table through the other corresponding SQL statement.
- Write the malicious Java agent into the database as Blob data type. In my illustration, I write the malicious
agent.jar
into the SQLite database filetest.jar
.
- Load Java agent
1 | http://127.0.0.1:8099/actuator/jolokia/exec/com.sun.management:type=DiagnosticCommand/jvmtiAgentLoad/!/tmp!/agent.jar |
- Successfully attach the malicious Java agent and complete the RCE