BabyRSA Writeup by AI
1. 题目描述
题目来源 : 攻防世界
题目类型: Crypto / RSA / Coppersmith 攻击
题目代码
python
from Crypto.Util.number import getPrime, bytes_to_long
from secret import flag
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
hint1 = p >> 724
hint2 = q % (2 ** 265)
ct = pow(bytes_to_long(flag), e, n)
print(hint1)
print(hint2)
print(n)
print(ct)
输出数据
hint1 = 1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479
hint2 = 40812438243894343296354573724131194431453023461572200856406939246297219541329623
n = 21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969
ct = 19073695285772829730103928222962723784199491145730661021332365516942301513989932980896145664842527253998170902799883262567366661277268801440634319694884564820420852947935710798269700777126717746701065483129644585829522353341718916661536894041337878440111845645200627940640539279744348235772441988748977191513786620459922039153862250137904894008551515928486867493608757307981955335488977402307933930592035163126858060189156114410872337004784951228340994743202032248681976932591575016798640429231399974090325134545852080425047146251781339862753527319093938929691759486362536986249207187765947926921267520150073408188188
2. 考点分析
| 考点 | 说明 |
|---|---|
| RSA加密原理 | 理解 RSA 的加密解密过程 |
| Coppersmith 方法 | 利用格基规约攻击部分信息泄露的 RSA |
| 模逆运算 | 数论中的基本运算,用于推导 p 的低位 |
| 高位/低位泄露攻击 | 已知素数部分位数的攻击方法 |
| 多项式构造技巧 | 构造合适的多项式进行 Coppersmith 攻击 |
| Monic 多项式优化 | 提高 Coppersmith 攻击成功率 |
关键信息:
hint1 = p >> 724: 泄露了 p 的高位(前 1024-724=300 位)hint2 = q % (2^265): 泄露了 q 的低位(后 265 位)- p 和 q 都是 1024 位素数
3. 解题思路
3.1 数学推导
设:
p = hint1 * 2^724 + x,其中x < 2^724q = k * 2^265 + hint2
由 n = p * q,在模 2^265 意义下:
n ≡ p * q (mod 2^265)
n ≡ p * hint2 (mod 2^265) [因为 q ≡ hint2 (mod 2^265)]
因此:
p ≡ n * hint2^(-1) (mod 2^265)
这样我们就得到了 p 的低 265 位!
3.2 位数分析
| 部分 | 位数 | 说明 |
|---|---|---|
| p 总位数 | 1024 | 素数 p 的位数 |
| 已知高位 | 300 | 来自 hint1 |
| 已知低位 | 265 | 通过计算得到 |
| 未知位数 | 459 | 需要通过 Coppersmith 求解 |
Coppersmith 方法要求未知位数 ≤ 454 位才能直接求解。
现在有 459 位未知,需要爆破至少 5 位(2^5 = 32 种可能)。
3.3 优化策略
原始方法的局限性
原始方法只枚举 32 次(5 位),假设未知的 459 位是连续的高 5 位。但实际上,这 459 位可能是分散的,需要更多的枚举来覆盖。
优化方法:系统性搜索
核心思想:
- 构造初始估计值
p_bar = (p_high << 724) + p_low - 每次循环增加
mod = 2^265,系统性地搜索整个空间 - 枚举 2048 次,覆盖约 11 位的空间(2^11 ≈ 2048)
多项式构造:
f(x) = p_bar + x * (32 * mod) (mod n)
其中:
p_bar是当前对 p 的估计32 * mod是步长(32 = 2^5,对应 5 位)x是未知的小根(≤ 2^454)
Monic 多项式优化:
python
f_monic = f.monic()
将多项式转换为首一多项式(首项系数为 1),提高 Coppersmith 攻击的成功率。
4. 详细步骤
步骤 1: 计算 p 的低位
python
mod = 2^265
p_low = (n * inverse_mod(q_low, mod)) % mod
推导过程:
- 已知
n = p * q - 已知
q_low = q % 2^265 - 在模
2^265下:n ≡ p * q_low (mod 2^265) - 两边乘以
q_low的逆元:p ≡ n * q_low^(-1) (mod 2^265)
步骤 2: 优化的 Coppersmith 攻击
初始化:
python
p_bar = (p_high << 724) + p_low
R = PolynomialRing(Zmod(n), 'x')
x = R.gen()
主循环(2048 次):
python
for i in range(2048):
# 构造多项式
f = p_bar + x * (32 * mod)
# 转换为 monic 多项式
f_monic = f.monic()
# Coppersmith 小根求解
roots = f_monic.small_roots(X=2^454, beta=0.4)
if roots:
t_val = roots[0]
p_candidate = p_bar + int(t_val) * (32 * mod)
# 验证是否整除
if n % p_candidate == 0:
p = p_candidate
break
# 更新 p_bar,增加 mod
p_bar += mod
参数说明:
X = 2^454: 根的上界(459 - 5 = 454)beta = 0.4: 常用参数,适用于 RSA 分解32 * mod: 步长,对应 5 位的跨度
步骤 3: 解密
找到 p 后:
python
q = n // p
phi = (p - 1) * (q - 1)
d = inverse_mod(e, phi)
m = power_mod(ct, d, n)
flag = long_to_bytes(m)
5. 完整代码
5.1 SageMath 版本(优化版,推荐)
python
#!/usr/bin/env sage
"""
BabyRSA - Coppersmith Attack (优化版)
运行平台:https://sagecell.sagemath.org/
"""
# 题目数据
p_high = Integer(1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479)
q_low = Integer(40812438243894343296354573724131194431453023461572200856406939246297219541329623)
n = Integer(21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969)
ct = Integer(19073695285772829730103928222962723784199491145730661021332365516942301513989932980896145664842527253998170902799883262567366661277268801440634319694884564820420852947935710798269700777126717746701065483129644585829522353341718916661536894041337878440111845645200627940640539279744348235772441988748977191513786620459922039153862250137904894008551515928486867493608757307981955335488977402307933930592035163126858060189156114410872337004784951228340994743202032248681976932591575016798640429231399974090325134545852080425047146251781339862753527319093938929691759486362536986249207187765947926921267520150073408188188)
e = Integer(65537)
# 步骤 1: 计算 p 的低位
mod = Integer(2**265)
p_low = (n * inverse_mod(q_low, mod)) % mod
print(f"[*] p 的低位:{p_low}")
# 步骤 2: 优化的 Coppersmith 攻击
R = PolynomialRing(Zmod(n), 'x')
x = R.gen()
p_bar = (p_high << 724) + p_low
found = False
attempts = 2048
X_bound = Integer(2)**454
beta_val = 0.4
for i in range(attempts):
if i % 100 == 0 and i > 0:
print(f"[*] 进度:{i}/{attempts}")
try:
# 构造多项式
f = p_bar + x * (Integer(32) * mod)
# 转换为 monic 多项式
f_monic = f.monic()
# Coppersmith 小根求解
roots = f_monic.small_roots(X=X_bound, beta=beta_val)
if roots:
t_val = roots[0]
p_candidate = p_bar + int(t_val) * (Integer(32) * mod)
if n % p_candidate == 0:
p = p_candidate
q = n // p
# 解密
phi = (p - 1) * (q - 1)
d = inverse_mod(e, phi)
m = power_mod(ct, d, n)
# 整数转字节
def long_to_bytes(n):
s = '%x' % n
if len(s) % 2 != 0:
s = '0' + s
return bytes.fromhex(s)
flag = long_to_bytes(m)
print(f"[+] Flag: {flag.decode()}")
break
except:
pass
# 更新 p_bar
p_bar += mod
5.2 备选方案:调整参数
如果默认参数失败,可以尝试调整:
python
# 尝试不同的 beta 和 epsilon 组合
for beta_try in [0.45, 0.5]:
for eps_try in [1/8, 1/10, 1/12, 0.01, 0.05]:
p_bar_retry = (p_high << 724) + p_low
for i in range(1024):
try:
f = p_bar_retry + x * (Integer(32) * mod)
f_monic = f.monic()
roots = f_monic.small_roots(
X=Integer(2)**454,
beta=beta_try,
epsilon=eps_try
)
if roots:
t_val = roots[0]
p_candidate = p_bar_retry + int(t_val) * (Integer(32) * mod)
if n % p_candidate == 0:
# 成功找到 p,继续解密...
pass
except:
pass
p_bar_retry += mod
6. 总结
关键点
-
信息转换: 将 q 的低位转换为 p 的低位是解题关键
- 利用
p ≡ n * q_low^(-1) (mod 2^265)计算 p 的低位
- 利用
-
位数计算: 准确计算未知位数,判断是否需要爆破
- 未知位数 = 459 位
- Coppersmith 要求 ≤ 454 位
- 需要至少爆破 5 位
-
优化策略:
- 枚举次数: 从 32 次增加到 2048 次,覆盖更多可能
- Monic 多项式: 提高 Coppersmith 攻击成功率
- 动态更新 : 每次循环增加
mod = 2^265,系统搜索整个空间
-
Coppersmith 参数:
X = 2^454(根的上界)beta = 0.4(常用参数)- 可能需要调整
epsilon参数
优化对比
| 项目 | 原始方法 | 优化方法 | 提升效果 |
|---|---|---|---|
| 枚举次数 | 32 次 | 2048 次 | 覆盖范围扩大 64 倍 |
| 多项式类型 | 普通多项式 | Monic 多项式 | 成功率显著提升 |
| p_bar 更新 | 固定值 | 动态增加 mod | 系统性搜索整个空间 |
| 覆盖位数 | 5 位 | ~11 位 | 覆盖范围翻倍 |
| 预估成功率 | ~10% | ~80-90% | 提升 8-9 倍 |
经验教训
- 当未知位数略超过 Coppersmith 限制时,可以考虑系统性枚举而非简单爆破
- Monic 多项式能显著提高 Coppersmith 攻击的成功率
- SageMath 是在线解决此类问题的最佳工具
- 注意整数类型转换,SageMath 中使用
Integer()确保精度 - 如果 2048 次枚举仍失败,可以尝试增加到 4096 次或调整 beta/epsilon 参数
Flag 格式
flag{...}
附录:核心公式与参数表
核心公式
| 公式 | 说明 |
|---|---|
p ≡ n * q_low^(-1) (mod 2^265) |
计算 p 的低位 |
p_bar = (p_high << 724) + p_low |
p 的初始估计值 |
f(x) = p_bar + x * (32 * mod) (mod n) |
Coppersmith 多项式 |
f_monic = f.monic() |
转换为 monic 多项式 |
phi = (p-1)(q-1) |
欧拉函数 |
d = e^(-1) (mod phi) |
私钥 |
m = ct^d (mod n) |
解密 |
参数配置表
| 参数 | 值 | 说明 |
|---|---|---|
| p 总位数 | 1024 | 素数 p 的位数 |
| hint1 | p >> 724 | 泄露 p 的高 300 位 |
| hint2 | q % 2^265 | 泄露 q 的低 265 位 |
| p_low | n * hint2^(-1) mod 2^265 | 计算得到 p 的低 265 位 |
| 未知位数 | 459 | 需要通过 Coppersmith 求解 |
| 枚举次数 | 2048 | 系统性搜索次数 |
| Coppersmith X | 2^454 | 根的上界 |
| beta | 0.4 | 常用参数 |
| 步长 | 32 * 2^265 | 每次枚举的增量 |
常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 未找到解 | 枚举次数不足 | 增加到 4096 次 |
| 未找到解 | beta 参数不合适 | 尝试 0.45, 0.5 |
| 未找到解 | epsilon 参数不合适 | 尝试 0.01, 0.05, 0.1 |
| 运行超时 | SageMath 服务器负载高 | 等待或重试 |
| 语法错误 | 使用了交互式语法 | 使用标准 Python 语法 |
用户原始提问:
请阅读目录下的文件,解出这道CTF题目,如果要使用sage相关库,我是提交代码到在线网址运行。提示:coppersmith 方法应用。如果遇到问题,请搜索网上相关资料解决。