thymeleaf模板注入学习与研究--查找与防御
字数 918 2025-08-12 11:34:43

Thymeleaf模板注入漏洞研究与防御指南

一、漏洞概述

Thymeleaf模板注入是一种服务器端模板注入(SSTI)漏洞,当攻击者能够控制模板名称或部分模板内容时,可以执行任意Java代码,导致远程代码执行(RCE)。

二、常见漏洞场景

2.1 模板参数外部可控

@RequestMapping("/path")
public String path(@RequestParam String lang) {
    return lang;
}

漏洞分析

  • 直接返回用户输入的参数作为模板名称
  • 常见于主题切换、语言切换等功能

2.2 使用@GetMapping注解且无返回值

@GetMapping("/doc/{document}")
public void getDocument(@PathVariable String document) {
    logger.info("Retrieving " + document);
}

漏洞分析

  • 根据Spring Boot定义,无返回值时以路由路径作为视图名称
  • 请求URL会被直接作为模板名称解析

三、Payload构造方法

3.1 基本Payload结构

__${恶意表达式}__::.x

3.2 实际攻击示例

URL编码后的Payload

__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x

对应原始表达式

__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::.x

3.3 不同场景下的Payload变体

  1. 路径拼接场景

    • 必须以::.x结尾
    • 示例请求:/doc/__${payload}__::.x
  2. 片段表达式场景

    • 可以省略::.x
    • 示例请求:/fragment?section=__${payload}__

四、漏洞检测方法

4.1 黑盒测试

  1. 寻找主题切换、背景更改等功能点
  2. 将参数替换为测试Payload
  3. 观察系统响应或执行结果

4.2 白盒审计

4.2.1 模板参数外部可控审计

  1. 收集所有模板文件名称
  2. 搜索控制器返回语句:
    return.*?\".*?模板名称
    
  3. 检查:
    • 返回参数是否外部可控
    • 是否不含HttpServlet相关对象
    • 是否没有重定向(redirect)

4.2.2 无返回值GetMapping审计

使用正则搜索:

@GetMapping$.*?$\s*public\s+void

五、漏洞修复方案

5.1 推荐修复方案(白名单方式)

@RequestMapping("/safepath")
public String path(@RequestParam int lang) {
    int num = request.getParameter("lang");
    HashMap<Integer, String> tems = new HashMap<Integer, String>();
    tems.put(1, "red template");
    tems.put(2, "yellow template");
    tems.put(3, "green template");
    return tems.get(num);
}

5.2 其他修复方案

  1. 使用@ResponseBody或@RestController

    @RestController
    public class SafeController {
        // 不再调用模板解析
    }
    
  2. 使用redirect或forward前缀

    @GetMapping("/safe/redirect")
    public String redirect(@RequestParam String url) {
        return "redirect:" + url;
    }
    
  3. 添加HttpServletResponse参数

    @GetMapping("/safe/doc/{document}")
    public void getDocument(@PathVariable String document, HttpServletResponse response) {
        log.info("Retrieving " + document);
    }
    

六、防御要点总结

  1. 避免直接使用用户输入作为模板名称
  2. 对必须使用外部输入的模板名称实施白名单验证
  3. 在不需要模板渲染的场景使用@ResponseBody
  4. 对高风险功能进行代码审查
  5. 保持Thymeleaf和Spring Boot版本更新

七、参考代码示例

7.1 漏洞代码示例

@Controller
public class VulnerableController {
    
    // 场景1:直接返回用户输入
    @RequestMapping("/vuln1")
    public String vuln1(@RequestParam String template) {
        return template;
    }
    
    // 场景2:无返回值GetMapping
    @GetMapping("/vuln2/{param}")
    public void vuln2(@PathVariable String param) {
        logger.info("Parameter: " + param);
    }
    
    // 场景3:片段表达式注入
    @GetMapping("/vuln3")
    public String vuln3(@RequestParam String section) {
        return "welcome :: " + section;
    }
}

7.2 安全代码示例

@Controller
public class SafeController {
    
    // 安全方式1:白名单
    @RequestMapping("/safe1")
    public String safe1(@RequestParam int templateId) {
        Map<Integer, String> templates = Map.of(
            1, "template1",
            2, "template2"
        );
        return templates.getOrDefault(templateId, "default");
    }
    
    // 安全方式2:使用@ResponseBody
    @GetMapping("/safe2")
    @ResponseBody
    public String safe2() {
        return "This will not be processed as template";
    }
    
    // 安全方式3:强制重定向
    @GetMapping("/safe3")
    public String safe3() {
        return "redirect:/safe-page";
    }
}
Thymeleaf模板注入漏洞研究与防御指南 一、漏洞概述 Thymeleaf模板注入是一种服务器端模板注入(SSTI)漏洞,当攻击者能够控制模板名称或部分模板内容时,可以执行任意Java代码,导致远程代码执行(RCE)。 二、常见漏洞场景 2.1 模板参数外部可控 漏洞分析 : 直接返回用户输入的参数作为模板名称 常见于主题切换、语言切换等功能 2.2 使用@GetMapping注解且无返回值 漏洞分析 : 根据Spring Boot定义,无返回值时以路由路径作为视图名称 请求URL会被直接作为模板名称解析 三、Payload构造方法 3.1 基本Payload结构 3.2 实际攻击示例 URL编码后的Payload : 对应原始表达式 : 3.3 不同场景下的Payload变体 路径拼接场景 : 必须以 ::.x 结尾 示例请求: /doc/__${payload}__::.x 片段表达式场景 : 可以省略 ::.x 示例请求: /fragment?section=__${payload}__ 四、漏洞检测方法 4.1 黑盒测试 寻找主题切换、背景更改等功能点 将参数替换为测试Payload 观察系统响应或执行结果 4.2 白盒审计 4.2.1 模板参数外部可控审计 收集所有模板文件名称 搜索控制器返回语句: 检查: 返回参数是否外部可控 是否不含HttpServlet相关对象 是否没有重定向(redirect) 4.2.2 无返回值GetMapping审计 使用正则搜索: 五、漏洞修复方案 5.1 推荐修复方案(白名单方式) 5.2 其他修复方案 使用@ResponseBody或@RestController : 使用redirect或forward前缀 : 添加HttpServletResponse参数 : 六、防御要点总结 避免直接使用用户输入作为模板名称 对必须使用外部输入的模板名称实施白名单验证 在不需要模板渲染的场景使用@ResponseBody 对高风险功能进行代码审查 保持Thymeleaf和Spring Boot版本更新 七、参考代码示例 7.1 漏洞代码示例 7.2 安全代码示例