【安全通报】Liferay Portal中的RCE漏洞
近期,白帽汇安全研究院观察到国外安全研究团队Code White公开了在Liferay Portal中发现的和JSON反序列化有关的高危漏洞,影响了6.1,6.2,,7.0,7.1,7.2版本。它可让未授权的攻击者通过JSON Web服务的API实现远程代码执行。
Liferay是一个开源的Portal产品,提供对多个独立系统的内容集成,为企业信息、流程等的整合提供了一套完整的解决方案,和其他商业产品相比,Liferay有着很多优良的特性,而且免费,在全球都有较多用户。
从FOFA的搜索结果来看,不少学校和政府网站都和其有关。
概况
根据目前FOFA系统最新数据(一年内数据),显示全球范围内共有44929个Liferay服务对外开放。美国使用数量最多,共有11045个,意大利第二,共有3481个,德国第三,共有3327个,西班牙第四,共有2866个,中国第五,共有2427个。
全球范围内分布情况如下(仅为分布情况,非漏洞影响情况)。
中国大陆地区浙江省使用数量最多,共有630个,北京市第二,共有462个,上海市第三,共有179个,广东省第四,共有164个,四川省第五,共有130个。
危害等级
高危
漏洞原理
Liferay Portal
提供了一个全面的JSON Web服务API,并提供了三种不同的调用Web服务方法的示例:
1.通过通用URL/api/jsonws/invoke
,其中服务方法及其参数通过POST作传输,一个JSON对象或基于表单的参数。
2.通过服务方法特定的URL,例如/api/jsonws/service-class-name/service-method-name
,其中参数传递是通过基于表单的POST数据包。
3.通过服务方法特定的URL,例如/api/jsonws/service-class-name/service-method-name
,其中参数也是通过URL的形式传递,例如/api/jsonws/service-class-name/service-method-name/arg1/val1/arg2/val2/…
。
身份验证和授权检查是在调用服务方法本身中实现的,而请求的处理和JSON反序列化则是在之前进行的。
1.CST-7111: 通过JSON反序列化实现RCE (LPS-88051/LPE-16598)
在Liferay Portal 6.1和6.2中,Flexjson库用于序列化和反序列化数据。它支持对象绑定,对任何带有无参数构造函数的类将使用被初始化对象的setter方法。类的规范是通过class
对象键:
{"class":"fully.qualified.ClassName", ... }
该漏洞于2018年12月被报告,已在企业版中被修复,包括6.1 EE GA3 fixpack 71和6.2 EE GA2 fixpack 1692和6.2 GA6。
2.CST-7205: 通过JSONWS实现远程代码执行 (LPS-97029/CVE-2020-7961)
在Liferay Portal 7中,Flexjson库被Jodd Json库取代,其不支持在JSON数据本身指定要反序列化的类。相反,只能指定根对象的类型,而且必须由java.lang.Class
对象实例显式提供。在查找对rootType
字段写访问的调用层次结构时,如下所示:
虽然大多数调用都指定了硬编码类型,但是有一个调用是可变的。通过调用层次结构向后跟踪parameter
类型变量,可以发现它来自一个ClassLoader.loadClass(String)
调用,该调用带有一个来自JSONWebServiceActionParameters
实例的参数值。该对象拥有在web服务调用中传递的参数。JSONWebServiceActionParameters
对象有一个JSONWebServiceActionParametersMap
实例,该实例有一个_parameterTypes
字段,用于将参数映射到类型。该映射用于在调用JSONWebServiceActionImpl._prepareParameters(Class<?>)
中的web服务方法的参数准备期间查找反序列化的类。
_parameterTypes
映射是通过JSONWebServiceActionParametersMap.put(String, object)
方法填充:
/* */ 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);
/* */ }
上述第102到110行:typeName
取自传入的key
字符串。因此,如果一个请求参数名包含一个':',它后面的部分指定参数的类型,即:
parameterName:fully.qualified.ClassName
在JSONWebServiceActionImpl._prepareParameters(Class<?>)
中,使用ReflectUtil.isTypeOf(Class, Class)
检查指定的类型是否扩展了要调用的方法的相应参数的类型。因为存在使用java.lang.object
参数的服务方法,所以可以指定任何类型。
该漏洞于2019年6月报告,在6.2 GA6、7.0 GA7、7.1 GA4、和7.2 GA2版本中被修复。
CVE-2020-7961利用截图如下:
外网也有研究人员复现成功:https://twitter.com/chybeta/status/1242133506974560256
本地复现情况如下:
漏洞影响
Liferay Portal
6.1、6.2、7.0、7.1、7.2
对应的修复版本是:
6.2 GA6、7.0 GA7、7.1 GA4和7.2 GA2
漏洞编号
CVE-2020-7961
修复建议
目前官方已发布了安全补丁,可到https://liferay.dev/blogs/-/blogs/security-patches-for-liferay-portal-6-2-7-0-and-7-1
进行相应版本的下载。
参考
[1] https://github.com/liferay/liferay-portal
[2] https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html
[3] https://blog.csdn.net/lushuaiyin/article/details/7023920
白帽汇从事信息安全,专注于安全大数据、企业威胁情报。
公司产品:FOFA-网络空间安全搜索引擎、FOEYE-网络空间检索系统、NOSEC-安全讯息平台。
为您提供:网络空间测绘、企业资产收集、企业威胁情报、应急响应服务。
最新评论