若依RuoYi481后台SSTI漏洞详解及复现
[TOC]
漏洞描述
若依(RuoYi)是一套基于Spring Boot + Shiro + Thymeleaf的快速开发平台,广泛应用于企业后台管理系统。在最新版本4.8.1中,存在一个严重的 Thymeleaf模板注入(SSTI)漏洞 。
该漏洞位于 CacheController.java 控制器的 /monitor/cache/getNames 接口, fragment 参数未对用户输入进行充分过滤。尽管新版增加了黑名单机制拦截危险操作,但攻击者可通过特定格式 __|$${...}|__::.x 绕过限制,实现任意代码执行。
通过此SSTI漏洞,攻击者可获取Shiro框架的RememberMe加密密钥,进而利用Shiro反序列化漏洞实现远程代码执行(RCE),完全控制受影响服务器。
漏洞原因及利用原理
根本原因:未受控的 fragment 参数直接传入模板解析器
这是漏洞的入口点。在 CacheController 的 getNames 方法中,存在如下关键代码:
1 | @GetMapping("/getNames") |
或者更直接的版本,可能调用了类似于 return fragment; 的表达式视图解析。
关键问题:
- 攻击者完全可控的
fragment参数,被直接拼接到视图路径(return语句)中,或直接作为视图名称返回。 - 在Spring MVC配置中,如果视图解析器配置为
ThymeleafViewResolver,并且当返回的字符串不包含显式的重定向或转发前缀(如redirect:或forward:)时,Spring会将其视为一个Thymeleaf模板文件名去解析。 - 但这里的
fragment参数并不是一个合法的模板文件路径,而是一段Thymeleaf表达式。
poc各部分的含义和作用
__| ... |__ - Thymeleaf预处理表达式
- 这是Thymeleaf的预处理表达式语法
__|表示开始一个预处理表达式块|__表示结束预处理表达式块- 在预处理表达式中,多个表达式可以用
|分隔
$${...} - Thymeleaf表达式
$${...}在Thymeleaf中是变量表达式- 在预处理上下文中,
$${expression}会被求值 - 注意:这里使用了两个
$符号,这是绕过黑名单的关键!
::.x - 片段选择器
::是Thymeleaf的片段选择器语法.x表示选择名为x的片段(实际不存在,但格式需要)
绕过技巧
- 双重
$符号绕过:$${而不是${- 黑名单可能只检查
${,而忽略了$${ - 但在Thymeleaf中,
$${expression}和${expression}在功能上通常是等效的
- 黑名单可能只检查
- 预处理表达式语法:
__|...|__- 黑名单可能没有检查这种复杂的预处理表达式语法
- Thymeleaf在处理时会先解析预处理表达式
- URL编码进一步混淆:
攻击者发送的实际请求可能经过URL编码
漏洞检测POC
1 | POST /monitor/cache/getNames HTTP/1.1 |
获取Shiro框架的RememberMe加密密钥
1 | fragment=__|$${#response.getWriter().print(@securityManager.getClass().forName('java.util.Base64').getMethod('getEncoder').invoke(null).encodeToString(@securityManager.rememberMeManager.cipherKey))}|__::.x |
fofa语法
1 | ((icon_hash="706913071" || icon_hash="-1231872293")) |
漏洞利用链分析
攻击流程:
发现SSTI漏洞 :通过
fragment参数注入Thymeleaf表达式绕过黑名单 :使用
__|$${...}|__::.x格式绕过关键字过滤获取Shiro密钥 :利用SSTI读取
securityManager.rememberMeManager.cipherKeyShiro反序列化 :使用获取的密钥构造RememberMe Cookie
实现RCE :通过Shiro反序列化链执行任意命令
漏洞修复建议
立即升级
升级至官方最新安全版本
关注官方GitHub发布的安全更新:https://gitee.com/y_project/RuoYi
评论







