服务端模板注入(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 漏洞的产生条件
- 用户输入直接拼接至模板:例如通过URL参数、表单字段等将内容插入模板。
- 模板引擎未安全配置:未禁用危险函数或未对用户输入转义。
- 模板语法支持函数调用或逻辑执行:如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. 防御措施
- 禁止用户输入直接控制模板内容:将用户输入作为数据传递,而非模板代码。
- 使用沙箱环境:限制模板引擎的访问权限(如禁用危险函数)。
- 转义用户输入:对用户输入进行HTML转义(但仅对部分攻击有效)。
- 白名单过滤:仅允许用户输入特定字符或格式。
7. 总结
SSTI漏洞的危害性高,因其允许直接执行服务端代码。防御关键在于严格分离数据与代码,确保用户输入始终作为数据处理,而非可执行的模板内容。