### Liferay Portal JSON Web Service RCE Vulnerabilities
Code White has found multiple critical rated JSON deserialization vulnerabilities affecting the Liferay Portal versions 6.1, 6.2, 7.0, 7.1, and 7.2. They allow unauthenticated remote code execution via the JSON web services API. Fixed Liferay Portal versions are 6.2 GA6, 7.0 GA7, 7.1 GA4, and 7.2 GA2.
The corresponding vulnerabilities are:
- [CST-7111: RCE via JSON deserialization](https://portal.liferay.dev/learn/security/known-vulnerabilities/-/asset_publisher/HbL5mxmVrnXW/content/id/113765197) ([LPS-88051](https://issues.liferay.com/browse/LPS-88051)/[LPE-16598](https://issues.liferay.com/browse/LPE-16598)[1](https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html#footnote-1))
The `JSONDeserializer` of Flexjson allows the instantiation of arbitrary classes and the invocation of arbitrary setter methods.
- [CST-7205: Unauthenticated Remote code execution via JSONWS](https://portal.liferay.dev/learn/security/known-vulnerabilities/-/asset_publisher/HbL5mxmVrnXW/content/id/117954271) ([LPS-97029](https://issues.liferay.com/browse/LPS-97029)/CVE-2020-7961)
The `JSONWebServiceActionParametersMap` of Liferay Portal allows the instantiation of arbitrary classes and invocation of arbitrary setter methods.
Both allow the instantiation of an arbitrary class via its parameter-less constructor and the invocation of setter methods similar to the JavaBeans convention. This allows unauthenticated remote code execution via various publicly known gadgets.
[Liferay released the patched versions 6.2 GA6 (6.2.5), 7.0 GA7 (7.0.6) and 7.1 GA4 (7.1.3)](https://liferay.dev/blogs/-/blogs/security-patches-for-liferay-portal-6-2-7-0-and-7-1) to address the issues; the version [7.2 GA2 (7.2.1) was already released in November 2019](https://liferay.dev/blogs/-/blogs/liferay-portal-7-2-ce-ga2-release). For 6.1, there is only a fixpack available.
## INTRODUCTION
Liferay Portal is one of the, if not even the most popular portal implementation as per Java Portlet Specification JSR-168. It provides a comprehensive JSON web service API at '`/api/jsonws`' with examples for three different ways of [invoking the web service method](https://portal.liferay.dev/docs/7-1/tutorials/-/knowledge_base/t/invoking-json-web-services):
1. Via the generic URL `/api/jsonws/invoke` where the service method and its arguments get transmitted via POST, either as a JSON object or via form-based parameters (the *JavaScript Example*)
2. Via the service method specific URL like `/api/jsonws/*service-class-name*/*service-method-name*` where the arguments are passed via form-based POST parameters (the *curl Example*)
3. Via the service method specific URL like `/api/jsonws/*service-class-name*/*service-method-name*` where the arguments are also passed in the URL like `/api/jsonws/*service-class-name*/*service-method-name*/*arg1*/*val1*/*arg2*/*val2*/…` (the *URL Example*)
Authentication and authorization checks are implemented within the invoked service methods themselves while the processing of the request and thus the JSON deserialization happens before. However, the JSON web service API can also be configured to deny unauthenticated access.
First, we will take a quick look at LPS-88051, a vulnerability/insecure feature in the JSON deserializer itself. Then we will walk through LPS-97029 that also utilizes a feature of the JSON deserializer but is a vulnerability in Liferay Portal itself.
## CST-7111: FLEXJSON'S `JSONDESERIALIZER`
In Liferay Portal 6.1 and 6.2, the [*Flexjson* library](http://flexjson.sourceforge.net/) is used for serializing and deserializing data. It supports object binding that will use setter methods of the objects instanciated for any class with a parameter-less constructor. The specification of the class is made with the `class` object key:
```
{"class":"fully.qualified.ClassName", ... }
```
This vulnerability was reported in December 2018 and has been fixed in the Enterprise Edition with [6.1 EE GA3 fixpack 71](https://issues.liferay.com/issues/?jql=labels+=+liferay-fixpack-portal-71-6130) and [6.2 EE GA2 fixpack 169](https://issues.liferay.com/issues/?jql=labels+=+liferay-fixpack-portal-169-6210)[2](https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html#footnote-2) and also the 6.2 GA6.
## CST-7205: JODD'S `JSONPARSER` + LIFERAY PORTAL'S `JSONWEBSERVICEACTIONPARAMETERSMAP`
In Liferay Portal 7, the Flexjson library is replaced by the [Jodd Json](https://jodd.org/json/) library that does not support specifying the class to deserialize within the JSON data itself. Instead, only the type of the root object can be specified and it has to be explicitly provided by a `java.lang.Class` object instance. When looking for the call hierarchy of write access to the `rootType` field, the following unveils:

While most of the calls have hard-coded types specified, there is one that is variable (see selected call on the right above). Tracing that `parameterType` variable through the call hierarchy backwards shows that it originates from a `ClassLoader.loadClass(String)` call with a parameter value originating from an `JSONWebServiceActionParameters` instance. That object holds the parameters passed in the web service call. The `JSONWebServiceActionParameters` object has an instance of a `JSONWebServiceActionParametersMap` that has a `_parameterTypes` field for mapping parameters to types. That map is used to look up the class for deserialization during preparation of the parameters for invoking the web service method in `JSONWebServiceActionImpl._prepareParameters(Class<?>)`.
The `_parameterTypes` map gets filled by the [`JSONWebServiceActionParametersMap.put(String, Object)` method](https://github.com/liferay/liferay-portal/blob/7.2.0-ga1/portal-impl/src/com/liferay/portal/jsonwebservice/JSONWebServiceActionParametersMap.java#L63-L143):
```java
/* */ public Object put(String key, Object value)
/* */ {
/* 64 */ int pos = key.indexOf(':');
/* */
/* 66 */ if (key.startsWith("-")) {
/* */ // [...]
/* */ }
/* 71 */ else if (key.startsWith("+")) {
/* */ // [...]
/* */ }
/* 101 */ else if (pos != -1) {
/* 102 */ String typeName = key.substring(pos + 1);
/* */
/* 104 */ key = key.substring(0, pos);
/* */
/* 106 */ if (_parameterTypes == null) {
/* 107 */ _parameterTypes = new HashMap();
/* */ }
/* */
/* 110 */ _parameterTypes.put(key, typeName);
/* */
/* 112 */ if (Validator.isNull(GetterUtil.getString(value))) {
/* 113 */ value = Void.TYPE;
/* */ }
/* */ }
/* */
/* */ // [...]
/* */
/* 142 */ return super.put(key, value);
/* */ }
```
Here the lines 102 to 110 are interesting: the `typeName` is taken from the `key` string passed in. So if a request parameter name contains a '`:`', the part after it specifies the parameter's type, i. e.:
```
parameterName:fully.qualified.ClassName
```
This syntax is also mentioned in some of the examples in the [*Invoking JSON Web Services* tutorial](https://portal.liferay.dev/docs/7-1/tutorials/-/knowledge_base/t/invoking-json-web-services).
Later in [`JSONWebServiceActionImpl._prepareParameters(Class)`](https://github.com/liferay/liferay-portal/blob/7.2.0-ga1/portal-impl/src/com/liferay/portal/jsonwebservice/JSONWebServiceActionImpl.java#L429-L501), the [`ReflectUtil.isTypeOf(Class, Class)`](https://github.com/oblac/jodd/blob/v3.6.8/jodd-core/src/main/java/jodd/util/ReflectUtil.java#L279-L284) is used to check whether the specified type extends the type of the corresponding parameter of the method to be invoked. Since there are service methods with `java.lang.Object` parameters, any type can be specified.
This vulnerability was reported in June 2019 and has been fixed this in 6.2 GA6, 7.0 GA7, 7.1 GA4, and 7.2 GA2 by using a whitelist of allowed classes.
### Demo

------
- [[1\]](https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html#footnote-mark-1) There are two editions of the Liferay Portal: the Community Edition (CE) and the Enterprise Edition (EE). The CE is free and its [source code is available at GitHub](https://github.com/liferay/liferay-portal). Both editions have their own project and issue tracker at issues.liferay.com: [CE has `LPS-*`](https://issues.liferay.com/projects/LPS/issues) and [EE has `LPE-*`](https://issues.liferay.com/projects/LPE/issues). LPS-88051 was created confidentially by Code White for CE and LPE-16598 was created publicly three days later for EE.
- [[2\]](https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html#footnote-mark-2) Fixpacks are only available for the Enterprise Edition (EE) and not for the Community Edition (CE).
Posted by [Markus Wulftange ](https://www.blogger.com/profile/14370068139467987062)
at [March 20, 2020](https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html)
Tags [Vulnerability Details](https://codewhitesec.blogspot.com/search/label/Vulnerability%20Details)
暂无评论