代码审计 | RuoYi4.6.2Thymeleaf模板注入详解
字数 1213 2025-08-20 18:17:07
Thymeleaf模板注入漏洞分析与利用 - RuoYi 4.6.2版本审计
1. 漏洞概述
本文详细分析RuoYi管理系统v4.6.2版本中存在的Thymeleaf模板注入(SSTI)漏洞。该漏洞源于系统在处理用户输入时未进行充分过滤,导致攻击者可以通过构造恶意输入实现服务器端模板注入,进而可能导致远程代码执行(RCE)。
2. 环境搭建
参考RuoYi v4.6.0版本的搭建方法:
- 下载RuoYi v4.6.2版本源码
- 配置Java环境和数据库
- 部署系统并确保正常运行
3. 漏洞利用
3.1 利用步骤
- 定位注入点:CacheController.java文件中的相关方法
- 构造恶意请求:
POST /path/to/vulnerable/endpoint ... fragment=恶意payload - 发送请求并观察响应
3.2 利用Payload示例
Thymeleaf 2.0版本的典型利用payload:
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("whoami").getInputStream()).next()}__::
4. 漏洞分析
4.1 漏洞触发流程
-
入口点:CacheController.java第39行
return "模板名称::" + fragment; // fragment参数可控且未过滤 -
请求处理流程:
invokeForRequest()方法处理用户请求invokeAndHandle()方法调用相关controller- 将返回值作为模板文件名传递给Thymeleaf引擎
-
模板解析过程:
processDispatchResult()方法处理结果- Thymeleaf引擎解析视图名称
- 包含用户输入的fragment参数被当作模板表达式解析
4.2 关键代码分析
// 在renderFragment方法中
IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
FragmentExpression fragmentExpression = (FragmentExpression)parser.parseExpression(context, viewTemplateName + "}");
这段代码将用户控制的viewTemplateName(包含fragment参数)作为Thymeleaf表达式解析,导致SSTI漏洞。
5. 漏洞原理
漏洞形成原因:
- 用户输入(fragment参数)直接拼接到模板名称中
- 未对用户输入进行任何过滤或转义
- 系统使用Thymeleaf 2.0版本,存在表达式注入风险
- 返回的视图名称被Thymeleaf引擎当作表达式解析
6. 修复方案
6.1 官方修复
RuoYi在4.7.2版本中通过升级Thymeleaf版本修复此漏洞。
6.2 其他修复建议
-
输入过滤:
// 对fragment参数进行严格过滤 if(fragment.contains("${") || fragment.contains("__")) { throw new IllegalArgumentException("Invalid input"); } -
使用最新版本:
- 升级到Thymeleaf 3.0.15+版本
- 注意:Thymeleaf 3.0.12和3.0.14版本也存在绕过方式
-
安全编码实践:
- 避免将用户输入直接作为模板名称
- 使用白名单验证用户输入
7. 相关资源
8. 总结
RuoYi v4.6.2版本的Thymeleaf模板注入漏洞展示了SSTI的典型利用场景。通过分析此漏洞,我们可以学习到:
- 模板引擎使用不当可能导致严重安全问题
- 用户输入必须经过严格验证和过滤
- 保持依赖库更新是安全开发的重要环节
- 理解框架内部处理流程对漏洞分析至关重要
安全建议:在使用任何模板引擎时,都应避免将用户输入直接作为模板或模板名称,并确保使用最新版本以获得安全修复。