CVE-2020-7961:Liferay Portal 反序列化漏洞分析

阅读量    314189 | 评论 3

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

作者:Hu3sky@360CERT

0x01 漏洞背景

2020年03月20日,Code White发现了影响Liferay Portal版本6.1、6.2、7.0、7.1和7.2的多个关键级别的JSON反序列化漏洞。它们允许通过JSON web服务API执行未经身份验证的远程代码。修复的Liferay Portal版本有6.2 GA6、7.0 GA7、7.1 GA4和7.2 GA2。

Liferay(又称Liferay Portal)是一个开源门户项目,该项目包含了一个完整的J2EE应用,以创建Web站点、内部网,以此来向适当的客户群显示符合他们的文档和应用程序。

对此,360CERT建议广大用户及时安装最新补丁,做好资产自查/自检/预防工作,以免遭受黑客攻击。

 

0x02 影响版本

  • Liferay Portal: 6.1、6.2、7.0、7.1、7.2

 

0x03 漏洞详情

入口定位

首先对路由的调用进行分析,我们看到web.xml,url-pattern为/api/jsonws/*,对应的servlet-name如下。

然后看到servlet-name对应的servlet-class。

我们在service函数进行下断。

首先获取path,为/api/jsonws/之后的部分,由于我们请求的不是单纯的/api/jsonws,所以进入最下面else的部分,跟入super.service,也就是JSONServlet.service,跟入_jsonAction.execute。

调用getJson,即其子类JSONWebServiceServiceAction.getJson。

跟入getJSONWebServiceAction。

这里匹配到了invoke,即前面图中的第一种调用方式,return了一个实例化对象JSONWebServiceInvokerAction,传入request对象,继续跟入。

获取cmd参数,也就是api,左边的那一列名称。

这里我们api选择的是/expandocolumn/update-column。

不为null,于是赋值给JSONWebServiceInvokerAction对象的_command,回到getJSON,调用JSONWebServiceInvokerAction.invoke。

先调用JSONFactoryUtil.looseDeserialize处理_command。

会先调用getJSONFactory,返回之前初始化过的JSONFactoryImpl。

调用createJSONDeserializer返回JSONDeserializerImpl的实例。

调用parse解析_command。

调用parseValue,之后就是jodd-json的解析器解析流程了。处理command成一个hashmap。

回到invoke,this._parseStatement->setMethod,将command设置为_method,存入statement。

回到invoke,调用_executeStatement,传入statement。

JSONWebServiceActionsManagerUtil.getJSONWebServiceAction。

在collectAll函数里会把POST的参数赋值到jsonWebServiceActionParameters里,并存入上下文(com.liferay.portal.kernel.service.ServiceContext,里面有response,request对象相关,可以用来做回显)。

Parameters key的处理细节

在collectAll里还有一个细节,就是对参数的处理,在_collectFromRequestParameters。

这里会将key和value取出来put到_jsonWebServiceActionParameters这个map里,不过在调用put函数是,还会进一步处理key。

首先定位key里的:符号,然后去掉+/-符号,把:后面的部分赋值给typename,将key赋值成:符号前面的部分,这里就是defaultData。

接着判断在key里是否有.符号,如果有.后面的将被赋值为innerName,当然我们这里没有.,接着执行HashMap.put。

获取ActionConfig

之后调用_findJSONWebServiceAction,传入jsonWebServiceActionParameters,path,获取parameterNames,调用_getJSONWebServiceActionConfig。

获取相关config。

然后回到getJSONWebServiceAction,实例化JSONWebServiceActionImpl进行赋值。

回到_executeStatement,进入JSONWebServiceActionImpl.invoke,jsonRPCRequest变量为null,调用_invokeActionMethod。

调用_prepareParameters方法。

defaultData的处理(关键部分)

跳过了中间的coulmnId,name和type,直接看到defalutData。 parameterType是java.lang.Object,而parameterTypeName是之前从key的:后面部分提取出来的type,不为null,于是调用loadClass加载parameterTypeName。

接着调用ReflectUtil.isTypeOf进行检测,检查指定的类型是否扩展要调用的方法的相应参数的类型,因为这里父类是java.lang.Object,一切类都继承了java.lang.Object类,这就然后我们可以通过parameterTypeName调用任意类。

接着是对value的处理,这里value有值,于是调用_convertValueToParameterValue。

对parameterType进行类型判断,都不符合,于是进入else。

调用_convertType,跟到TypeConverterManagerBean.convertType。

会根据type去调用lookup函数寻找converter。

如果寻找不到,进入下面的else,都不符合的话,那么就会抛出错误,找不到该converter。

回到_convertType,进行catch,输入类型不为Map,继续返回。

在_convertValueToParameterValue中进行catch。

如果value是以{开头,就会进入下面的JSONFactoryUtil.looseDeserialize,传入parameterType和value。

jsonDeserializer.use函数会将我们的class赋值给rootType成员。

接着调用deserialize函数。

之后的内容就不深入分析了,大致列一下就行了。

类的实例化

类的实例化部分在jodd.json.JsonParserBase#newObjectInstance。

从deserialize开始的调用栈如下。

set方法调用

这里的setUserOverridesAsString方法是在我们传入的WrapperConnectionPoolDataSource方法的父类里进行调用的。 jodd.introspector.MethodDescriptor#invokeSetter

从deserialize开始的调用栈。

漏洞利用

出网回显

不出网回显

 

0x04 时间线

2020-03-20 漏洞细节被公开

2020-04-26 360-CERT 发布分析

 

0x05 参考链接

  1. Liferay Portal JSON Web Service RCE Vulnerabilities
分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多