CTF实战:手把手教你用Python+gmpy2秒解RSA共模攻击题(附完整脚本)
·
CTF实战:用Python+gmpy2破解RSA共模攻击的五个关键步骤
第一次参加CTF比赛时,我盯着那道RSA题目整整两小时毫无头绪。直到发现两个密文共享同一个模数n,才意识到这是典型的共模攻击场景。本文将用最直白的方式,带你重现从茫然到破解的全过程。
1. 环境准备与工具选择
在开始前,我们需要配置合适的开发环境。推荐使用Python 3.8+版本,这是目前最稳定的选择。关键库gmpy2的安装可能会让新手头疼——特别是在Windows系统上。
# 安装必备库
pip install gmpy2 pycryptodome
如果遇到 gmpy2 安装失败,可以尝试以下替代方案:
-
Linux/macOS用户 :先安装依赖库
# Debian/Ubuntu sudo apt install libgmp-dev libmpfr-dev libmpc-dev # macOS brew install gmp mpfr libmpc -
Windows用户 :直接下载预编译的whl文件
# 从https://www.lfd.uci.edu/~gohlke/pythonlibs/#gmpy2下载对应版本的whl pip install gmpy2‑2.1.0b5‑cp38‑cp38‑win_amd64.whl
提示:遇到
ImportError时,检查Python版本与gmpy2是否匹配。32位和64位系统也需要对应版本。
2. 识别共模攻击的特征
共模攻击有三大典型特征,就像侦探破案的线索:
- 相同的模数n :两个密文使用完全一样的n值
- 不同的公钥指数 :e1和e2互质(通常为不同的素数)
- 加密相同明文 :c1和c2是对同一消息m的加密
在实际CTF题目中,这些信息可能隐藏在JSON数据、网络流量或注释里。以BUUCTF的rsa3为例,题目通常会给出:
n = 22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801
e1 = 11187289
e2 = 9647291
c1 = 22322035275663237041646893770451933509324701913484303338076210603542612758956262869640822486470121149424485571361007421293675516338822195280313794991136048140918842471219840263536338886250492682739436410013436651161720725855484866690084788721349555662019879081501113222996123305533009325964377798892703161521852805956811219563883312896330156298621674684353919547558127920925706842808914762199011054955816534977675267395009575347820387073483928425066536361482774892370969520740304287456555508933372782327506569010772537497541764311429052216291198932092617792645253901478910801592878203564861118912045464959832566051361
c2 = 18702010045187015556548691642394982835669262147230212731309938675226458555210425972429418449273410535387985931036711854265623905066805665751803269106880746769003478900791099590239513925449748814075904017471585572848473556490565450062664706449128415834787961947266259789785962922238701134079720414228414066193071495304612341052987455615930023536823801499269773357186087452747500840640419365011554421183037505653461286732740983702740822671148045619497667184586123657285604061875653909567822328914065337797733444640351518775487649819978262363617265797982843179630888729407238496650987720428708217115257989007867331698397
3. 数学原理的实战解读
共模攻击的核心在于 扩展欧几里得算法 。我们不需要完全理解其数学证明,但必须掌握如何应用:
- 找到满足
e1*s1 + e2*s2 = 1的整数s1和s2 - 利用这两个系数组合密文:
m = (c1^s1 * c2^s2) mod n
这个等式成立的秘密在于:
m^(e1*s1 + e2*s2) ≡ m^1 ≡ m (mod n)
(c1^s1 * c2^s2) ≡ (m^e1)^s1 * (m^e2)^s2 ≡ m^(e1*s1 + e2*s2) ≡ m (mod n)
4. 完整攻击脚本与逐行解析
下面是我们破解BUUCTF rsa3的完整代码,每一行都有详细注释:
from gmpy2 import gcdext, powmod
from Crypto.Util.number import long_to_bytes
# 题目给出的参数
n = 22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801
e1, e2 = 11187289, 9647291
c1 = 22322035275663237041646893770451933509324701913484303338076210603542612758956262869640822486470121149424485571361007421293675516338822195280313794991136048140918842471219840263536338886250492682739436410013436651161720725855484866690084788721349555662019879081501113222996123305533009325964377798892703161521852805956811219563883312896330156298621674684353919547558127920925706842808914762199011054955816534977675267395009575347820387073483928425066536361482774892370969520740304287456555508933372782327506569010772537497541764311429052216291198932092617792645253901478910801592878203564861118912045464959832566051361
c2 = 18702010045187015556548691642394982835669262147230212731309938675226458555210425972429418449273410535387985931036711854265623905066805665751803269106880746769003478900791099590239513925449748814075904017471585572848473556490565450062664706449128415834787961947266259789785962922238701134079720414228414066193071495304612341052987455615930023536823801499269773357186087452747500840640419365011554421183037505653461286732740983702740822671148045619497667184586123657285604061875653909567822328914065337797733444640351518775487649819978262363617265797982843179630888729407238496650987720428708217115257989007867331698397
# 关键步骤1:使用扩展欧几里得算法找到s1和s2
gcd, s1, s2 = gcdext(e1, e2)
print(f"系数s1: {s1}, s2: {s2}") # 通常一正一负
# 关键步骤2:处理负指数(需要模逆元)
if s1 < 0:
c1 = powmod(c1, -1, n) # 计算c1的模逆元
s1 = -s1
if s2 < 0:
c2 = powmod(c2, -1, n)
s2 = -s2
# 关键步骤3:组合计算明文
m = (powmod(c1, s1, n) * powmod(c2, s2, n)) % n
# 结果转换
flag = long_to_bytes(m)
print("破解结果:", flag) # b'flag{49d91077a1abcb14f1a9d546c80be9ef}'
5. 常见错误与调试技巧
即使按照脚本操作,仍可能遇到各种问题。以下是五个常见错误及解决方案:
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
ValueError: invalid literal for int() |
参数中包含非数字字符 | 检查粘贴的n/e/c是否完整,去除换行和空格 |
TypeError: pow() 3rd argument not allowed unless all arguments are integers |
参数类型错误 | 确保所有参数都是整数,用 int() 转换 |
| 结果输出乱码 | 得到的m不是有效明文 | 检查是否处理了负指数,确认题目确实是共模攻击 |
| 计算时间过长 | n过大或算法问题 | 确认使用 powmod 而非 pow ,检查电脑性能 |
gmpy2.gcdext 返回空值 |
e1和e2不互质 | 确认题目条件,可能需要其他攻击方式 |
注意:当s1或s2为负数时,必须计算对应密文的模逆元。这是新手最容易忽略的关键步骤。
实际比赛中,我建议先验证小数字示例。比如用n=3233, e1=17, e2=19加密字母'A'(ASCII 65),确保脚本能正确解密后再处理大赛题目。
更多推荐
所有评论(0)