ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

CTF学习/crypto/滑动攻击/相关密钥/不可能差分/AES缓存时序

CTF学习/crypto/滑动攻击/相关密钥/不可能差分/AES缓存时序

滑动攻击/相关密钥/不可能差分/AES缓存时序

考点概念

对称密码

滑动攻击(Slide Attack):

针对轮函数完全相同的迭代分组密码,寻找"滑动对" (P, F(P)),满足 E(F(P)) = F(E(P))(E = F^r)。一旦获得滑动对,可把密钥恢复简化为对单轮的分析,即使轮数极多也能攻击。

相关密钥攻击(Related-Key Attack):

攻击者能获取同一明文在多个相关密钥(如 K、K XOR delta)下的加密结果,利用密钥关系降低复杂度。DES 的补码性质是典型实例:E_K'(~P) = ~E_K(P)(K' = ~K),因此给定明密文对可将 DES 搜索空间减半。

AES 不可能差分攻击:

利用 AES 某些差分传播路径概率为 0(四轮不可能差分、反向扩展),对密钥逐字节排除候选,将 AES 全轮攻击降到约 2^126。属于理论性攻击,CTF 极少出现完整实现。

AES 缓存时序攻击:

AES 标准实现用 S-box 查表,表访问地址依赖密钥;攻击者测量解密过程的缓存访问时间/驱逐行为可推断 S-box 索引,逐步恢复密钥。需要本地目标机与精确计时

通常以"侧信道实验环境"形式出现。

识别特征

滑动攻击:题目轮函数周期固定、密钥重用,提示"slide attack";附脚本给出轮函数。

相关密钥:题目允许在密钥 XOR 固定常数下多次加密;DES 题出现补码提示。

不可能差分:理论题、CTF 论文题,通常附 AES 差分表与过滤过程。

缓存时序:题目提供远程服务 + 大量加密/解密样本与时间测量,要求恢复 S-box 索引或密钥。

综述性提示:题目描述出现"其它攻击面""不可""相关密钥"等。

靶场题目

Beatboxer(AES 变体线性分析) Triple DES(DES 补码属性)

Writeup

题目:Beatboxer(CryptoHack) 识别:

审读源码发现 S 盒不是标准 AES S 盒,而是 GF(2^8)(AES 同款多项式)上的仿射映射 s[x] = 0x2a 乘 x 再异或 0x2a(本地验证:对前 32 个 x 全部成立,且逆映射为 x = 0x2a 的逆元乘 y 异或 0x2a 后的值,0x2a 的逆元为 0x98);

密钥扩展也用该 S 盒。ShiftRows 排列、MixColumns GF 乘法、AddRoundKey 异或三者在 GF(2) 上全部线性,于是整条加密链对明文是 GF(2)-仿射:E(m) = L(m) XOR t,L 与密钥无关(纯结构决定),t 由密钥决定

解题:

本地实现

选任意 keyA 得到 E_A。三条关键恒等式本地验证成立:

E_A(m) XOR E_A(0) 与 E_B(m) XOR E_B(0) 在两个不同密钥下相同,说明 L 与密钥无关

E_R(m) XOR E_A(m) 与 m 无关,说明全部密钥相关项并入公共偏置

对任意明文 F 有 E_R(F) = E_A(F) XOR E_A(m0) XOR E_R(m0)。攻击时只允许一次加密,先用它拿 (m0, c0),再请求 encrypt_flag 得密文块 C_i,按恒等式三算出 E_A(F_i) = C_i XOR c0 XOR E_A(m0);

又 E_A(F_i) = L(F_i) XOR t_A,其中 t_A = E_A(0),所以 L(F_i) = E_A(F_i) XOR E_A(0)。最后用 128 个单位基向量预计算 L 的像并做 GF(2) 高斯消元回代求 L 逆,逐块还原 F_i 即 flag(含 PKCS 风格填充字节)。 脚本:

from os import urandom ​ src = open("13406_beatboxer.py", encoding="utf-8").read() src = src.split("class Challenge")[0] src = "\n".join(l for l in src.splitlines() if "utils" not in l and "listener" not in l) ns = {} exec(src, ns) AES_cls = ns["AES"] ​ def gmul(a, b): p = 0 for _ in range(8): if b & 1: p ^= a hi = a & 0x80 a = (a << 1) & 0xff if hi: a ^= 0x1b b >>= 1 return p ​ sbox = AES_cls.sbox print("s[x]==0x2a*x^0x2a(前32项):", all(sbox[x] == (gmul(0x2a, x) ^ 0x2a) for x in range(32))) ​ keyA, keyR = urandom(16), urandom(16) A, R = AES_cls(keyA), AES_cls(keyR) m0 = b"\x11" * 16 MOCK = b"crypto{aff1ne_sp0ng3}" + b"\x06" * 11 ​ c0 = R.encrypt(m0) cflag = b"".join(R.encrypt(MOCK[i:i + 16]) for i in range(0, len(MOCK), 16)) ​ tA = A.encrypt(b"\x00" * 16) ​ ​ def L(m): return bytes(a ^ b for a, b in zip(A.encrypt(m), tA)) ​ ​ basis = [] for j in range(128): v = bytearray(16) v[j // 8] |= 1 << (7 - j % 8) basis.append(L(bytes(v))) ​ ​ def gf2_solve(bas, y): M = [[int.from_bytes(bas[j], "big"), 1 << j] for j in range(128)] bycol, row = {}, 0 for col in range(127, -1, -1): bit = 1 << col piv = next((i for i in range(row, 128) if M[i][0] & bit), None) if piv is None: continue M[row], M[piv] = M[piv], M[row] for i in range(128): if i != row and M[i][0] & bit: M[i][0] ^= M[row][0] M[i][1] ^= M[row][1] bycol[col] = M[row] row += 1 assert row == 128, "L 奇异" Y, x = int.from_bytes(y, "big"), 0 for col in range(127, -1, -1): img, pre = bycol[col] if Y >> col & 1: x ^= pre Y ^= img assert Y == 0 out = bytearray(16) for j in range(128): if x >> j & 1: out[j // 8] |= 1 << (7 - j % 8) return bytes(out) ​ ​ recovered = b"" for i in range(0, len(cflag), 16): E_A_F = bytes(a ^ b ^ c for a, b, c in zip(cflag[i:i + 16], c0, A.encrypt(m0))) recovered += gf2_solve(basis, bytes(a ^ b for a, b in zip(E_A_F, tA))) print("差分还原:", recovered, recovered == MOCK)

工具:CryptoHack – Challenges

题目:Triple DES(CryptoHack) 识别:DES 补码性质 E_{~K}(~P) = ~E_K(P)

解题:利用补码性质对候选密钥一次计算同时校验 K 与 ~K 两组候选,密钥空间减半;

结合双重/三重 DES 的中间相遇结构做表交与消歧,最终用恢复的密钥链解密 flag 段

脚本:

from Crypto.Cipher import DES ​ K = b"abcdefgh" P = b"plaintex" comp = lambda b: bytes(x ^ 0xff for x in b) ​ c1 = DES.new(K, DES.MODE_ECB).encrypt(P) c2 = DES.new(comp(K), DES.MODE_ECB).encrypt(comp(P)) print("E(K,P) =", c1.hex()) print("E(~K,~P) =", c2.hex()) print("补码性质成立:", c2 == comp(c1))

工具:Triple DES

脚本

""" 其它对称攻击面综述 (滑动攻击/相关密钥/不可能差分/AES缓存时序) 对可自动化的三项做实证演示: DES 补码性质(相关密钥攻击的一环): ~E(K,P) = E(~K,~P) => 密钥空间减半搜索 AES-ECB 块重复检测: 识别 ECB 模式(密文长度 16 的整数倍 + 出现重复块) 滑动攻击最小演示: 轮函数相同的迭代结构存在"滑动对" (E(F(P)) = F(E(P))) ​ ​ ​ 实战替换 ​ DES 密钥/明文 <- 题目中候选密钥与已知明文(补码校验法) AES 密文 <- 题目附件密文(判断是否为 ECB) """ from Crypto.Cipher import AES, DES ​ KA = b"abcdefgh" PA = b"plaintex" ​ ​ def compe(key: bytes, blk: bytes): return bytes(b ^ 0xff for b in key), bytes(b ^ 0xff for b in blk) ​ ​ if __name__ == "__main__": c1 = DES.new(KA, DES.MODE_ECB).encrypt(PA) kcomp, pcomp = compe(KA, PA) c2 = DES.new(kcomp, DES.MODE_ECB).encrypt(pcomp) assert c2 == bytes(b ^ 0xff for b in c1), "DES 补码性质验证失败" print("A. DES 补码性质验证通过: E(~K,~P) = ~E(K,P) (密钥搜索可减半)") ​ plain = b"ABCDEFGHIJKLMNOP" * 4 ct = AES.new(b"k" * 16, AES.MODE_ECB).encrypt(plain) blocks = [ct[i:i + 16] for i in range(0, len(ct), 16)] dup = len(blocks) - len(set(blocks)) print(f"B. 密文长度 {len(ct)} 字节 = 16 的 {len(blocks)} 倍, 重复块数 {dup}") assert len(ct) % 16 == 0 and dup > 0, "未检测到 ECB 特征" print("B. 判定: 存在重复块, 高度疑似 ECB 模式") ​ def feistel_round(v, sk): L, R = (v >> 8) & 0xff, v & 0xff return ((R ^ ((L * sk + 3) & 0xff)) << 8) | L ​ def enc2(v, sk): return feistel_round(feistel_round(v, sk), sk) ​ sk = 7 p0 = 0x1234 p1 = feistel_round(p0, sk) assert enc2(p1, sk) == feistel_round(enc2(p0, sk), sk), "滑动对性质不成立" print("C. 滑动对验证通过: 迭代结构 E(P') = F(E(P)), 可借滑动对恢复密钥") ​ print("SUCCESS: 26 节三个可自动化演示全部通过")
返回列表