[NISACTF 2022]babyupload
[NISACTF 2022]babyupload
题目来源:nssctf
题目类型:web
涉及考点:文件上传
1. 题目说传一个图片文件,那我们传个muma.jpg看看
![](https://images.cnblogs.com/cnblogs_com/blogs/729425/galleries/2331778/o_230811151134_image-20230811224740279.png)
但是上传失败:
- 回去检查一下源代码,发现有
/source
![](https://images.cnblogs.com/cnblogs_com/blogs/729425/galleries/2331778/o_230811151134_image-20230811224938030.png)
直接访问下载了一个压缩文件,解压之后是一个py文件,随后进行代码审计
2. 代码审计
from flask import Flask, request, redirect, g, send_from_directory
import sqlite3
import os
import uuid
app = Flask(__name__)
SCHEMA = """CREATE TABLE files (
id text primary key,
path text
);
"""
def db():
g_db = getattr(g, '_database', None)
if g_db is None:
g_db = g._database = sqlite3.connect("database.db")
return g_db
@app.before_first_request
def setup():
os.remove("database.db")
cur = db().cursor()
cur.executescript(SCHEMA)
@app.route('/')
def hello_world():
return """<!DOCTYPE html>
<html>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="file">
<input type="submit" value="Upload File" name="submit">
</form>
<!-- /source -->
</body>
</html>"""
@app.route('/source')
def source():
return send_from_directory(directory="/var/www/html/", path="www.zip", as_attachment=True)
@app.route('/upload', methods=['POST'])
def upload():
if 'file' not in request.files:
return redirect('/')
file = request.files['file']
if "." in file.filename:
return "Bad filename!", 403
conn = db()
cur = conn.cursor()
uid = uuid.uuid4().hex
try:
cur.execute("insert into files (id, path) values (?, ?)", (uid, file.filename,))
except sqlite3.IntegrityError:
return "Duplicate file"
conn.commit()
file.save('uploads/' + file.filename)
return redirect('/file/' + uid)
@app.route('/file/<id>')
def file(id):
conn = db()
cur = conn.cursor()
cur.execute("select path from files where id=?", (id,))
res = cur.fetchone()
if res is None:
return "File not found", 404
# print(res[0])
with open(os.path.join("uploads/", res[0]), "r") as f:
return f.read()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
我们直接看最关键的def upload
和def file
里的内容,意思是,上传的文件不能有后缀名,且文件名前会拼接一个前缀upload/
,使得输出的文件只能是在目录upload/
下的,这里就涉及到os.path.join()
的绝对路径拼接漏洞:
绝对路径拼接漏洞
os.path.join(path,*paths)函数用于将多个文件路径连接成一个组合的路径。第一个函数通常包含了基础路径,而之后的每个参数被当作组件拼接到基础路径之后。
然而,这个函数有一个少有人知的特性,如果拼接的某个路径以 / 开头,那么包括基础路径在内的所有前缀路径都将被删除,该路径将视为绝对路径
即,若我们使得res[0]='/flag'
,则可以读取到根目录下的flag文件,因此利用bp抓包,修改文件名为/flag
即可:
![](https://images.cnblogs.com/cnblogs_com/blogs/729425/galleries/2331778/o_230811151135_image-20230811230918346.png)
我们直接访问得到的路径,获得flag:
![](https://images.cnblogs.com/cnblogs_com/blogs/729425/galleries/2331778/o_230811151134_image-20230811230938222.png)
NSSCTF{4ee39007-decc-43ca-bffc-65f593babeb3}
日期:2023.8.11
作者:y0Zero