资料说明:原记录中提及的本机脚本及题目附件未随本文附上,相关文件名仅用于说明当时的复现流程。
Premaster(permeate)· 一个“填充对不对”的回答就够了
平台题目名:Premaster(Crypto,743 分,11:19:02 提交)。内部代号
permeate,目标m3bk608v:58999。
1 | flag{ttElEB3NmncnSmw66vkv9vWRXhaqa8DVJjn7Hj5G} |
目标:m3bk608v.nestctf.cyberpeace.cn:58999(TLS)
附件:pubkey.json(RSA n / e)
复现:py -3.13 attack.py → 落盘 plaintext.txt
一句话
服务端不告诉你明文,只回答一个比特:你给的密文解出来是不是合法的 PKCS#1 v1.5 填充。这一个比特就是 Bleichenbacher 预言机(1998),够把任意密文逐字节还原 —— 这里要还原的是会话开始时发下来的 c0。
0. 面
TLS 连上去,服务端先吐一行 banner:
1 | <tag> <c0-hex> <s0-decimal> |
c0 是会话密文(RSA 加密后的 PKCS#1 v1.5 块),s0 是它自带的初始盲化因子 —— 省掉了标准攻击里的“找起始 s”那一步。
之后每次发一行十六进制 c,回一行:
1 | ok # c 解出来是 00 02 || 非零填充 || 00 || 消息 |
1. 问题结构
RSA 解密一整个块:m = c^d mod n,合法填充形如
1 | 00 02 [PS: ≥8 字节非零] 00 [message] |
也就是 2B ≤ m < 3B(B = 2^(8(k-2)))。服务端只暴露 m ∈ [2B, 3B) 这一个区间判断,其余全黑。经典结论:有了这个判断,就能把 m 的可能范围从一整个模数区间,逐步收缩到单点。
2. 攻击步骤(脚本里的实现)
初始区间集合 M = {(2B, 3B-1)},然后用 banner 给的 s0 做第一次收缩。
之后迭代两类步骤:
- 多区间时(3a):从
s_prev + 1起逐个试s,直到c0 · s^e mod n被判ok;命中即用。 - 单区间时(3c):由
r = ceil((2(b·s_prev - 2B))/n)起,对每个r算候选s = ceil((2B + r·n)/b),批量投喂,取第一个ok。
每次命中都过一遍区间收紧:
1 | rmin = ceil((a·s - (3B-1)) / n) |
把所有候选区间排序合并,直到集合里只剩一个点 —— 那就是 m。
3. 工程上真正决定成败的两件事
(1) 批量问,别一问一答。 RSA 一次 2048 位运算在服务端不便宜,一问一答的 RTT 会把总时间拉到不可接受。脚本一次写 256 个 c,再连读 256 行 ok/fail,只取第一个命中:
1 | def batch(self, svals): |
(2) 用 banner 的 s0 少走一轮。 服务端已经把第一个有效 s 给你了,等于白送一次区间收缩。
4. 还原明文
单点解出来后按 00 02 PS 00 msg 剥壳:
1 | em = m.to_bytes(k, "big") |
1 | flag{ttElEB3NmncnSmw66vkv9vWRXhaqa8DVJjn7Hj5G} |
5. 踩坑
| 坑 | 现象 | 解决 |
|---|---|---|
| 一问一答 | 每秒几百次,跑不完 | 批量 256 个一批,单次 write + 顺序读回 |
| 自己找起始 s | 从 ceil(n/3B) 起扫,空转 |
banner 直接给了 s0,用它做第一次收缩 |
| 区间不合并 | 候选指数增长,越跑越慢 | 每轮排序后合并相邻/重叠区间 |
只判断 m < 3B |
收缩不到单点 | 必须同时要求 m ≥ 2B(00 02 前缀) |
| 连接被服务端关 | ConnectionError: closed |
重连后重新取 banner(c0/s0 是新会话的) |
6. 防御侧
- 解密失败时不要区分“填充错”和“结构错”,统一返回同一个错误、同一耗时;
- 用 RSA-KEM / OAEP 替代 PKCS#1 v1.5 加密;
- 对同一密文的重复提交做速率限制与会话绑定 —— 这个 oracle 需要几万到几十万次询问,限流能直接掐死。
7. 一句话总结
Bleichenbacher 二十年不过时,因为它的前提太廉价:只要有一个能区分“合法/非法填充”的旁路,RSA 的语义安全性就没了。 这题甚至连“找起点”都替你省了 —— banner 把 c0 和 s0 一起递到手上。
本文作者 Allureluoli
文字版权归作者所有,转载请注明出处;商业用途请先联系二月。