1. 密码学竞赛中的RSA挑战
在CTF(Capture The Flag)网络安全竞赛中,Crypto密码学题型一直是检验选手数学功底和代码能力的试金石。而RSA算法作为现代密码学的基石,几乎出现在每场CTF赛事中。记得我第一次参加线下赛时,就被一道看似简单的RSA题目卡了整整两小时——那是个典型的模数分解问题,但需要结合费马分解和Pollard's rho算法才能高效破解。
RSA题型之所以经典,在于它能融合数论知识、编程技巧和实战思维。不同于Web或Pwn题型需要复杂的漏洞利用,RSA破解往往只需要十几行Python代码,但背后需要选手对算法原理有深刻理解。本文将系统梳理CTF中RSA题型的六大攻击场景,从基础的模数分解到进阶的Coppersmith攻击,每个方法都配有实战代码和竞赛真题解析。
2. RSA算法核心原理回顾
2.1 密钥生成机制
RSA的安全性建立在"大整数分解难题"上,其密钥生成过程如下:
- 选择两个大质数p和q(CTF中通常为512bit或1024bit)
- 计算模数N = p × q
- 计算欧拉函数φ(N) = (p-1)(q-1)
- 选择公钥指数e(常见值为65537)
- 计算私钥d ≡ e⁻¹ mod φ(N)
在CTF题目中,攻击者通常能获取公钥(N, e)和密文c,目标是通过各种方法还原明文m ≡ cᵈ mod N。
2.2 典型题目文件结构
一道标准的RSA题目通常包含以下文件:
code复制- public.key # 公钥文件
- flag.enc # 加密后的flag
- task.py # 加密脚本(可能含提示)
使用OpenSSL解析公钥的示例命令:
bash复制openssl rsa -pubin -in public.key -text -noout
3. CTF常见RSA攻击手法
3.1 模数分解攻击
当N较小时(如512bit),可以直接用factordb.com或yafu工具分解。实战案例:
python复制from Crypto.Util.number import long_to_bytes
import gmpy2
n = 742449129124467073921545687640895127535705902454369756401331
e = 65537
c = 39207274348578481322317340648475596807303160111338236677373
# 通过factordb查得p,q
p = 752708788837165590355094155871
q = 986369682585281993933185289261
phi = (p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
关键技巧:遇到大N时先尝试factordb查询,可能已有现成分解结果
3.2 共模攻击
当相同明文用不同公钥(e₁,e₂)加密,且模数N相同时:
python复制def common_modulus(e1, e2, c1, c2, n):
gcd, a, b = gmpy2.gcdext(e1, e2)
if a < 0:
c1 = gmpy2.invert(c1, n)
a = -a
if b < 0:
c2 = gmpy2.invert(c2, n)
b = -b
return pow(c1,a,n) * pow(c2,b,n) % n
3.3 低加密指数攻击
当e很小时(如e=3),可能直接开方得到明文:
python复制m = gmpy2.iroot(c, e)[0]
但需注意明文需要满足m^e < N,否则需要结合中国剩余定理。
4. 进阶攻击手法解析
4.1 Wiener攻击
当私钥d较小时(d < 1/3 N^(1/4)),可以通过连分数展开破解:
python复制def wiener_attack(e, n):
# 连分数展开算法
# ...详细实现代码...
return d
4.2 Coppersmith定理应用
针对已知明文高位或低位的情况:
python复制n = # 模数
e = 3
c = # 密文
m_known = # 已知的明文部分
F.<x> = PolynomialRing(Zmod(n))
f = (m_known + x)^e - c
roots = f.small_roots(X=2^k, beta=0.5) # k为未知位数
5. 实战题目拆解
5.1 2022年某CTF赛题
题目给出:
- N = 799...(1024bit)
- e = 65537
- c = 532...
通过分析发现N具有以下特性:
python复制p = getPrime(512)
q = next_prime(p) # 提示:q与p非常接近
使用费马分解法:
python复制def fermat_factor(n):
a = gmpy2.isqrt(n) + 1
b2 = a*a - n
while not gmpy2.is_square(b2):
a += 1
b2 = a*a - n
return (a - gmpy2.isqrt(b2), a + gmpy2.isqrt(b2))
5.2 2023年De1CTF赛题
题目使用了RSA-OAEP填充方式,但错误地重复使用了相同的随机数。攻击脚本核心部分:
python复制# 已知两段密文c1,c2对应明文m1,m2
# 且m1 = pad(m)||r, m2 = pad(m)||r
def attack(c1, c2, e, n):
# 使用Franklin-Reiter相关消息攻击
# ...具体实现代码...
return m
6. 工具链与调试技巧
6.1 必备工具清单
- RsaCtfTool:集成多种攻击方法的自动化工具
bash复制
python RsaCtfTool.py --publickey key.pub --uncipherfile flag.enc - SageMath:用于Coppersmith攻击等高级算法
- PyCryptodome:处理各种加密格式
6.2 调试经验
- 遇到报错"m must be less than n"时,检查是否漏了模运算
- 使用
long_to_bytes时注意处理可能的填充字符 - 当解密结果乱码时,尝试:
- 检查字节序(大端/小端)
- 尝试不同编码(UTF-8/ASCII/hex)
- 检查是否有二次加密
7. 防御措施与出题思路
了解攻击方法后,出题时应注意:
- 确保N足够大(至少2048bit)
- 避免使用小e(如3)
- 不要重复使用相同的随机数
- 对输入进行严格校验
对于开发者而言,应当:
- 使用标准库(如Python的cryptography)
- 及时更新依赖项
- 避免自行实现加密算法
致命错误记录:曾在某次比赛中误将p作为明文发送,导致秒破。切记检查输出内容!
8. 延伸学习资源
- 《应用密码学手册》- 第8章公钥加密
- Cryptopals挑战赛:Set 5和Set 6
- NCTF历年Crypto题目归档
- Coppersmith论文《Small Solutions to Polynomial Equations...》
最后分享一个实用技巧:在本地搭建RSA题目环境时,可以使用pwntools库的process函数模拟远程连接,方便调试爆破脚本。遇到特别复杂的数论问题时,不妨先用小参数验证算法正确性,再应用到大赛题目中。