Facebook Google Plus Twitter LinkedIn YouTube RSS Menu Search Resource - BlogResource - WebinarResource - ReportResource - Eventicons_066 icons_067icons_068icons_069icons_070

[R1] Liferay CE Portal /api/liferay Java Deserialization Blacklist Bypass Remote Code Execution

Critical

Synopsis

Liferay Portal is a web platform that lets you "create and connect personalized digital experiences across web, mobile and connected devices". The software has both an open source “community edition and a commercial “Digital Experience” or “Enterprise” edition. While some of our engineers had never heard of Liferay Portal, they were impressed to see that it has been forked nearly 2000 times on GitHub, as well as when Shodan returned over 7,000 hosts running Liferay Portal.

While investigating LPS-67681 for a potential Nessus detection plugin, we found that there was a Java object deserialization blacklist. Given our history with deserialization vulnerabilities and a strong aversion to blacklists, due to them rarely working, we immediately wondered if we could bypass it.

We could not find a CVE associated with deserialization and Liferay Portal in public or private databases. However, we did find the initial commit into the 7.0 branch as well as an advisory for the 6.x branch related to Java serialization (tracked as VulnDB ID 136465). It is interesting to note that Liferay assigns the severity of ‘1’, out of a two-point system, rather than using CVSS.

Additionally, note that Liferay’s advisory indicates that the deserialization endpoints (TunnelServlet (/api/liferay) and Spring-Remote (/api/spring)) are restricted to localhost by default, and only allows user’s to add specific IPs to the ACL (no wild cards are supported). In theory, that’s pretty solid. Unfortunately, users are often shortsighted. This is proven by looking through the first few entries of Shodan. On the first couple of pages, we were able to make an initial HTTP request to two of the servers restricted endpoints on four servers to verify they are Internet addressable. How does that occur, you ask? One hint is HTTP 403 messages we received that look like this:

	HTTP Status 403 - Access denied for 192.168.146.20

As you can probably guess, that wasn't the IP we tested from. In fact, that’s an internal IP. Presumably, the vulnerable servers have a proxy in front of them and some admin has added the IP of the proxy to the ACL – therefore allowing the entire Internet access to the restricted endpoints. Good for attackers, bad for organizations. This makes any potential attack on those interfaces much more interesting.

The blacklist found in the latest version (Liferay CE Portal 7.0 GA3) covers all known gadgets except C3P0, DiskFileItem variants, JRMPListener, JRMPClient, and Java DoS gadgets. For example, attempting to poke a blacklisted gadget results in:

com.liferay.portal.kernel.io.ProtectedObjectInputStream.restricted.class.names=\
        com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,\
        org.apache.commons.collections.functors.CloneTransformer,\
        org.apache.commons.collections.functors.ForClosure,\
        org.apache.commons.collections.functors.InvokerTransformer,\
        org.apache.commons.collections.functors.InstantiateFactory,\
        org.apache.commons.collections.functors.InstantiateTransformer,\
        org.apache.commons.collections.functors.PrototypeFactory$PrototypeCloneFactory,\
        org.apache.commons.collections.functors.PrototypeFactory$PrototypeSerializationFactory,\
        org.apache.commons.collections.functors.WhileClosure,\
        org.apache.commons.collections4.functors.InvokerTransformer,\
        org.codehaus.groovy.runtime.ConvertedClosure,\
        org.codehaus.groovy.runtime.MethodClosure,\
        org.springframework.beans.factory.ObjectFactory,\
        org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider,\
        sun.reflect.annotation.AnnotationInvocationHandler

That said, getting around the blacklist isn’t difficult. Why "getting around the blacklist" instead of "bypassing"? Typically, this involves using a byte[] from the blacklisted ObjectInputStream to create a new ObjectInputStream that doesn’t have a blacklist.

If we can bypass the blacklist then what do we get? Liferay has updated both Commons Collections and Groovy to the "non-vulnerable" versions. However, there are still vulnerable libraries on the classpath; for example, Commons BeanUtils. There is a project on GitHub that contains a list of the known bypass objects. It just so happens that Liferay includes one of these as objects via Commons Beanutils. We have written a PoC for Linux-based Liferay Portal called "beanutils_bypass.py" and shared with the vendor. The PoC simply touches “/tmp/beans_bypass.py” via sending an unauthenticated HTTP POST to the /api/liferay endpoint.

We found another bypass object on the classpath that we don’t believe anyone has yet found or reported. We can use a SerializableRenderedImage from Oracle's jai_core.jar to bypass the blacklist. We also wrote a PoC for Linux-based Liferay Portal called "image_bypass.py" that simply touches “/tmp/image_bypass” via sending an unauthenticated HTTP POST to the /api/liferay endpoint.

In addition to the above, we can also use ysoserial’s "JRMPClient.java" to create a connect back to an RMI Registry of our choice, from which we can then trigger remote code execution. We didn’t create a PoC for this one since it’s a little more complicated and the other PoC scripts demonstrate the bypass sufficiently. For a box of oatmeal cream pies and six-pack of Mr. Pibb, we'll loan you Jacob to write a PoC for that one too.

Solution

Liferay has released a patch (LSV-278) that addresses this issue. Note that the advisory and patch require authentication.

Disclosure Timeline

2016-09-09 - Issue discovered
2016-09-14 - Advisory initial draft
2016-09-14 - Vendor notified via security@liferay.com
2016-09-15 - Vendor ack, discusses some issues
2016-10-19 - Ping vendor for update
2016-10-20 - Vendor says fix is done, waiting for backport.
2016-11-24 - Ping vendor for update
2016-11-25 - Vendor says they are "in a process of negotiating the next security release schedule ... should know more next week."
2016-12-09 - Vendor says release date set for Dec 13
2016-12-14 - Tenable says adding auth is popular mitigation, but encourages documentation to be updated reflecting the ability of auth'd users to execute code via the interface
2016-12-15 - Vendor thanks us for idea, says will update documentation soon.
2017-01-04 - Ping vendor to see if new version was released in Dec
2017-01-06 - Vendor says new version released for EE, but community version with fix not available yet
2017-01-09 - Vendor says no ETA for community edition (CE), but will be in next GA which is ~ 6 months

All information within TRA advisories is provided “as is”, without warranty of any kind, including the implied warranties of merchantability and fitness for a particular purpose, and with no guarantee of completeness, accuracy, or timeliness. Individuals and organizations are responsible for assessing the impact of any actual or potential security vulnerability.

Tenable takes product security very seriously. If you believe you have found a vulnerability in one of our products, we ask that you please work with us to quickly resolve it in order to protect customers. Tenable believes in responding quickly to such reports, maintaining communication with researchers, and providing a solution in short order.

For more details on submitting vulnerability information, please see our Vulnerability Reporting Guidelines page.

If you have questions or corrections about this advisory, please email advisories@tenable.com