CTF实战:从BUUCTF的Samemod题,聊聊RSA共模攻击的“坑”与正确解码姿势
2026/6/11 23:38:03 网站建设 项目流程

CTF实战:从BUUCTF的Samemod题,聊聊RSA共模攻击的“坑”与正确解码姿势

在CTF竞赛中,RSA加密算法一直是密码学挑战的热门考点。而共模攻击作为RSA的经典攻击方式,看似简单却暗藏玄机。今天我们就以BUUCTF平台上的Samemod题目为例,深入探讨共模攻击在实际解题中容易忽略的关键细节,特别是数字到ASCII转换这一"最后一公里"问题。

1. 共模攻击原理与标准解法

RSA共模攻击(Collaborative RSA Attack)是指当两个密文使用相同的模数n但不同的指数e1和e2加密时,如果e1和e2互质,攻击者可以恢复出明文而无需分解n。其数学基础是扩展欧几里得算法:

s1*e1 + s2*e2 = gcd(e1,e2) = 1 m = (c1^s1 * c2^s2) mod n

标准解题脚本通常如下:

import gmpy2 import libnum n = 6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249 e1, e2 = 773, 839 c1 = 3453520592723443935451151545245025864232388871721682326408915024349804062041976702364728660682912396903968193981131553111537349 c2 = 5672818026816293344070119332536629619457163570036305296869053532293105379690793386019065754465292867769521736414170803238309535 s, s1, s2 = gmpy2.gcdext(e1, e2) m = (pow(c1, s1, n) * pow(c2, s2, n)) % n print(libnum.n2s(int(m)).decode())

2. Samemod题的特殊陷阱

在大多数CTF题目中,上述标准解法确实可以直接得到flag。但Samemod题目设计了一个精妙的陷阱:

  1. 解密后得到的数字明文为:1021089710312311910410111011910111610410511010710511610511511211111511510598108101125
  2. 直接hex解码会得到乱码,因为这不是标准的十六进制表示
  3. 实际需要将数字按ASCII码规则拆分:
    • 1开头的三位数代表一个ASCII字符(如102→'f')
    • 其他两位数代表一个ASCII字符(如10→'\n')

这种编码方式在CTF中并不常见,导致许多选手即使正确实施了共模攻击,最终却卡在了解码环节。

3. 正确的数字拆分解码方法

针对Samemod题的特殊编码方式,我们需要实现智能的数字拆分算法:

result = str(1021089710312311910410111011910111610410511010710511610511511211111511510598108101125) flag = "" i = 0 while i < len(result): if result[i] == '1': # 三位数ASCII码 c = chr(int(result[i:i+3])) i += 3 else: # 两位数ASCII码 c = chr(int(result[i:i+2])) i += 2 flag += c print(flag) # flag{whenwethinkitispossible}

关键点在于:

  • ASCII码中可打印字符的十进制范围是32-126
  • 三位数必然以1开头(100-126)
  • 两位数则可能是10-99

4. 实战中的调试技巧

当遇到类似问题时,可以采用以下排查流程:

  1. 验证共模攻击结果:确保解密出的数字明文确实正确
  2. 分析数字结构:观察数字串是否有特定模式(如固定位数交替)
  3. 尝试多种解码方式
    • 直接hex解码
    • 按固定位数拆分
    • 尝试不同进制转换
  4. 检查ASCII范围:确保转换后的数值在可打印字符范围内
  5. 逆向思考:考虑flag可能的格式(如以"flag{"开头)

一个实用的调试代码片段:

def debug_decoding(number): print("原始数字:", number) # 尝试hex解码 try: hex_str = hex(number)[2:] print("Hex解码尝试:", bytes.fromhex(hex_str).decode('ascii', errors='replace')) except: print("Hex解码失败") # 尝试两位数拆分 print("两位数拆分:", ''.join([chr(int(str(number)[i:i+2])) for i in range(0, len(str(number)), 2)])) # 尝试智能拆分 print("智能拆分:", smart_split_decode(number))

5. 密码学工具链的最佳实践

在CTF密码学挑战中,熟练使用以下工具可以事半功倍:

工具/库主要功能适用场景
gmpy2大数运算RSA相关计算
libnum数字转换数字与字节互转
Crypto.Util.number长整数转换跨语言数据兼容
sageMath高级数学运算复杂密码学攻击

对于RSA题目,建议建立如下解题流程:

  1. 收集所有给定参数(n, e, c等)
  2. 识别攻击向量(共模、低指数、因数分解等)
  3. 实施攻击获取数字明文
  4. 尝试多种解码方式:
    • 直接转字节
    • Hex解码
    • Base64解码
    • 自定义编码(如本题)
  5. 验证flag格式

6. 从这道题学到的经验

Samemod题目给我们上了宝贵的一课:密码学攻击的最后一公里——数据表示和编码同样重要。在实际CTF比赛中:

  • 不要假设所有题目都使用标准编码
  • 注意观察解密结果的数字模式
  • 准备多种解码工具函数备用
  • 养成验证flag格式的习惯

最后分享一个实用的Python解码工具集:

from Crypto.Util.number import long_to_bytes import binascii import base64 def try_all_decodings(number): # 尝试各种常见解码方式 decodings = { 'long_to_bytes': long_to_bytes(number), 'hex': binascii.unhexlify(hex(number)[2:]), 'base64': base64.b64decode(long_to_bytes(number)) } for name, value in decodings.items(): try: print(f"{name}: {value.decode()}") except: print(f"{name}: 解码失败")

记住,在CTF竞赛中,有时候最明显的解法未必是正确的解法。保持开放的思维,多角度尝试,才能在各种精心设计的密码学迷宫中找到正确的出口。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询