绕过限制:若依模板注入在高版本 Thymeleaf 中的绕过分析
字数 1717 2025-08-30 06:50:35
若依CMS高版本Thymeleaf模板注入绕过分析
前言
本文详细分析若依CMS系统中存在的Thymeleaf模板注入漏洞及其在高版本中的绕过技术。该漏洞允许攻击者在特定条件下执行任意代码,危害性极高。
技术背景
若依CMS简介
若依CMS是一款基于Java开发的开源内容管理系统,主要特点包括:
- 开源免费
- 模块化设计
- 用户友好的界面
- 强大的文章管理功能
- 完善的权限管理
- SEO友好
- 活跃的社区支持
Thymeleaf模板引擎
Thymeleaf是Java生态中广泛使用的模板引擎,主要特性:
- 自然模板:直接使用标准HTML
- 表达式语言(OGNL)
- 支持多种视图解析(HTML/XML/JS/CSS)
- 丰富的标签和属性
- 与Spring框架深度集成
- 国际化支持
漏洞原理分析
漏洞触发流程
-
Handler封装ModelAndView对象
- 请求经过
DispatcherServlet#doDispatch方法 - 调用
invokeHandlerMethod方法初始化ModelAndViewContainer - 通过反射为
returnValue赋值 - 设置
viewName值
- 请求经过
-
处理ModelAndView对象获取view
processDispatchResult方法处理返回结果render方法准备渲染视图resolveViewName解析视图名称
-
渲染view
ThymeleafView#render方法完成实际渲染- 通过
renderFragment处理模板片段 - 当
TemplateName不包含::时,直接使用viewTemplateName - 包含
::时解析为templateName和markupSelectors
关键注入点
漏洞核心在于Thymeleaf对SpEL表达式的处理:
- 输入被
preprocess方法预处理 - 符合正则匹配的表达式被提取
StandardExpressionParser.parseExpression解析表达式expression.execute执行表达式
测试过程
漏洞特征
- 返回值或路径可控的路由
- 参数型注入点(如
String类型参数)
限制条件
- Thymeleaf 3.0.12及以上版本
- 默认payload无法直接使用
绕过技术分析
版本差异
高版本Thymeleaf新增了两个关键防护机制:
-
checkViewNameNotInRequest
- 新版本会将输入转为小写
- 检查
requestURI.contains(vn) - 若匹配则抛出异常
-
containsSpELInstantiationOrStatic
- 防止使用
T字符实例化对象 - 检测以下模式:
- 对象实例化(如
new SomeClass) - 静态方法调用(如
T(SomeClass))
- 对象实例化(如
- 防止使用
绕过checkViewNameNotInRequest
利用viewName和request.getRequestURI()解析差异:
-
双斜杠绕过
- 原始payload:
/doc/__${payload}__::.x - 绕过payload:
doc//__${payload}__::.x - 原理:标准化处理会删除一个
/,导致requestURI不匹配
- 原始payload:
-
分号绕过
- payload:
doc;/__${payload}__::.x - 原理:
getCachedPathValue处理URL时的差异
- payload:
绕过containsSpELInstantiationOrStatic
-
添加空格
- 在表达式关键部分添加不影响执行的空格
- 如:
T (java.lang.Runtime)而非T(java.lang.Runtime)
-
其他干扰字符
- 可尝试添加不影响表达式执行的字符
最终利用
结合两种绕过技术,构造有效payload:
doc//__${T (java.lang.Runtime).getRuntime().exec("calc")}__::.x
或:
doc;/__${T (java.lang.Runtime).getRuntime().exec("calc")}__::.x
防御建议
- 升级到最新Thymeleaf版本
- 对用户输入进行严格过滤
- 禁用不必要的SpEL表达式功能
- 实施严格的输入验证机制
参考
- Thymeleaf Spring Issue #256
- 若依CMS官方文档
- Thymeleaf官方安全公告