Liferay Portal反序列化


漏洞概述

Liferay(又称Liferay Portal)是一个开源门户项目,该项目包含了一个完整的J2EE应用。该项目使用了Web、EJB以及JMS等技术,特别是其前台界面部分使用Struts 框架技术,基于XML的portlet配置文件可以自由地动态扩展,使用了Web Services来支持一些远程信息的获取,使用 Apache Lucene实现全文检索功能。

7.2.1 CE GA2 之前的 Liferay Portal 中不可信数据的反序列化允许远程攻击者通过 JSON Web 服务 (JSONWS) 执行任意代码。

漏洞复现

环境搭建

下载tomcat集成包,在liferay-ce-portal-7.2.0-ga1\tomcat-9.0.17\bin路径下打开startup.bat,等待tomcat服务开启。

访问http://127.0.0.1:8080能正常访问下图页面则说明搭建成功。

img

跟随网页提示完成初始化后进入以下页面,漏洞环境搭建完成

img

漏洞利用

构造恶意代码

img

将其编译为class文件后开启http服务

img

使用Java反序列化利用工具marshalsec的c3p0模块生成payload

img

将构造完成的payload放入请求数据包中

img

可以看到成功执行弹出计算器的命令

img

漏洞分析

从nvd官网对CVE-2020-7961的描述中发现反序列化的数据是经过了JSON web service的

img

定位到WEB-INF/web.xml中

img

通过该映射规则的servlet找到其对应的类为com.liferay.portal.jsonwebservice.JSONWebServiceServlet

img

跟进这个servlet类,其中的service方法中定义了查看json web服务的路径

img

在web页面中输入路径http://url/api/jsonws可查看api列表。

img

在这些接口有多个接口参数接收java.lang.object,比如update-column,意味着在此处传递的参数可以构造符合Java Beans的可利用恶意类

img

liferay在7以前的版本使用flexjson处理、序列化json数据而在7以后使用jodd json处理、序列化json数据,这里主要分析liferay7之后的版本。

通过查阅资料得知liferay中的com.liferay.portal.json.JSONSerializerImpl实现了jodd中的json序列化的接口JSONSerializer

img

在com.liferay.portal.json.JSONDeserializerImpl中实现了了jodd中的反序列化接口JSONDeserializer

img

通过漏洞发现者whitecode团队给出jodd.json.Parser的调用图,我们可以在JSONWebServiceServlet下断点后发送/api/jsonws/invoke请求

img

一直debug到JSONWebServiceSerlet的父类JSONservlet中发现调用execute处理json继续跟入此方法

img

观察com.liferay.portal.struts.JSONAction的execute方法,首先调用rerouteExecte检测路径,调用checkAuthToken方法鉴权,接着调用getJSON再对json数据处理,跟进getJSON

img

在没有上传异常通过后进入getJSONWebServiceAction

img

在JSONWebServiceAction中继续更热返回的JSONWebServiceInvokerAction类的invoke方法

img

在invoke方法的第一行中发现这里反序列化了_command,__command参数是用来传入调用的api方法

img

继续往下调用了_parseStatement,__executeStatement

img

跟入_executeStatement观察result的成分继续深入jsonWebServiceAction

img

从下面代码发现getJSONWebServiceAction()最后返回的是一个JSONWebServiceActionImpl实例

public JSONWebServiceAction getJSONWebServiceAction(

HttpServletRequest httpServletRequest)

throws NoSuchJSONWebServiceException {

String path = GetterUtil.getString(httpServletRequest.getPathInfo());

String method = GetterUtil.getString(httpServletRequest.getMethod());

String parameterPath = null;

JSONRPCRequest jsonRPCRequest = null;

int parameterPathIndex = _getParameterPathIndex(path);

if (parameterPathIndex != -1) {

parameterPath = path.substring(parameterPathIndex);

path = path.substring(0, parameterPathIndex);

}

else {

if (method.equals(HttpMethods.POST) &&

!PortalUtil.isMultipartRequest(httpServletRequest)) {

jsonRPCRequest = JSONRPCRequest.detectJSONRPCRequest(

httpServletRequest);

if (jsonRPCRequest != null) {

path += StringPool.SLASH + jsonRPCRequest.getMethod();

method = null;

}

}

}

JSONWebServiceActionParameters jsonWebServiceActionParameters =

new JSONWebServiceActionParameters();

jsonWebServiceActionParameters.collectAll(

httpServletRequest, parameterPath, jsonRPCRequest, null);

if (jsonWebServiceActionParameters.getServiceContext() != null) {

ServiceContextThreadLocal.pushServiceContext(

jsonWebServiceActionParameters.getServiceContext());

}

JSONWebServiceActionConfig jsonWebServiceActionConfig =

_findJSONWebServiceAction(

httpServletRequest, path, method,

jsonWebServiceActionParameters);

return new JSONWebServiceActionImpl(

jsonWebServiceActionConfig, jsonWebServiceActionParameters,

_jsonWebServiceNaming);

}

跟入JSONWebServiceActionImpl观察_prepareParameters方法,通过反射获取所有参数,for遍历拿到参数名并处理参数值,当参数值不为空时,会进行类型转换。

img

继续往后跟进跟进参数调用_convertValueToParameterValue方法

img

其中折叠的部分包含了将json反序列化传入的参数值,赋值给parameterValue的过程,并判断不是map实例并且是以{开头就反序列化JSONFactoryUtil.looseDeserialize(valueString, parameterType),如果parameterType可控,那么就会造成反序列化漏洞

img

上述的_jsonWebServiceActionParameters在其定义的过程中存入了一个JSONWebServiceActionParametersMap

img

跟入JSONWebServiceActionParametersMap其中的putty方法在whitecode的文章中描述的很清晰,参数的类型取自key传进来的字符串,如果请求参数名称包含 ‘ :‘,传递进来的值会被构造为”:”前是key,”:”后是typename的hashmap。

img

参考链接

https://xz.aliyun.com/t/7499#toc-9

https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html

https://paper.seebug.org/1162/


文章作者: jokerscar
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 jokerscar !
  目录