Layer cake
整体解法路线是:先通过 Base64 和 Caesar 拿到 Vigenere 密钥,再用 Vigenere 解出 repeating-XOR 密钥,接着从一段 XOR 线索里提取 RC4 口令,最后解出最终密文。
notice.txt 先做 Base64 解码,得到一段全大写的 Caesar 密文。向回偏移 7 位后,可以得到提示语,从中提取出 Vigenere 密钥 ORACLE。
接着用 ORACLE 去解 old_letter.txt,可以得到 repeating-XOR 的密钥 NIGHTFALL。
再用 NIGHTFALL 去异或 traffic.txt,虽然结果中夹杂了一些不可见字符,但可以明显看出最长的一段纯小写字符串是 retrowizard,这就是最后解密 vault.txt 所需的 RC4 密钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import base64 import re from itertools import cycle from Crypto.Cipher import ARC4
notice = "QU9MIENQTkxVTFlMIFJMRiBQWiBWWUhKU0w=" old_letter = "HYE TPTSRTKYK LFR MPC WJ NKRLHWANW" traffic = "282029293846332f584e222231542f324c3e2b3d3527232f3b2d3e2a" vault = "mun76xkQmk/MM4u0BRQQipplWO4PI7iJioGFFYRczP4PSuwZxcoRNw=="
def caesar_dec(s: str, shift: int) -> str: out = [] for ch in s: if "A" <= ch <= "Z": out.append(chr((ord(ch) - ord("A") - shift) % 26 + ord("A"))) else: out.append(ch) return "".join(out)
def vigenere_dec(ct: str, key: str) -> str: out = [] ki = 0 for ch in ct: if "A" <= ch <= "Z": k = ord(key[ki % len(key)]) - ord("A") out.append(chr((ord(ch) - ord("A") - k) % 26 + ord("A"))) ki += 1 else: out.append(ch) return "".join(out)
notice_stage = base64.b64decode(notice).decode() vigenere_key = caesar_dec(notice_stage, 7).split()[-1]
xor_key = vigenere_dec(old_letter, vigenere_key).split()[-1]
mid = bytes( c ^ k for c, k in zip(bytes.fromhex(traffic), cycle(xor_key.encode())) ) rc4_key = max(re.findall(rb"[a-z]{4,}", mid), key=len).decode()
flag = ARC4.new(rc4_key.encode()).decrypt(base64.b64decode(vault)).decode()
print(vigenere_key) print(xor_key) print(rc4_key) print(flag)
|
运行输出:
1 2 3 4
| ORACLE NIGHTFALL retrowizard flag{caesar_vigenere_xor_rc4_all_in_one}
|