# Giới thiệu Server-Side Template Injection trong Java
## 1. SSTI là gì ?
- **Định nghĩa**: là một lỗi bảo mật xảy ra khi untrusted data được truyền trực tiếp vào template engine hoặc expression language mà không được sanitize.
- **Nguyên lý chung**:
```mermaid
graph LR
A[User Input] --> B[Template Engine]
B --> C[AST Construction]
C --> D[Code Execution]
- **Impact**: Có thể dẫn đến full system compromise nếu JVM chạy với quyền cao.
## 2. Template Engine phổ biến trong Java
### Spring Expression Language (SpEL)
**Context**: Spring Framework (Spring Boot), dùng trong `@Value`, XML configs.
**Syntax**: `#{expression}`, `T(class).method()`, `new Class()`.
**Ví dụ sử dụng an toàn**:
```java
@RestController
public class SafeController {
@GetMapping("/welcome")
public String welcome(@RequestParam String name) {
ExpressionParser parser = new SpelExpressionParser();
// Sử dụng SimpleEvaluationContext để giới hạn quyền
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Expression exp = parser.parseExpression("'Hello ' + #name");
return exp.getValue(context, name, String.class); // Safe
}
}
```
### Apache Velocity
**Context**: Render templates (emails, pages).
**Syntax**: `${object.method()}`, `#set`, `#if/#foreach`.
**Ví dụ sử dụng an toàn**:
```java
public class VelocitySafe {
public String renderWelcome(User user) {
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, true); // Bật strict mode
ve.init();
VelocityContext context = new VelocityContext();
context.put("user", user);
Template template = ve.getTemplate("templates/welcome.vm"); // Template cố định
StringWriter writer = new StringWriter();
template.merge(context, writer);
return writer.toString();
}
}
```
### FreeMarker
**Context**: HTML/email generation.
**Syntax**: ${expression}, ?new(), <#if>, <#list>.
**Ví dụ sử dụng an toàn**:
```java
public class FreeMarkerSafe {
public String renderWelcome(User user) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER); // Bật sandbox
Template template = cfg.getTemplate("welcome.ftl"); // Template cố định
Map<String, Object> data = new HashMap<>();
data.put("user", user);
StringWriter out = new StringWriter();
template.process(data, out);
return out.toString();
}
}
```
### Thymeleaf
**Context**: Spring Boot, hiện đại, HTML templates.
**Syntax**: `th:text="${expression}"`, `th:utext`, `#{...}`.
**Ví dụ sử dụng an toàn**:
```java
@Controller
public class ThymeleafSafeController {
@GetMapping("/profile")
public String profile(@RequestParam String tab, Model model) {
// Chỉ cho phép giá trị tab trong whitelist
if(!Arrays.asList("info", "settings").contains(tab)) {
throw new IllegalArgumentException("Invalid tab");
}
model.addAttribute("user", userService.getCurrentUser());
return "profile/" + tab; // Template cố định
}
}
```
## 3. Detection & Exploit
### Payload đơn giản detect để detect engine
| Engine | Payload Detect | Kết quả dương tính |
|------------|-------------------------|-------------------|
| **SpEL** | `#{7*7}` | Trả về 49 |
| **Velocity** | `#set($x=7*7)${x}` | Trả về 49 |
| **FreeMarker** | `${7*7}` | Trả về 49 |
| **Thymeleaf** | `[[${7*7}]]` | Trả về 49 |
| **JSP EL** | `${1+2}` | Trả về 3 |
### Spring Expression Language (SpEL) - Vulnerable Code
```java
@RestController
public class VulnerableController {
@GetMapping("/spel")
public String spel(@RequestParam String input) {
ExpressionParser parser = new SpelExpressionParser();
// VULNERABLE: Sử dụng StandardEvaluationContext
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("input", input);
// VULNERABLE: Cho phép user kiểm soát biểu thức
Expression exp = parser.parseExpression(input);
return exp.getValue(context, String.class);
}
// VULNERABLE: Sử dụng trong @Value với input không kiểm soát
@Value("#{${customExpression}}")
private String dynamicValue;
}
```
**Payload RCE**: `T(java.lang.Runtime).getRuntime().exec('calc')`
### Apache Velocity - Vulnerable Code
```java
public class VelocityVulnerable {
public String render(String userTemplate) {
VelocityEngine ve = new VelocityEngine();
ve.init();
VelocityContext context = new VelocityContext();
// VULNERABLE: Cho phép user kiểm soát toàn bộ template
StringWriter writer = new StringWriter();
ve.evaluate(context, writer, "log", userTemplate);
return writer.toString();
}
}
```
**Payload RCE**: `#set($str=$class.inspect("java.lang.String").type) #set($chr=$class.inspect("java.lang.Character").type) #set($ex=$str.valueOf($chr.toChars(33)))${$class.inspect("java.lang.Runtime").type.getRuntime().exec('calc')}`
### FreeMarker - Vulnerable Code
```java
public class FreeMarkerVulnerable {
public String render(String templateName, Map<String, Object> data) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
// VULNERABLE: Cho phép user kiểm soát tên template
Template template = cfg.getTemplate(templateName);
// VULNERABLE: Cho phép user truyền object nguy hiểm
StringWriter out = new StringWriter();
template.process(data, out);
return out.toString();
}
}
```
**Payload RCE**: `/../(../)*/exploit.ftl` với nội dung exploit.ftl: `<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("calc") }`
### Thymeleaf - Vulnerable Code
```java
@Controller
public class ThymeleafVulnerableController {
@GetMapping("/render")
public String render(@RequestParam String templateContent, Model model) {
// VULNERABLE: Render template từ input người dùng
model.addAttribute("template", templateContent);
return "dynamic-template";
}
}
```
**Payload RCE**: `__${T(java.lang.Runtime).getRuntime().exec('calc')}__::.x`
## 4. Mitigation
### Biện pháp chung
- **Không bao giờ** để user kiểm soát template hoặc biểu thức
- Sử dụng template cố định với dữ liệu đầu vào đã validate
- Áp dụng nguyên tắc least privilege cho JVM
### Mitigation theo engine
**SpEL**:
```java
// LUÔN dùng SimpleEvaluationContext cho untrusted input
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// Vô hiệu hóa SpEL trong @Value
@Configuration
public class SpelConfig implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
((AbstractBeanFactory) beanFactory).setBeanExpressionResolver(null);
}
}
```
**Velocity**:
```java
// Bật strict mode và disable risky settings
ve.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, true);
ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, null);
ve.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, null);
```
**FreeMarker**:
```java
// Kích hoạt sandbox mạnh mẽ
cfg.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
// Vô hiệu hóa ?new
cfg.setAPIBuiltinEnabled(false);
```
**Thymeleaf**:
```java
// Tắt pre-processing
spring.thymeleaf.mode=HTML
// Trong code Java
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(false);
return engine;
}
```
**JSP/JSTL**:
```jsp
<!-- Vô hiệu hóa EL -->
<%@ page isELIgnored="true" %>
<!-- Hoặc dùng JSTL escape -->
<c:out value="${param.input}" />
```
### Cấu hình hệ thống
```properties
# Spring Boot: Tắt SpEL trong @Value
spring.spel.ignore=true
# Giới hạn quyền JVM
-Djava.security.manager
-Djava.security.policy==/path/to/security.policy
```
## 5. Reference
1. [OWASP: Server-Side Template Injection](https://owasp.org/www-community/attacks/Server-Side_Template_Injection)
2. [Spring Security: SpEL Evaluation Context](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/expression/spel/support/SimpleEvaluationContext.html)
3. [FreeMarker Security Practices](https://freemarker.apache.org/docs/pgui_config_security.html)
4. [Thymeleaf Template Injection](https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/)
5. [Java SSTI Cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#java)
6. [CVE-2016-4977: Spring Security OAuth RCE](https://tanzu.vmware.com/security/cve-2016-4977)
7. [Secure Coding Guidelines for Java](https://www.oracle.com/java/technologies/javase/seccodeguide.html)
8. [Spring Framework RCE via Data Binding (CVE-2022-22965)](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement)