CodeQL Study 之 RuoYi-4.7.8 漏洞分析
字数 1637 2025-08-22 22:47:39

CodeQL 分析 RuoYi-4.7.8 漏洞研究

1. 背景介绍

RuoYi 是一个基于 Spring Boot 和 Apache Shiro 的权限管理系统,4.7.8 版本中存在一些安全漏洞。本文使用 CodeQL 对这些漏洞进行分析。

2. 漏洞分析环境搭建

2.1 创建 CodeQL 数据库

codeql database create ruoyi-database --language=java --command='mvn clean package -f "pom.xml"'

注意:路径不能包含中文

3. 定时任务功能分析

3.1 调用方式

后台定时任务支持两种调用方式:

  1. Bean 调用:需要添加对应 Bean 注解 @Component@Service
  2. Class 类调用:添加类和方法指定包即可,调用目标字符串

3.2 安全限制

黑名单限制

com.ruoyi.quartz.controller.SysJobController#addSave 中定义:

public static final String LOOKUP_RMI = "rmi:";
public static final String LOOKUP_LDAP = "ldap:";
public static final String LOOKUP_LDAPS = "ldaps:";
public static final String HTTP = "http://";
public static final String HTTPS = "https://";

public static final String[] JOB_ERROR_STR = {
    "java.net.URL",
    "javax.naming.InitialContext",
    "org.yaml.snakeyaml",
    "org.springframework",
    "org.apache",
    "com.ruoyi.common.utils.file",
    "com.ruoyi.common.config"
};

白名单限制

public static final String[] JOB_WHITELIST_STR = {
    "com.ruoyi"
};

3.3 定时任务执行逻辑

位于 com.ruoyi.quartz.util.JobInvokeUtil#invokeMethod

  1. 获取 beanName、methodName、methodParams 等值
  2. 反射调用方法

关键限制条件:

  • 若是 Spring 容器中注册过的 bean,可直接从容器中取出
  • 若是指定 class 名称,会通过反射 newInstance() 创建对象,因此必须保证 class 中存在无参构造函数
  • 方法必须是 public 修饰的方法
  • 方法参数类型只能为 String、Boolean、Long、Double、Integer

4. CodeQL 查询分析

4.1 查询语句

import java

from Method m
where 
    m.getDeclaringType().getAConstructor().hasNoParameters() and
    m.isPublic() and
    m.getAParamType() instanceof TypeString and
    m.getDeclaringType().getPackage().getName().matches("com.ruoyi%") and
    not m.isAbstract() and
    not m.getDeclaringType().getPackage().getName().matches("com.ruoyi.common.config%") and
    not m.getDeclaringType().getPackage().getName().matches("com.ruoyi.common.utils.file%") and
    not m.getName().matches("get%") and
    not m.getName().matches("is%") and
    not m.getName().matches("has%")
select m.getDeclaringType().getPackage().getName(), m.getDeclaringType(), m

4.2 查询结果分析

4.2.1 SSRF 漏洞

com.ruoyi.common.utils.http.HttpUtils#sendGet 是一个无回显的 SSRF:

  • 可以使用 file、ftp、jar 等协议
  • 由于禁用了 http 和 https,利用价值有限

示例利用:

com.ruoyi.common.utils.http.HttpUtils.sendGet("ftp://d8lmq0s1.dnslog.pw")

4.2.2 SQL 注入漏洞

com.ruoyi.generator.service.impl.GenTableServiceImpl#createTable

  • 跟进到文件 GenTableMapper.xml
  • MyBatis 支持两种参数符号:
    • #:使用预编译向占位符中设置值,可有效防止 SQL 注入
    • $:拼接 SQL,是触发 SQL 注入的关键

利用方式:

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a61... WHERE job_id = 1;')

这样可以绕过新建任务的限制,直接修改数据库中的内容。

5. RCE 利用分析

5.1 黑名单类分析

黑名单中禁止的类和方法:

  1. javax.naming.InitialContext#lookup
  2. org.yaml.snakeyaml.Yaml#load
  3. org.springframework.jndi.JndiLocatorDelegate#lookup
  4. org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup#getDataSource
  5. org.apache.velocity.runtime.RuntimeInstance#init

5.2 可利用的攻击方式

  1. SnakeYAML 反序列化:虽然 org.yaml.snakeyaml 在黑名单中,但可能有绕过方式
  2. JNDI 注入:通过其他方式触发 JNDI 查找,结合反序列化

6. 防御建议

  1. 加强黑名单过滤,考虑使用更严格的正则表达式
  2. 对 SQL 操作强制使用预编译参数
  3. 限制反射调用的范围
  4. 对定时任务的目标方法进行更严格的权限控制
  5. 定期更新依赖库,修复已知漏洞

7. 总结

通过 CodeQL 分析,我们发现了 RuoYi 4.7.8 版本中存在的多个安全问题,包括 SSRF、SQL 注入和潜在的 RCE 漏洞。这些漏洞主要源于不安全的反射调用、不充分的输入过滤和 SQL 拼接等问题。开发者应当重视这些安全问题,采取相应的防护措施。

CodeQL 分析 RuoYi-4.7.8 漏洞研究 1. 背景介绍 RuoYi 是一个基于 Spring Boot 和 Apache Shiro 的权限管理系统,4.7.8 版本中存在一些安全漏洞。本文使用 CodeQL 对这些漏洞进行分析。 2. 漏洞分析环境搭建 2.1 创建 CodeQL 数据库 注意:路径不能包含中文 3. 定时任务功能分析 3.1 调用方式 后台定时任务支持两种调用方式: Bean 调用 :需要添加对应 Bean 注解 @Component 或 @Service Class 类调用 :添加类和方法指定包即可,调用目标字符串 3.2 安全限制 黑名单限制 在 com.ruoyi.quartz.controller.SysJobController#addSave 中定义: 白名单限制 3.3 定时任务执行逻辑 位于 com.ruoyi.quartz.util.JobInvokeUtil#invokeMethod : 获取 beanName、methodName、methodParams 等值 反射调用方法 关键限制条件: 若是 Spring 容器中注册过的 bean,可直接从容器中取出 若是指定 class 名称,会通过反射 newInstance() 创建对象,因此必须保证 class 中存在无参构造函数 方法必须是 public 修饰的方法 方法参数类型只能为 String、Boolean、Long、Double、Integer 4. CodeQL 查询分析 4.1 查询语句 4.2 查询结果分析 4.2.1 SSRF 漏洞 com.ruoyi.common.utils.http.HttpUtils#sendGet 是一个无回显的 SSRF: 可以使用 file、ftp、jar 等协议 由于禁用了 http 和 https,利用价值有限 示例利用: 4.2.2 SQL 注入漏洞 com.ruoyi.generator.service.impl.GenTableServiceImpl#createTable : 跟进到文件 GenTableMapper.xml MyBatis 支持两种参数符号: # :使用预编译向占位符中设置值,可有效防止 SQL 注入 $ :拼接 SQL,是触发 SQL 注入的关键 利用方式: 这样可以绕过新建任务的限制,直接修改数据库中的内容。 5. RCE 利用分析 5.1 黑名单类分析 黑名单中禁止的类和方法: javax.naming.InitialContext#lookup org.yaml.snakeyaml.Yaml#load org.springframework.jndi.JndiLocatorDelegate#lookup org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup#getDataSource org.apache.velocity.runtime.RuntimeInstance#init 5.2 可利用的攻击方式 SnakeYAML 反序列化 :虽然 org.yaml.snakeyaml 在黑名单中,但可能有绕过方式 JNDI 注入 :通过其他方式触发 JNDI 查找,结合反序列化 6. 防御建议 加强黑名单过滤,考虑使用更严格的正则表达式 对 SQL 操作强制使用预编译参数 限制反射调用的范围 对定时任务的目标方法进行更严格的权限控制 定期更新依赖库,修复已知漏洞 7. 总结 通过 CodeQL 分析,我们发现了 RuoYi 4.7.8 版本中存在的多个安全问题,包括 SSRF、SQL 注入和潜在的 RCE 漏洞。这些漏洞主要源于不安全的反射调用、不充分的输入过滤和 SQL 拼接等问题。开发者应当重视这些安全问题,采取相应的防护措施。