服务端模板注入(SSTI)漏洞详解
字数 1166 2025-11-10 17:48:02

服务端模板注入(SSTI)漏洞详解

1. 漏洞描述

服务端模板注入(Server-Side Template Injection,SSTI)是一种发生在服务端模板引擎中的代码注入漏洞。攻击者通过向模板中插入恶意代码,使得服务端在渲染模板时执行任意命令,可能导致敏感信息泄露、服务器被控制等严重后果。

核心问题:模板引擎将用户输入直接拼接到模板中,且未对用户输入进行安全过滤或转义,导致用户输入被当作模板代码执行。


2. 模板引擎的工作原理

模板引擎用于将动态数据(如用户信息、文章内容)嵌入静态页面(如HTML)。例如,一个简单的模板语法可能如下:

<h1>Welcome, {{ username }}!</h1>

服务端会将 username 变量的值替换到模板中,生成最终的HTML。
危险场景:如果用户能控制模板内容(如直接输入 {{ 恶意代码 }}),模板引擎可能执行恶意逻辑。


3. SSTI 漏洞的产生条件

  1. 用户输入直接拼接至模板:例如通过URL参数、表单字段等将内容插入模板。
  2. 模板引擎未安全配置:未禁用危险函数或未对用户输入转义。
  3. 模板语法支持函数调用或逻辑执行:如Jinja2、Twig、Freemarker等引擎支持执行表达式或命令。

示例场景

  • 用户注册时,用户名被用于生成个性化页面:
    template = f"Hello, {user_input}!"  # 直接拼接用户输入
    
  • 若用户输入 {{ 7*7 }},模板引擎可能输出 Hello, 49!,表明表达式被执行。

4. 漏洞检测方法

步骤1:识别模板引擎类型

向参数提交特殊语法,观察响应是否执行:

  • Jinja2(Python):输入 {{ 7*7 }},检查是否返回 49
  • Twig(PHP):输入 {{ 7*7 }}{{ self }}
  • Freemarker(Java):输入 ${7*7}

步骤2:验证代码执行能力

尝试执行基本命令或访问内置对象:

  • 输入 {{ ''.__class__ }}(Jinja2)查看返回的类信息。
  • 输入 <% 7*7 %> 测试Java模板引擎(如Velocity)。

5. 漏洞利用步骤(以Jinja2为例)

步骤1:获取内置类对象

{{ ''.__class__ }}  
# 返回 <class 'str'>,说明可访问Python内置类。

步骤2:追溯至危险类(如os)

{{ ''.__class__.__mro__[1].__subclasses__() }}  
# 获取str类的所有子类,寻找可用的模块(如os、subprocess)。

步骤3:执行系统命令

找到包含 os 模块的子类(如 catch_warnings),利用其执行命令:

{{ ''.__class__.__mro__[1].__subclasses__()[40]('whoami', shell=True).communicate() }}  
# 调用subprocess.Popen执行whoami命令。

6. 防御措施

  1. 禁止用户输入直接控制模板内容:将用户输入作为数据传递,而非模板代码。
  2. 使用沙箱环境:限制模板引擎的访问权限(如禁用危险函数)。
  3. 转义用户输入:对用户输入进行HTML转义(但仅对部分攻击有效)。
  4. 白名单过滤:仅允许用户输入特定字符或格式。

7. 总结

SSTI漏洞的危害性高,因其允许直接执行服务端代码。防御关键在于严格分离数据与代码,确保用户输入始终作为数据处理,而非可执行的模板内容。

服务端模板注入(SSTI)漏洞详解 1. 漏洞描述 服务端模板注入(Server-Side Template Injection,SSTI)是一种发生在 服务端模板引擎 中的代码注入漏洞。攻击者通过向模板中插入恶意代码,使得服务端在渲染模板时执行任意命令,可能导致敏感信息泄露、服务器被控制等严重后果。 核心问题 :模板引擎将用户输入直接拼接到模板中,且未对用户输入进行安全过滤或转义,导致用户输入被当作模板代码执行。 2. 模板引擎的工作原理 模板引擎用于将动态数据(如用户信息、文章内容)嵌入静态页面(如HTML)。例如,一个简单的模板语法可能如下: 服务端会将 username 变量的值替换到模板中,生成最终的HTML。 危险场景 :如果用户能控制模板内容(如直接输入 {{ 恶意代码 }} ),模板引擎可能执行恶意逻辑。 3. SSTI 漏洞的产生条件 用户输入直接拼接至模板 :例如通过URL参数、表单字段等将内容插入模板。 模板引擎未安全配置 :未禁用危险函数或未对用户输入转义。 模板语法支持函数调用或逻辑执行 :如Jinja2、Twig、Freemarker等引擎支持执行表达式或命令。 示例场景 : 用户注册时,用户名被用于生成个性化页面: 若用户输入 {{ 7*7 }} ,模板引擎可能输出 Hello, 49! ,表明表达式被执行。 4. 漏洞检测方法 步骤1:识别模板引擎类型 向参数提交特殊语法,观察响应是否执行: Jinja2 (Python):输入 {{ 7*7 }} ,检查是否返回 49 。 Twig (PHP):输入 {{ 7*7 }} 或 {{ self }} 。 Freemarker (Java):输入 ${7*7} 。 步骤2:验证代码执行能力 尝试执行基本命令或访问内置对象: 输入 {{ ''.__class__ }} (Jinja2)查看返回的类信息。 输入 <% 7*7 %> 测试Java模板引擎(如Velocity)。 5. 漏洞利用步骤(以Jinja2为例) 步骤1:获取内置类对象 步骤2:追溯至危险类(如os) 步骤3:执行系统命令 找到包含 os 模块的子类(如 catch_warnings ),利用其执行命令: 6. 防御措施 禁止用户输入直接控制模板内容 :将用户输入作为数据传递,而非模板代码。 使用沙箱环境 :限制模板引擎的访问权限(如禁用危险函数)。 转义用户输入 :对用户输入进行HTML转义(但仅对部分攻击有效)。 白名单过滤 :仅允许用户输入特定字符或格式。 7. 总结 SSTI漏洞的危害性高,因其允许直接执行服务端代码。防御关键在于 严格分离数据与代码 ,确保用户输入始终作为数据处理,而非可执行的模板内容。