服务器端模板注入(SSTI)漏洞进阶与防护
字数 1290 2025-11-08 10:03:34
服务器端模板注入(SSTI)漏洞进阶与防护
1. 漏洞描述
服务器端模板注入(SSTI)是当应用将用户输入直接拼接到模板中,且未进行安全过滤或沙箱隔离时,攻击者可通过注入模板指令执行任意代码的漏洞。与普通SSTI相比,进阶场景涉及模板引擎的沙箱绕过、上下文感知攻击或高级语言特性滥用(如Python的类继承、Java的反射机制)。
2. 漏洞原理深入
- 模板引擎的工作机制:模板引擎(如Jinja2、Thymeleaf、Freemarker)将模板语法(如
{{ 2+2 }})解析为可执行代码,动态生成页面。 - 漏洞触发点:若用户输入(如URL参数、表单数据)直接嵌入模板,攻击者可插入恶意表达式(如
{{ config.items() }})窃取数据或调用危险函数。 - 进阶挑战:部分引擎默认启用沙箱(如Jinja2的沙箱模式),但攻击者可能通过以下方式绕过:
- 利用引擎内置方法(如Python的
__subclasses__)访问敏感类; - 通过字符编码或特殊语法混淆指令(如
${T(java.lang.Runtime).getRuntime().exec('id')})。
- 利用引擎内置方法(如Python的
3. 攻击步骤示例(以Jinja2为例)
步骤1:检测模板注入点
向参数提交纯表达式{{ 7*7 }},若页面返回"49",则存在漏洞。
步骤2:探索沙箱环境
- 查看内置对象:注入
{{ ''.__class__ }},返回字符串类的详细信息。 - 遍历类继承链:通过
{{ ''.__class__.__mro__[1].__subclasses__() }}获取所有子类列表。
步骤3:寻找可利用类
在子类列表中搜索危险类(如<class 'os._wrap_close'>),并通过索引定位(如第40号类)。
步骤4:执行命令
构造Payload调用os.system:
{{ ''.__class__.__mro__[1].__subclasses__()[40]('cat /etc/passwd').read() }}
4. 进阶绕过技巧
- 字符过滤绕过:若关键字被过滤,使用十六进制编码(如
\x5f代替下划线)或拼接字符串(如'__cla'+'ss__')。 - 沙箱逃逸:利用模板引擎的全局函数(如Jinja2的
cycler或lipsum)访问Python的__builtins__。 - 上下文感知攻击:在Thymeleaf中,结合Spring表达式(SpEL)注入
${T(java.lang.System).getenv()}。
5. 防护方案
- 输入校验:严格限制用户输入格式(如白名单正则匹配),禁止特殊字符(
{}$)。 - 模板内容分离:将动态数据与模板结构分离,使用上下文变量(如
template.render(user=input))而非直接拼接。 - 沙箱强化:启用模板引擎的沙箱模式,禁用危险方法(如Jinja2的
{% sandboxed %}标签)。 - 代码审查工具:使用Semgrep等工具检测代码中的模板拼接模式。
6. 总结
SSTI进阶攻击依赖对模板引擎底层机制的深入利用,防护需结合输入校验、沙箱隔离和安全开发实践,避免用户输入直接参与模板解析。