目录

hibernate validate EL表达式注入漏洞

一、漏洞分析

官方给出的漏洞,版本1:https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator

/posts/hibernate-validate-el-injection/out-20240520131033260.png
imgs

未提有漏洞,实测存在漏洞,版本2(不做参考):

https://mvnrepository.com/artifact/org.hibernate/hibernate-validator

/posts/hibernate-validate-el-injection/out-20240520131048738.png
img

6.1.4及以下版本指向同一漏洞编号,CVE-2020-10693(EL表达式注入)

/posts/hibernate-validate-el-injection/out-20240520131347923.png
img

实际测试,使用无漏洞版本6.1.*最高版本(6.1.7)进行测试,依然能rce

/posts/hibernate-validate-el-injection/out-20240520131332305.png
img

debug跟踪,关键代码如下

/org/hibernate/validator/hibernate-validator/6.1.7.Final/hibernate-validator-6.1.7.Final.jar!/org/hibernate/validator/messageinterpolation/AbstractMessageInterpolator.class

分为三步:

  1. 从参数中拿出message
  2. 判断是否有{,解析要执行的参数
  3. 执行el表达式

/posts/hibernate-validate-el-injection/out-20240520131319381.png
img

/posts/hibernate-validate-el-injection/out-20240520131314638.png
img

以下是执行时过程代码,可忽略

/org/hibernate/validator/hibernate-validator/6.1.7.Final/hibernate-validator-6.1.7.Final.jar!/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.class

/posts/hibernate-validate-el-injection/out-20240520131301642.png
img

/org/hibernate/validator/hibernate-validator/6.1.7.Final/hibernate-validator-6.1.7.Final.jar!/org/hibernate/validator/internal/engine/messageinterpolation/InterpolationTerm.class

/posts/hibernate-validate-el-injection/out-20240520131253009.png
img

/org/hibernate/validator/hibernate-validator/6.1.7.Final/hibernate-validator-6.1.7.Final.jar!/org/hibernate/validator/internal/engine/messageinterpolation/ElTermResolver.class

/posts/hibernate-validate-el-injection/out-20240520131242148.png
img

结论:官方在6.1.7.Final中并未处理EL表达式拼接,也未在公告中说明这个版本存在问题(他说没漏洞实际有漏洞,作为特性个人认为官方不认漏洞,但在大版本6.2.0修复了缺陷)

二、未受影响版本

实际测试6.2.0.Final,一二步没有任何变化

/org/hibernate/validator/hibernate-validator/6.2.0.Final/hibernate-validator-6.2.0.Final.jar!/org/hibernate/validator/messageinterpolation/AbstractMessageInterpolator.class

/posts/hibernate-validate-el-injection/out-20240520131232131.png
img

第三步判断了EL表达式语言引擎启用的功能级别,NONE不执行EL表达式(默认为NONE)

/posts/hibernate-validate-el-injection/out-20240520131223251.png
img

Hibernate Validator 6.2.0.Final 开始提供了EL表达式几个功能级别,可以通过ExpressionLanguageFeatureLevel枚举:

  • NONE 表达式语言内插完全禁用。
  • VARIABLES 允许通过addExpressionVariable()的资源包和使用formatter对象。
  • BEAN_PROPERTIES 允许一切VARIABLES允许加上bean属性的插值。
  • BEAN_METHODS 还允许执行bean方法。

/org/hibernate/validator/hibernate-validator/6.2.0.Final/hibernate-validator-6.2.0.Final.jar!/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorContextImpl.class

/posts/hibernate-validate-el-injection/out-20240520131208941.png
img

三、官方修复方案

错误用法示例(关键代码14行):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class MonthValidatorProcess implements ConstraintValidator<MonthValidator, String> {
    public static final DateTimeFormatter YEAR_MONTH_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    @Override
    public boolean isValid(String yearMonth, ConstraintValidatorContext constraintValidatorContext) {
        if (StringUtils.isBlank(yearMonth)) {
            return false;
        }
        try {
            String yearMonthDay = yearMonth + "01";
            LocalDate.parse(yearMonthDay, YEAR_MONTH_DATE_FORMATTER);
            return true;
        } catch (Throwable e) {
            constraintValidatorContext.disableDefaultConstraintViolation();
            constraintValidatorContext.buildConstraintViolationWithTemplate(String.format("日期[%s]不合法", yearMonth)) // String字符串直接拼接到buildConstraintViolationWithTemplate
                    .addConstraintViolation();
            return false;
        }
    }
}

1、使用参数化的消息模板

正确用法示例(关键代码15行)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class MonthValidatorProcess implements ConstraintValidator<MonthValidator, String> {
    public static final DateTimeFormatter YEAR_MONTH_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    @Override
    public boolean isValid(String yearMonth, ConstraintValidatorContext constraintValidatorContext) {
        if (StringUtils.isBlank(yearMonth)) {
            return false;
        }
        try {
            String yearMonthDay = yearMonth + "01";
            LocalDate.parse(yearMonthDay, YEAR_MONTH_DATE_FORMATTER);
            return true;
        } catch (Throwable e) {
            HibernateConstraintValidatorContext hcontext = constraintValidatorContext.unwrap(HibernateConstraintValidatorContext.class);
            hcontext.disableDefaultConstraintViolation();
            hcontext.addExpressionVariable("validatedValue",yearMonth).buildConstraintViolationWithTemplate("日期${validatedValue}不合法") // 使用addExpressionVariable参数绑定
                    .addConstraintViolation();
            return false;
        }
    }
}

2、升级hibernate-validator版本

升级hibernate-validator大于等于6.2.0.final(官方在大于等于6.2.0.final中判断了EL表达式语言引擎启用的功能级别,默认级别不执行EL表达式)

注:7.0.0及以上版本存在较大变更,虽然不存在漏洞,但很多方法都变了,需要重新写hibernate