silent_peeper Writeup by AI
题目描述
- 题目来源: 攻防世界 (AdWorld)
- 题目类型: Crypto (密码学)
- 考点: Diffie-Hellman 密钥交换、小指数攻击、BSGS 算法、AES 解密
考点分析
1. Diffie-Hellman 密钥交换
题目使用了经典的 Diffie-Hellman 密钥交换协议:
- 给定大素数
p和生成元g - 私钥
a和b是 40 位随机整数 - 公钥
A = g^a mod p,B = g^b mod p - 共享密钥
key = A^b mod p = B^a mod p
2. 小指数攻击
由于私钥 a 和 b 只有 40 位(约 2^40 ≈ 10^12 种可能),存在暴力破解的可能性。
3. AES-ECB 加密
使用推导出的共享密钥的前 16 字节作为 AES 密钥,采用 ECB 模式加密 flag。
解题思路
方法一:BSGS 算法(推荐)
Baby-Step Giant-Step 算法是求解离散对数问题的经典算法,时间复杂度为 O(√n)。
对于 40 位的指数:
- 搜索空间:2^40 ≈ 1.1×10^12
- BSGS 复杂度:2^20 ≈ 1.05×10^6 次运算
- 完全可以在合理时间内求解
方法二:直接枚举私钥 b
由于只需要恢复任意一个私钥即可计算共享密钥,也可以选择枚举较小的那个私钥。
详细步骤
Step 1: 提取参数
从 enc_.py 和 cipher 文件中提取:
python
p = 174807157365465092731323561678522236549173502913317875393564963123330281052524687450754910240009920154525635325209526987433833785499384204819179549544106498491589834195860008906875039418684191252537604123129659746721614402346449135195832955793815709136053198207712511838753919608894095907732099313139446299843
g = 41899070570517490692126143234857256603477072005476801644745865627893958675820606802876173648371028044404957307185876963051595214534530501331532626624926034521316281025445575243636197258111995884364277423716373007329751928366973332463469104730271236078593527144954324116802080620822212777139186990364810367977
A = 142989488568573584455487421652639325256968267580899511353325709765313839485530879575182195391847106611058986646758739505820350416810754259522949402428485456431884223161690132385605038767582431070875138678612435983425500273038807582069763455994486365993366499478412783220052753597397455113133312907456163112016
B = 16631700400183329608792112442038543911563829699195024819408410612490671355739728510944167852170853457830111233224257622677296345757516691802411264928943809622556723315310581871447325139349242754287009766402650270061476954875266747743058962546605854650101122523183742112737784691464177427011570888040416109544
ciphertext = ed5c68ebb65aa3a13afb259cf3984ce60bdc54b7ef918b850745df850cf4c450b02216c0c6e67ed501a17e516496cd6c
Step 2: BSGS 算法实现
python
def bsgs(g, h, p, n_bits):
m = int(ceil(sqrt(2**n_bits))) # m = 2^20
# Baby Step: 建表 g^j mod p
table = {}
val = 1
for j in range(m):
table[val] = j
val = (val * g) % p
# Giant Step: 查找 A * (g^(-m))^i mod p
inv_g_m = pow(g, -m, p)
gamma = h
for i in range(m):
if gamma in table:
j = table[gamma]
return i * m + j
gamma = (gamma * inv_g_m) % p
Step 3: 计算共享密钥
找到私钥 a = 822690494337 后:
python
key_int = pow(B, a, p)
key = long_to_bytes(key_int)[:16] # 取前 16 字节
Step 4: AES 解密
python
cipher = AES.new(key, AES.MODE_ECB)
plaintext_padded = cipher.decrypt(ciphertext)
pad_len = plaintext_padded[-1] # PKCS5/7 填充
plaintext = plaintext_padded[:-pad_len]
完整代码
见 solve.py
核心代码:
python
from Crypto.Util.number import *
from Crypto.Cipher import AES
import binascii
from math import ceil, sqrt
def bsgs(g, h, p, n_bits):
m = int(ceil(sqrt(2**n_bits)))
# Baby Step
table = {}
val = 1
for j in range(m):
table[val] = j
val = (val * g) % p
# Giant Step
inv_g_m = pow(g, -m, p)
gamma = h
for i in range(m):
if gamma in table:
return i * m + j
gamma = (gamma * inv_g_m) % p
return None
# 参数
A = 142989488568573584455487421652639325256968267580899511353325709765313839485530879575182195391847106611058986646758739505820350416810754259522949402428485456431884223161690132385605038767582431070875138678612435983425500273038807582069763455994486365993366499478412783220052753597397455113133312907456163112016
B = 16631700400183329608792112442038543911563829699195024819408410612490671355739728510944167852170853457830111233224257622677296345757516691802411264928943809622556723315310581871447325139349242754287009766402650270061476954875266747743058962546605854650101122523183742112737784691464177427011570888040416109544
ciphertext_hex = "ed5c68ebb65aa3a13afb259cf3984ce60bdc54b7ef918b850745df850cf4c450b02216c0c6e67ed501a17e516496cd6c"
p = 174807157365465092731323561678522236549173502913317875393564963123330281052524687450754910240009920154525635325209526987433833785499384204819179549544106498491589834195860008906875039418684191252537604123129659746721614402346449135195832955793815709136053198207712511838753919608894095907732099313139446299843
g = 41899070570517490692126143234857256603477072005476801644745865627893958675820606802876173648371028044404957307185876963051595214534530501331532626624926034521316281025445575243636197258111995884364277423716373007329751928366973332463469104730271236078593527144954324116802080620822212777139186990364810367977
# 求解私钥 a
a = bsgs(g, A, p, 40)
print(f"[+] 私钥 a = {a}")
# 计算共享密钥
key_int = pow(B, a, p)
key = long_to_bytes(key_int)[:16]
# AES 解密
ciphertext = binascii.unhexlify(ciphertext_hex)
cipher = AES.new(key, AES.MODE_ECB)
plaintext_padded = cipher.decrypt(ciphertext)
pad_len = plaintext_padded[-1]
plaintext = plaintext_padded[:-pad_len]
print(f"[+] Flag: {plaintext.decode()}")
总结
关键知识点
- Diffie-Hellman 密钥交换原理:理解 A = g^a mod p 和共享密钥的计算方式
- 小指数攻击:当私钥位数较小时,存在暴力破解可能
- BSGS 算法:求解离散对数问题的高效算法,时间复杂度 O(√n)
- AES-ECB 解密:使用推导出的密钥进行解密并去除 PKCS5/7 填充
注意事项
- BSGS 算法需要构建哈希表,空间复杂度为 O(√n)
- 对于 40 位指数,约需 10^6 次运算和相应的内存空间
- Python 的
pow(base, exp, mod)支持模逆运算:pow(g, -m, p) - AES 密钥取自共享密钥的前 16 字节(128 位)
扩展思考
- 如果私钥是 60 位,BSGS 需要 2^30 ≈ 10^9 次运算,仍然可行但需要更多时间
- 如果私钥是 80 位或更高,需要考虑更高级的攻击方法(如 Pollard's rho)
- 实际应用中应使用至少 256 位的私钥以保证安全性
用户原始提问
请阅读目录下的文件,解出这道CTF题目。