Xoring_is_Caring - Writeup by AI
题目信息
| 项目 | 内容 |
|---|---|
| 题目来源 | Bugku CTF |
| 题目类型 | Crypto (密码学) |
| Flag 格式 | shellmates{} |
| 题目描述 | I've xored my flag using a random key, could you find my secret flag ? |
| 密文 | b'\x8a\x16\xc1:\xdd\x9f\x0b\x1e\xf1\x88\x9b^\xce%\x9c\x91X\x04\xa5\xc0\x8d\x16\xcd%\x91\x9b\x19J\xe0\x93\x855\xc6y\x8a\x98\'n\xe9\xd4\x97\x10\xf7~\xce\x8e,a\xb1\xd7\xc9J\xcb"\x80' |
| 密文长度 | 55 字节 |
考点分析
| 考点 | 分值权重 | 说明 |
|---|---|---|
| XOR 加密原理 | 25% | 理解异或运算的可逆性:A ^ B = C 等价于 C ^ B = A |
| 已知明文攻击 | 35% | 利用已知的 flag 格式推导密钥 |
| 滑动窗口技术 | 25% | 关键突破点:已知模式可能出现在密文的任意位置 |
| 密钥长度推断 | 15% | 通过暴力破解不同长度的密钥找到正确解 |
解题思路
关键突破点
初始尝试假设 shellmates{ 在密文开头(位置 0),但推导出的密钥解密后得到的不是完整可读文本。
关键洞察 :题目只说 flag 格式是 shellmates{},但没说一定在密文开头!因此需要使用滑动窗口技术在密文的任意位置搜索该模式。
解题步骤
步骤 1: 基础分析
python
enc = b'\x8a\x16\xc1:\xdd\x9f\x0b\x1e\xf1\x88\x9b^\xce%\x9c\x91X\x04\xa5\xc0\x8d\x16\xcd%\x91\x9b\x19J\xe0\x93\x855\xc6y\x8a\x98\'n\xe9\xd4\x97\x10\xf7~\xce\x8e,a\xb1\xd7\xc9J\xcb"\x80'
print(f"密文长度:{len(enc)}") # 输出:55 字节
步骤 2: 错误尝试 - 假设在开头
python
known = b"shellmates{"
key_at_start = bytes([enc[i] ^ known[i] for i in range(len(known))])
# 结果:f97ea456b1f26a6a94fbe0
# 用此密钥解密得到:shellmates{???... (后面不可读)
结论 :密钥不是简单的 11 字节循环,或者 shellmates{ 不在开头。
步骤 3: 滑动窗口 + 短密钥暴力破解
核心思路:
- 遍历密文中所有可能的起始位置(0 到 44)
- 对于每个位置,假设这里是
shellmates{ - 尝试不同的密钥长度(1-10 字节)
- 推导密钥并解密整个密文
- 验证解密结果是否全部为可打印 ASCII 字符且包含完整的
shellmates{...}
python
for start_pos in range(len(enc) - 11):
for key_len in range(1, 11):
# 推导密钥
test_key = bytes([
enc[start_pos + i] ^ known_pattern[i % len(known_pattern)]
for i in range(key_len)
])
# 解密
decrypted = xor_decrypt(enc, test_key)
# 验证
if (b'shellmates{' in decrypted and
b'}' in decrypted and
all(32 <= b < 127 for b in decrypted)):
print(f"找到解!位置={start_pos}, 密钥长度={key_len}")
步骤 4: 成功解密
发现:
- 起始位置: 20
- 密钥长度: 10
- 密钥 (hex) :
fe7ea849fdf6783e85e0 - 完整明文 :
this is the flag : shellmates{Kn0wn_Pl4in_73xT_4774ck}
完整代码
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
enc = b'\x8a\x16\xc1:\xdd\x9f\x0b\x1e\xf1\x88\x9b^\xce%\x9c\x91X\x04\xa5\xc0\x8d\x16\xcd%\x91\x9b\x19J\xe0\x93\x855\xc6y\x8a\x98\'n\xe9\xd4\x97\x10\xf7~\xce\x8e,a\xb1\xd7\xc9J\xcb"\x80'
def xor_decrypt(cipher, key):
return bytes([cipher[i] ^ key[i % len(key)] for i in range(len(cipher))])
def is_all_printable(data):
return all(32 <= b < 127 for b in data)
known_pattern = b"shellmates{"
# 滑动窗口 + 短密钥搜索
for key_len in range(1, 11):
for start_pos in range(len(enc) - key_len):
test_key = bytes([
enc[start_pos + i] ^ known_pattern[i % len(known_pattern)]
for i in range(key_len)
])
decrypted = xor_decrypt(enc, test_key)
if (b'shellmates{' in decrypted and
b'}' in decrypted and
is_all_printable(decrypted)):
flag_start = decrypted.find(b'shellmates{')
flag_end = decrypted.rfind(b'}')
flag = decrypted[flag_start:flag_end+1]
print(f"[✓] 找到解!")
print(f"密钥长度:{key_len}")
print(f"密钥 (hex): {test_key.hex()}")
print(f"完整明文:{decrypted.decode('ascii')}")
print(f"Flag: {flag.decode('ascii')}")
exit()
运行结果:
[✓] 找到解!
密钥长度:10
密钥 (hex): fe7ea849fdf6783e85e0
完整明文:this is the flag : shellmates{XXX}
Flag: shellmates{XXX}