[NewStarCTF 2023 公开赛道]eazy_crt

MagicianV RSA 题解(WP)

题目源码:

复制代码
from Crypto.Util.number import *
from secret import flag, p, q
from hashlib import *
import random

assert 'flag{' + md5(str(p).encode()).hexdigest() + '}' == flag
assert isPrime(p), isPrime(q)
assert p.bit_length() == 1024, q.bit_length() == 1024

m = random.getrandbits(400)
e = 65537
d = inverse(e, (p - 1) * (q - 1))
r1, r2, r3 = getPrime(20), getPrime(20), getPrime(10)

dp, dq = d % (p - 1), d % (q - 1)
Sp, Sq = pow(m + getPrime(10), dp, r1 * p), pow(m, dq, r2 * q)
s1, s2 = pow(m, dp % (r1 - 1), r1), pow(m, dq % (r2 - 1), r2)

S_ = Sq + (q * r2) * (int(inverse(q * r2, p * r1)) * (Sp - Sq) % (p * r1))

c1, c2 = (S_ - s1 + 1) % r1, (S_ - s2 + 1) % r2

gamma = (r3 * c1 + (2 ** 10 - r3) * c2) // (2 ** 10)

S = pow(S_, gamma, p * q)

给出了:

  • m

  • n = p*q

  • S_

  • S

目标:

复制代码
flag = flag{md5(str(p))}

所以核心是:

分解 n


一、观察关键点

最关键的一句:

复制代码
S = pow(S_, gamma, n)

即:

复制代码
S ≡ S_^gamma mod n

这里:

复制代码
gamma = (r3 * c1 + (2 ** 10 - r3) * c2) // (2 ** 10)

其中:

  • r3 是 10 bit 素数

  • c1 < r1

  • c2 < r2

  • r1,r2 是 20 bit 素数

因此:

gamma 很小

数量级:

复制代码
gamma < 2^20

二、爆破 gamma

因为:

复制代码
S = S_^gamma mod n

而:

复制代码
gamma < 2^20

所以直接暴力:

复制代码
for g in range(2**20):
    if pow(S_, g, n) == S:
        print(g)

得到:

复制代码
gamma = 337756

三、利用 gamma 分解 n

由于:

复制代码
S ≡ S_^gamma mod n

则:

复制代码
S_^gamma - S ≡ 0 mod n

即:

复制代码
n | (S_^gamma - S)

这意味着:

复制代码
pow(S_, gamma, n) - S

与 n 存在巨大关系。

进一步考虑:

RSA 中常用:

复制代码
gcd(a^k - b, n)

去提取因子。

于是尝试:

复制代码
g = gcd(pow(S_, gamma) - S, n)

即可得到:

复制代码
p

随后:

复制代码
q = n // p

完成分解。


四、计算 flag

题目:

复制代码
flag = flag{md5(str(p))}

因此:

复制代码
from hashlib import md5

flag = "flag{" + md5(str(p).encode()).hexdigest() + "}"

得到:

复制代码
flag{b40ea076da8c73572ae5d067aa0fc22e}

五、完整 EXP

复制代码
from Crypto.Util.number import *
from hashlib import md5
from math import gcd

m = ...
n = ...
S_ = ...
S = ...

for gamma in range(1 << 20):
    if pow(S_, gamma, n) == S:
        print("[+] gamma =", gamma)
        break

x = pow(S_, gamma) - S
p = gcd(x, n)
q = n // p

print("[+] p =", p)
print("[+] q =", q)

flag = "flag{" + md5(str(p).encode()).hexdigest() + "}"
print(flag)

六、题目考点

这题核心是:

小指数泄露

由于:

复制代码
gamma < 2^20

导致:

复制代码
S = S_^gamma mod n

可以直接离散爆破。

随后通过:

复制代码
gcd(pow(S_, gamma) - S, n)

恢复 RSA 因子。

本质属于:

RSA 参数构造失误 + 小指数攻击

相关推荐
xiaogai_gai7 小时前
仅查询策略实战:从金蝶云·星空旗舰版定时拉取收料通知单
大数据·数据库·python
benchmark_cc7 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu7 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog7 小时前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
CoderYanger8 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
估值探索者8 小时前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口
田里的水稻9 小时前
PyTorch_Dataloader\TensorBoard---数据加载与可视化
人工智能·pytorch·python·神经网络·机器学习
Dmz丶9 小时前
前端转 AI 100 天 Day 27:Docker 容器化——从“我电脑能跑“到“到处能跑“
python
卿卿的产品经理日记9 小时前
【AI产品经理实战】Day 38|try-except 踩坑实录:报错是数据
人工智能·笔记·python·学习·产品经理
全栈练习生9 小时前
文档智能与实践
python·ai