题目
from flask import Flask, render_template, request
from flag import flag, FLAG
import datetime
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
f = open("app.py", "r")
ctx = f.read()
f.close()
f1ag = request.args.get('f1ag') or ""
exp = request.args.get('exp') or ""
flAg = FLAG(f1ag)
message = "Your flag is {0}" + exp
if exp == "":
return ctx
else:
return message.format(flAg)
if __name__ == "__main__":
app.run()
思路
关键代码分析:
-
flAg = FLAG(f1ag)
:用户提供的f1ag
参数被传入FLAG
函数处理,假设当参数不正确时返回一个对象实例。 -
message = "Your flag is {0}" + exp
:将用户输入的exp
拼接到字符串中,形成新的格式化字符串。 -
return message.format(flAg)
:使用flAg
作为参数进行格式化,若exp
包含格式化占位符,可触发二次格式化,访问对象属性。
Payload解析:
-
?f1ag=1&exp={0.__class__.__init__.__globals__}
-
f1ag=1
:传入错误参数使FLAG
函数返回一个对象实例(如错误对象)。 -
exp
构造为{0.__class__.__init__.__globals__}
,利用属性链访问:-
__class__
:获取flAg
对象的类。 -
__init__
:获取类的构造函数方法。 -
__globals__
:获取构造函数所在模块的全局变量字典,其中可能包含flag
变量。
-
漏洞利用过程:
-
拼接格式化字符串:
message
变为"Your flag is {0}{0.__class__.__init__.__globals__}"
。 -
格式化触发属性访问:
flAg
作为第一个参数替换{0}
,第二个占位符访问其属性链,最终获取到模块全局变量。 -
泄露全局变量:全局变量字典中包含
flag
或FLAG
,响应中返回该字典内容,暴露真实flag。
EXP
?f1ag=1&exp={0.__class__.__init__.__globals__}