March 25, 2020

GHSL-2020-027: Server-Side Template Injection in Netflix Conductor

Alvaro Muñoz

Summary

A Server-Side Template Injection was identified in Netflix Conductor enabling attackers to inject arbitrary Java EL expressions, leading to a pre-auth Remote Code Execution (RCE) vulnerability.

CVE

CVE-2020-9296

Product

Netflix Conductor

Tested Version

v2.25.1-alpha

Issues found

GHSL-2020-027 Details - Remote Code Execution - JavaEL Injection

It is possible to run arbitrary code on the server (with Conductor service account privileges) by injecting arbitrary Java Expression Language (EL) expressions.

Netflix Conductor uses Java Bean Validation (JSR 380) custom constraint validators such as com.netflix.conductor.common.constraints.TaskTimeoutConstraint.TaskTimeoutValidator 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, they 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.

class TaskTimeoutValidator implements ConstraintValidator<TaskTimeoutConstraint, TaskDef> {
    @Override
    public void initialize(TaskTimeoutConstraint constraintAnnotation) {
    }
    @Override
    public boolean isValid(TaskDef taskDef, ConstraintValidatorContext context) {
        context.disableDefaultConstraintViolation();
        boolean valid = true;
        if (taskDef.getTimeoutSeconds() > 0) {
            if (taskDef.getResponseTimeoutSeconds() > taskDef.getTimeoutSeconds()) {
                valid = false;
                String message = String.format("TaskDef: %s responseTimeoutSeconds: %d must be less than timeoutSeconds: %d",
                        taskDef.getName(), taskDef.getResponseTimeoutSeconds(), taskDef.getTimeoutSeconds());
                context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
            }
        }
        return valid;
    }
}

We found multiple paths flowing into ConstraintValidatorContext.buildConstraintViolationWithTemplate(0).

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.
  • Use parameterized messages instead of string concatenation. E.g.
HibernateConstraintValidatorContext context = constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class );
context.addMessageParameter( "foo", "bar" );
context.buildConstraintViolationWithTemplate( "My violation message contains a parameter {foo}").addConstraintViolation();
  • 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

This report was subject to the GHSL coordinated disclosure policy

  • 02/18/2020: Report sent to Vendor via BugCrowd
  • 02/19/2020: Vulnerability acknowledged
  • 02/19/2020: Sent new RCE payload
  • 02/19/2020: Netflix acknowledged issue as P2 on secondary target. Awards $1500

Supporting resources

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-YEAR-ID in any communication regarding this issue.