April 15, 2020

GHSL-2020-030: Server-Side Template Injection in Dropwizard

Alvaro Muñoz

Summary

A Server-Side Template Injection was identified in Dropwizard self-validating feature enabling attackers to inject arbitrary Java EL expressions, leading to Remote Code Execution (RCE) vulnerability.

CVE

  • CVE-2020-5245
  • CVE-2020-11002

Product

DropWizard

Tested Version

v2.0.1

Details

DropWizard self-validating classes use Java Bean Validation (JSR 380) custom constraint validators. When building custom constraint violation error messages, it is important to understand that they support different types of interpolation, including Java EL expressions. Therefore if an attacker can inject arbitrary data in the error message template being passed to ConstraintValidatorContext.buildConstraintViolationWithTemplate() argument, he will be able to run arbitrary Java code. Unfortunately, it is common that validated (and therefore, normally untrusted) bean properties flow into the custom error message.

DropWizard's io.dropwizard.validation.selfvalidating.ViolationCollector.addViolation() passes its argument into ConstraintValidatorContext.buildConstraintViolationWithTemplate() without any further sanitization. Therefore, any untrusted data being passed to addViolation() will be evaluated as an EL expression allowing arbitrary code execution.

Note that this is not a vulnerability in the framework per-se, but an RCE vulnerable API being exposed to developers without proper information. We don't think this is only a missing warning in the documentation, but rather we think that this API should protect developers against potential misuse (see recommendations to disable EL interpolation altogether below).

As a proof of concept you can reuse dropwizard-example project and modify Person.java to become self-validated:

...
import io.dropwizard.validation.selfvalidating.SelfValidating;
import io.dropwizard.validation.selfvalidating.SelfValidation;
import io.dropwizard.validation.selfvalidating.ViolationCollector;

@SelfValidating
public class Person {
...
    @SelfValidation
    public void validateFullName(ViolationCollector col) {
        if (fullName.contains("$")) {
            col.addViolation("Full name contains invalid characters:  " + fullName);
        }
    }
...

Note that a property of the validated, and therefore normally untrusted, bean is passed to addViolation() which in turn will pass it to ConstraintValidatorContext.buildConstraintViolationWithTemplate(0).

To reproduce the issue, send a POST request to http://server/people with the following body:

{"fullName":"java.lang.Runtime.getRuntime().exec('touch /tmp/pwned');//${''.class.forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval(validatedValue.fullName)}","jobTitle":"Title"}

We can see the process has been executed by checking the existence of /tmp/pwned file in conductor file system or simply by inspecting the response

Impact

This issue may lead to Remote Code execution

Remediation

There are different approaches to remediate the issue:

  • Do not include validated bean properties in the custom error message.
  • Sanitize the validated bean properties to make sure that there are no EL expressions. An example of valid sanitization logic can be found here.
  • Disable the EL interpolation and only use ParameterMessageInterpolator:
Validator validator = Validation.byDefaultProvider()
   .configure()
   .messageInterpolator( new ParameterMessageInterpolator() )
   .buildValidatorFactory()
   .getValidator();
  • Replace Hibernate-Validator with Apache BVal which in its latest version does not interpolate EL expressions by default. Note that this replacement may not be a simple drop-in replacement.

Coordinated Disclosure Timeline

  • 02/19/2020: Report sent to Vendor
  • 03/12/2020: Sent email to dropwizard.committers+security@gmail.com to ask for confirmation and acknowledge of the report
  • 02/24/2020: Advisory was published
  • 03/12/2020: Sent an email to Dropwizard letting them know the fix is insufficient due to hibernate implementation bug
  • 03/26/2020: New fix is ready for testing

Vendor Advisories

Credit

This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz). We would like to thank Guillaume Smet from the Hibernate Validator team for help with the remediation advice.

Contact

You can contact the GHSL team at securitylab@github.com, please include the GHSL-2020-030 in any communication regarding this issue.