服务器端模板注入(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')})。

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的cyclerlipsum)访问Python的__builtins__
  • 上下文感知攻击:在Thymeleaf中,结合Spring表达式(SpEL)注入${T(java.lang.System).getenv()}

5. 防护方案

  • 输入校验:严格限制用户输入格式(如白名单正则匹配),禁止特殊字符({}$)。
  • 模板内容分离:将动态数据与模板结构分离,使用上下文变量(如template.render(user=input))而非直接拼接。
  • 沙箱强化:启用模板引擎的沙箱模式,禁用危险方法(如Jinja2的{% sandboxed %}标签)。
  • 代码审查工具:使用Semgrep等工具检测代码中的模板拼接模式。

6. 总结
SSTI进阶攻击依赖对模板引擎底层机制的深入利用,防护需结合输入校验、沙箱隔离和安全开发实践,避免用户输入直接参与模板解析。

服务器端模板注入(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')} )。 3. 攻击步骤示例(以Jinja2为例) 步骤1:检测模板注入点 向参数提交纯表达式 {{ 7*7 }} ,若页面返回"49",则存在漏洞。 步骤2:探索沙箱环境 查看内置对象:注入 {{ ''.__class__ }} ,返回字符串类的详细信息。 遍历类继承链:通过 {{ ''.__class__.__mro__[1].__subclasses__() }} 获取所有子类列表。 步骤3:寻找可利用类 在子类列表中搜索危险类(如 <class 'os._wrap_close'> ),并通过索引定位(如第40号类)。 步骤4:执行命令 构造Payload调用 os.system : 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进阶攻击依赖对模板引擎底层机制的深入利用,防护需结合输入校验、沙箱隔离和安全开发实践,避免用户输入直接参与模板解析。