buuctf-shrine之SSTI

拖了好几天,还是把wp写下来吧

首先打开靶场,我们会发现,直接把源码就给你了

我们查看源代码会更舒服点,贴到这里:

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/<path: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)

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

这一句,我们可以发现,FLAG是在config中,那我们是不是可以直接访问{{config}},先不看这个,我们接着往下看

主页路由就是读出这个文件的代码。没有我们可以控制的地方,所以继续往下看

我们发现路由注册/shrine/<path:shrine>  # path可控

然后有一个视图函数,在视图函数还声明了safe_jinja()的函数,需要接受一个参数s,返回一个字符串

大概就是,如果你传入config,或者是self.config的时候,都会将其置为None.自然我们读不到config配置下的flag值。

这就验证了上一个我们无法用{{config}}去找flag

而且,我们还发现了flask.render_template_string()这个函数,SSTI肯定就在这里

好了了解代码之后,我们就开始实际注入了

 当作表达式执行了,于是我们开始去找payload,这里self,和config肯定不能用了,被过滤掉了

不过,python还有一些内置的函数,比如url_forget_flashed_messages

返回之前在Flask中通过 flash() 传入的闪现信息列表。

把字符串对象表示的消息加入到一个消息队列中,

然后通过调用 get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。

有了这些内置函数,我们再看看他们的globals列表

 我们发现了这个,那它是不是就是现在的app呢?于是我们payload,{{url_for.__globals__['current_app'].config}}

然后我们就拿到了flag

 flag{73e221d4-0d85-470f-9c97-e1dd9026de7d}

这是利用了python的一些内置的函数,然后进行它这个函数的绕过。然后就行访问。

/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

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

原文地址:https://www.cnblogs.com/junlebao/p/14287133.html