1. 从一道CTF题看RSA基础攻击手法
2019年HDCTF网络安全竞赛中的"basic rsa"题目,看似简单却暗藏玄机。这道题考察的是RSA加密算法的基础知识以及常见的攻击手段。作为密码学中最经典的公钥加密算法,RSA的安全性建立在"大整数分解难题"之上,但当参数设置不当时,就会给攻击者留下可乘之机。
提示:在CTF比赛中,RSA相关题目通常考察对算法原理的理解和参数漏洞的利用能力,而非暴力破解。
1.1 RSA算法核心原理回顾
RSA算法由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出,其安全性依赖于大整数分解的困难性。算法流程主要分为三个步骤:
-
密钥生成:
- 选择两个大质数p和q
- 计算n = p × q
- 计算欧拉函数φ(n) = (p-1)(q-1)
- 选择整数e满足1 < e < φ(n)且gcd(e, φ(n)) = 1
- 计算d ≡ e⁻¹ mod φ(n)
- 公钥为(e, n),私钥为(d, n)
-
加密过程:
- 明文m转换为整数M (0 ≤ M < n)
- 密文C ≡ Mᵉ mod n
-
解密过程:
- 计算M ≡ Cᵈ mod n
- 将M转换回明文m
1.2 题目环境搭建与初步分析
假设我们获得了题目提供的以下参数:
- 公钥(e, n)
- 加密后的密文c
典型的解题思路是尝试恢复私钥(d, n)来解密密文。根据RSA原理,我们需要获取φ(n)或直接分解n得到p和q。在"basic rsa"这类基础题目中,通常存在以下几种漏洞可能:
- n过小可直接分解:当n的位数较小时(如512bit以下),可以用工具快速分解
- 共模攻击:如果相同的n被多个用户使用
- 低加密指数攻击:当e很小时(如e=3)
- 因数碰撞:如果两个n有公共因数
- 已知d攻击:当泄露了d时可以恢复私钥
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. RSA参数常见漏洞与利用技术
2.1 小模数n的分解攻击
这是CTF中最基础的RSA攻击方式。当n的位数不足时,可以在较短时间内完成因数分解。以下是使用Python进行分解的示例:
python复制from sympy import factorint
n = 0x123456... # 题目给出的n
factors = factorint(n)
p, q = list(factors.keys())
print(f"p = {p}\nq = {q}")
对于更大的n(如768bit以上),可以使用更专业的工具:
- Factordb:在线分解数据库(http://factordb.com)
- YAFU:自动化整数分解工具
- GMP-ECM:椭圆曲线分解方法
注意:在实际CTF比赛中,题目给出的n通常已经足够小,可以直接用工具分解。如果遇到无法分解的大n,则要考虑其他攻击方式。
2.2 低加密指数攻击
当公钥指数e很小时(如e=3),如果明文m也较小,可能导致mᵉ < n,此时可以直接开e次方恢复明文:
python复制from gmpy2 import iroot
c = 0x123... # 密文
e = 3
m, is_exact = iroot(c, e)
if is_exact:
print(bytes.fromhex(hex(m)[2:]).decode())
防御措施:加密时对明文进行填充(如OAEP),确保mᵉ >> n。
2.3 共模攻击
当相同的明文m用相同的n但不同的e加密时,如果gcd(e₁,e₂)=1,则可以通过扩展欧几里得算法恢复明文:
python复制from gmpy2 import gcdext
def common_modulus_attack(c1, c2, e1, e2, n):
gcd, x, y = gcdext(e1, e2)
if gcd != 1:
return None
if x < 0:
c1 = invert(c1, n)
x = -x
if y < 0:
c2 = invert(c2, n)
y = -y
m = (pow(c1, x, n) * pow(c2, y, n)) % n
return m
2.4 Wiener攻击
当私钥d较小时(d < 1/3 n^(1/4)),可以通过连分数展开来恢复d。以下是Python实现:
python复制from Crypto.Util.number import long_to_bytes
from fractions import Fraction
def wiener_attack(e, n):
# 将e/n展开为连分数
frac = Fraction(e, n)
convergents = []
for i in range(100): # 尝试100次
a = frac.numerator // frac.denominator
convergents.append(a)
if frac.denominator == 0:
break
frac = 1/(frac - a)
# 检查每个收敛项
for k in range(1, len(convergents)):
d = convergents[k]
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) // k
# 解方程x² - (n - phi + 1)x + n = 0
b = n - phi + 1
delta = b*b - 4*n
if delta < 0:
continue
sqrt_delta = isqrt(delta)
if sqrt_delta * sqrt_delta != delta:
continue
p = (b + sqrt_delta) // 2
q = (b - sqrt_delta) // 2
if p * q == n:
return d
return None
3. 针对HDCTF2019题目的实战解题
假设题目提供了以下参数:
- n = 742449129124467073921545687640895127535705902454369756401331
- e = 3
- c = 39207274348578481322317340648475596807303160111338236677373
3.1 第一步:分解n
使用factordb在线工具分解n:
code复制n = 752708788837165590355094155871 × 986369682585281993933185289261
得到:
p = 752708788837165590355094155871
q = 986369682585281993933185289261
3.2 第二步:计算私钥d
python复制from Crypto.Util.number import inverse
p = 752708788837165590355094155871
q = 986369682585281993933185289261
e = 3
n = p * q
phi = (p-1)*(q-1)
d = inverse(e, phi)
print(d)
3.3 第三步:解密密文c
python复制m = pow(c, d, n)
print(bytes.fromhex(hex(m)[2:]).decode())
3.4 完整解题脚本
python复制from Crypto.Util.number import long_to_bytes, inverse
n = 742449129124467073921545687640895127535705902454369756401331
e = 3
c = 39207274348578481322317340648475596807303160111338236677373
# 分解n得到p和q
p = 752708788837165590355094155871
q = 986369682585281993933185289261
# 计算私钥d
phi = (p-1)*(q-1)
d = inverse(e, phi)
# 解密
m = pow(c, d, n)
print(long_to_bytes(m).decode())
4. RSA安全实践与防御措施
4.1 安全的参数选择
-
模数n的位数:
- 目前推荐至少2048位
- 高安全场景使用3072或4096位
-
公钥指数e的选择:
- 常用e=65537(2^16+1)
- 避免使用小e(如3)
-
私钥指数d:
- 必须足够大,防止Wiener攻击
- 建议d > n^0.292
4.2 加密填充方案
- PKCS#1 v1.5:较老的标准,仍广泛使用但存在某些攻击可能
- OAEP:推荐使用的填充方案,安全性更高
4.3 实际应用中的注意事项
-
密钥生成:
- 使用安全的随机数生成器
- p和q应该大小相近但差异足够大
- (p-1)和(q-1)都应该有大素因子
-
实现安全:
- 防止时序攻击
- 防止错误分析攻击
- 使用恒定时间算法
-
密钥管理:
- 私钥必须严格保护
- 定期更换密钥
- 使用HSM保护密钥
重要提示:在实际开发中,应该使用成熟的密码学库(如OpenSSL、PyCryptodome),而不是自己实现RSA算法,以避免引入安全漏洞。
5. CTF中RSA题目的进阶技巧
5.1 已知部分私钥信息攻击
当题目给出私钥d的部分信息时,可以使用Coppersmith方法恢复完整私钥。例如已知d的低位:
python复制def partial_d_attack(n, e, d_lowbits, knownbits):
P.<x> = PolynomialRing(Zmod(n))
d = d_lowbits + x * 2^knownbits
f = e * d - 1
roots = f.small_roots(X=2^(n.nbits()-knownbits), beta=0.3)
if roots:
return d_lowbits + roots[0] * 2^knownbits
return None
5.2 Franklin-Reiter相关消息攻击
当两个明文存在线性关系,且使用相同的n和e加密时:
python复制def franklin_reiter_attack(c1, c2, e, n, a, b):
# 假设m2 = a*m1 + b
P.<x> = PolynomialRing(Zmod(n))
f1 = x^e - c1
f2 = (a*x + b)^e - c2
return -gcd(f1, f2).coefficients()[0]
5.3 Hastad广播攻击
当相同的明文用相同的e加密发送给e个不同的接收者时:
python复制from sympy.ntheory.modular import crt
def hastad_attack(c_list, n_list, e):
assert len(c_list) == len(n_list) == e
m_e = crt(n_list, c_list)[0]
m, exact = iroot(m_e, e)
if exact:
return m
return None
5.4 Boneh-Durfee攻击
当d < n^0.292时,比Wiener攻击更强的攻击方法:
python复制# 实现较复杂,通常使用现成工具如RsaCtfTool
6. 实用工具与资源推荐
6.1 RSA解题工具集
-
RsaCtfTool:多功能RSA攻击工具
code复制git clone https://github.com/Ganapati/RsaCtfTool.git cd RsaCtfTool python RsaCtfTool.py --publickey key.pub --uncipherfile cipher.txt -
sage数学工具:包含多种高级数论算法
-
factordb:在线大整数分解服务
6.2 学习资源
-
书籍:
- 《应用密码学:协议、算法与C源程序》Bruce Schneier
- 《密码编码学与网络安全》William Stallings
-
在线课程:
- Coursera密码学专项课程
- Stanford密码学课程
-
CTF平台:
- CTFtime.org
- Hack The Box
- PicoCTF
6.3 Python密码学库
-
PyCryptodome:全面的密码学库
python复制from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP -
gmpy2:高精度数学运算
python复制import gmpy2 from gmpy2 import mpz, powmod, invert -
sympy:符号数学计算
python复制from sympy import factorint, gcd
在实际CTF比赛中遇到RSA题目时,建议按照以下步骤进行:
- 收集所有给定参数(n,e,c等)
- 检查n是否可以分解
- 检查是否存在特殊关系(如e很小、相同n等)
- 尝试常见攻击方法
- 使用工具验证思路
- 编写最终解题脚本
通过这道"basic rsa"题目,我们不仅学习了RSA的基础知识,还掌握了多种实用的攻击技术。在后续的CTF比赛中遇到更复杂的RSA题目时,这些技术将成为你的有力武器。
