Up to the April 2018 CPU (6u191, 7u181, 8u171) Java’s RMI endpoints allowed HTTP tunneling of requests. Failing to implement further restrictions on these requests it was possible to perform them as cross-origin requests from third-party websites. This makes it possible to exploit otherwise unreachable RMI endpoints.

One of the more obscure features of JRMP, which forms the basis for RMI and ultimately JMX, is an alternate transport protocol that encapsulates the message payloads in the body of HTTP POST requests. On the listener side this protocol will be automatically detected (by checking whether the message starts with POST) and request handling adjusted accordingly. In the Java standard library’s JRMP server implementation this magic was unconditionally enabled up to the April 2018 critical patch update (= 6u191, 7u181, 8u171). Support for this feature has already been removed in Java 9+.

An often overlooked security issue with such HTTP based protocols is that the web’s security model does allow websites to make certain “simple” requests to other sites, including ones on the local network and even ones only reachable on the host running the browser. Applications therefor need to make sure that no dangerous/state-changing operations can be performed with these allowed-by-default cross-origin requests. Usually this can be achieved by requiring some custom headers, content type or HTTP authentication.

And that is what the implementation failed to do, ultimately allowing any website to make requests (not accessing the responses) to the RMI/JMX endpoints you thought that were only accessible on your private network.

Despite the relatively low immediate impact, combining this issue with certain other RMI/JMX vulneratiblities you may end up with an attacker on the internet gaining code execution on one of your local systems by tricking you into visiting some malicious website. This includes a couple of deserialization attacks fixed in the past CPU releases, a topic which deserves a separate post some time, as well as possibly some older bugs that allowed direct remote classloading.

I have published some PoC code for this issue at mbechler/serjs.