CTF实战:手把手教你用Python脚本秒解BUUCTF那道RSA共模攻击题(附完整代码)
CTF实战Python脚本秒解BUUCTF RSA共模攻击题第一次在BUUCTF平台遇到RSA共模攻击题时我盯着两组相似的n值和不同的e值完全摸不着头脑。直到理解了背后的数学原理才发现这类题目其实有固定的解题套路。本文将用最直白的方式带你从零开始攻破BJDCTF2020这道典型题目。1. 识别共模攻击场景当看到题目附件给出以下特征时就要立即想到共模攻击的可能性相同的模数n两组数据中的n值完全一致不同的指数ee1和e2值不同且通常互质对应的密文提供两个用不同公钥加密的密文c1和c2# 题目给出的典型数据结构 n 2105833933... # 长达617位的相同n值 e1, c1 2767, 2015249016... e2, c2 3659, 1129869732...共模攻击可行的核心原理在于当两个加密指数互质时存在整数s1和s2满足e1*s1 e2*s2 1这个等式让我们能够组合两个密文还原出原始明文。2. 必备数学工具准备解决这类题目需要两个关键Python库gmpy2处理大整数运算libnum实现数值与字节转换安装命令pip install gmpy2 libnum注意Windows用户可能需要先安装Microsoft Visual C 14.0以上版本3. 攻击脚本编写详解完整攻击脚本可分为三个逻辑部分3.1 参数输入阶段直接从题目复制粘贴参数值n 21058339337354287847534107544613605305015441090508924094198816691219103399526800112802416383088995253908857460266726925615826895303377801614829364034624475195859997943146305588315939130777450485196290766249612340054354622516207681542973756257677388091926549655162490873849955783768663029138647079874278240867932127196686258800146911620730706734103611833179733264096475286491988063990431085380499075005629807702406676707841324660971173253100956362528346684752959937473852630145893796056675793646430793578265418255919376323796044588559726703858429311784705245069845938316802681575653653770883615525735690306674635167111 e1, c1 2767, 20152490165522401747723193966902181151098731763998057421967155300933719378216342043730801302534978403741086887969040721959533190058342762057359432663717825826365444996915469039056428416166173920958243044831404924113442512617599426876141184212121677500371236937127571802891321706587610393639446868836987170301813018218408886968263882123084155607494076330256934285171370758586535415136162861138898728910585138378884530819857478609791126971308624318454905992919405355751492789110009313138417265126117273710813843923143381276204802515910527468883224274829962479636527422350190210717694762908096944600267033351813929448599 e2, c2 3659, 112986973231409888120577353242859084805047214541457965350144187389590352456006799472978745178189281815090815450270565237900225982339180112610119731963863956893715267747855823261219591861955860698515924676378193666240441336610163733608851589569552636456143458813504940123282752158213069552127882826178126865488831510668661490603634829587083647269829087983401822887021010233938397814273865372304594365126130473115858750680082108189969414601565893141350104383624475224282068849449526398266772478190668127068357731070595670828223123007210498270136604186102651892888402471865981457417240843516335084927077552068862028762273.2 核心攻击逻辑使用扩展欧几里得算法求解系数import gmpy2 # 计算满足e1*s1 e2*s2 1的系数 _, s1, s2 gmpy2.gcdext(e1, e2) # 注意s1或s2可能为负数需要处理模逆元 if s1 0: c1 gmpy2.invert(c1, n) s1 -s1 if s2 0: c2 gmpy2.invert(c2, n) s2 -s2 # 组合密文还原明文 m (pow(c1, s1, n) * pow(c2, s2, n)) % n关键点当s1或s2为负数时需要对对应密文取模逆元这是很多初学者容易忽略的步骤3.3 结果输出处理将大整数转换为可读字符串import libnum flag libnum.n2s(int(m)).decode() print(Flag:, flag)4. 完整脚本与执行结果将上述代码组合成完整解决方案import gmpy2 import libnum # 题目参数 n 21058339337354287847534107544613605305015441090508924094198816691219103399526800112802416383088995253908857460266726925615826895303377801614829364034624475195859997943146305588315939130777450485196290766249612340054354622516207681542973756257677388091926549655162490873849955783768663029138647079874278240867932127196686258800146911620730706734103611833179733264096475286491988063990431085380499075005629807702406676707841324660971173253100956362528346684752959937473852630145893796056675793646430793578265418255919376323796044588559726703858429311784705245069845938316802681575653653770883615525735690306674635167111 e1, c1 2767, 20152490165522401747723193966902181151098731763998057421967155300933719378216342043730801302534978403741086887969040721959533190058342762057359432663717825826365444996915469039056428416166173920958243044831404924113442512617599426876141184212121677500371236937127571802891321706587610393639446868836987170301813018218408886968263882123084155607494076330256934285171370758586535415136162861138898728910585138378884530819857478609791126971308624318454905992919405355751492789110009313138417265126117273710813843923143381276204802515910527468883224274829962479636527422350190210717694762908096944600267033351813929448599 e2, c2 3659, 11298697323140988812057735324285908480504721454145796535014418738959035245600679947297874517818928181509081545027056523790022598233918011261011973196386395689371526774785582326121959186195586069851592467637819366624044133661016373360885158956955263645614345881350494012328275215821306955212788282617812686548883151066866149060363482958708364726982908798340182288702101023393839781427386537230459436512613047311585875068008210818996941460156589314135010438362447522428206884944952639826677247819066812706835773107059567082822312300721049827013660418610265189288840247186598145741724084351633508492707755206886202876227 # 共模攻击 _, s1, s2 gmpy2.gcdext(e1, e2) if s1 0: c1 gmpy2.invert(c1, n) s1 -s1 if s2 0: c2 gmpy2.invert(c2, n) s2 -s2 m (pow(c1, s1, n) * pow(c2, s2, n)) % n flag libnum.n2s(int(m)).decode() print(成功获取flag:, flag)执行后将直接输出flag内容整个过程在普通电脑上耗时不足1秒。5. 实战技巧与扩展思考通过这道题可以总结出RSA共模攻击的快速识别特征题目特征提供两组或多组公钥(n,e)模数n相同而e不同每组公钥对应一个密文防御措施在实际系统中绝对避免重复使用模数n为不同用户生成独立的密钥对变种题型结合Base64编码的密文需要先解压或解码的附件隐藏的n值需要从其他信息推导建议将核心攻击代码保存为模板文件遇到类似题目只需替换参数即可快速解题。对于更复杂的RSA题型可以尝试以下扩展学习路径学习路线图: 基础RSA → 共模攻击 → 低加密指数攻击 → 中国剩余定理 → Wiener攻击 → Boneh-Durfee攻击掌握这些技巧后你会发现BUUCTF上80%的RSA题都能在5分钟内解决。记住CTF竞赛中效率是关键建立自己的密码学代码库能大幅提升解题速度。